2015-08-08 157 views
0

我使用OpenGL 4.4和SDL2。我試圖用頂點(-1,-1,0),(1,-1,0),(0,1,0)渲染一個簡單的三角形。但是,當我認爲我正確地做了一切事情時,沒有任何東西可以被吸引使用OpenGL 4.4的SDL2:三角形不能正確渲染

我提取,從我的項目重組的相關代碼:

#include <cerrno> 
#include <cstring> 
#include <exception> 
#include <fstream> 
#include <iostream> 
#include <string> 
#include <GL/glew.h> 
#include <GL/glu.h> 
#include <SDL2/SDL.h> 
#include <SDL2/SDL_opengl.h> 

void init(); 
void cleanUp(); 
std::string loadShader(std::string filepath); 
void checkShaderSuccess(GLuint shader); 

SDL_Window* win; 
SDL_GLContext glContext; 
GLuint program, vertShader, fragShader, vao, vbo; 

class GenError: public std::exception { 
public: 
     GenError(): 
       exception(), msg("") {} 

     GenError(const std::string& m): 
       exception(), msg(m) {} 

     virtual ~GenError() throw() {} 

     virtual const char* what() const throw() { 
       return msg.c_str(); 
     } 
private: 
     std::string msg; 
}; 

int main() { 
     init(); 

     program = glCreateProgram(); 
     if (program == 0) { 
       throw GenError("Shader creation failed: " 
            "Could not find valid memory location in " 
            "constructor"); 
     } 

     vertShader = glCreateShader(GL_VERTEX_SHADER); 
     fragShader = glCreateShader(GL_FRAGMENT_SHADER); 
     if (vertShader == 0 || fragShader == 0) { 
       std::string m; 
       m += "Shader creation failed: " 
         "Could not find valid memory location when " 
         "adding shader: "; 
       m += (char *)gluErrorString(glGetError()); 
       throw GenError(m); 
     } 

     std::cout << "Creating vertex shader..." << std::endl; 
     std::string data = loadShader("./shaders/basicVertex.vs"); 
     const GLchar* data_c = data.c_str(); 
     glShaderSource(vertShader, 1, &data_c, NULL); 
     glCompileShader(vertShader); 
     checkShaderSuccess(vertShader); 
     glAttachShader(program, vertShader); 
     std::cout << "Vertex shader created" << std::endl; 

     std::cout << "Creating fragment shader..." << std::endl; 
     data = loadShader("./shaders/basicFragment.fs"); 
     data_c = data.c_str(); 
     glShaderSource(fragShader, 1, &data_c, NULL); 
     glCompileShader(fragShader); 
     checkShaderSuccess(fragShader); 
     glAttachShader(program, fragShader); 
     std::cout << "Fragment shader created" << std::endl; 

     glLinkProgram(program); 

     GLint success; 
     glGetProgramiv(program, GL_LINK_STATUS, &success); 
     if (success == GL_FALSE) { 
       GLint logLen = 0; 
       glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLen); 
       GLchar programLog[logLen]; 
       glGetProgramInfoLog(program, logLen, &logLen, programLog); 
       std::string m; 
       m += "Failed to link program: "; 
       m += (char *)gluErrorString(glGetError()); 
       m += ": "; 
       m += (char *)programLog; 
       throw GenError(m); 
     } 

     glValidateProgram(program); 

     glGetProgramiv(program, GL_VALIDATE_STATUS, &success); 
     if (success == GL_FALSE) { 
       GLint logLen = 0; 
       glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLen); 
       GLchar programLog[logLen]; 
       glGetProgramInfoLog(program, logLen, &logLen, programLog); 
       std::string m; 
       m += "Failed to validate program: "; 
       m += (char *)gluErrorString(glGetError()); 
       m += ": "; 
       m += (char *)programLog; 
       throw GenError(m); 
     } 

     glGenVertexArrays(1, &vao); 
     glBindVertexArray(vao); 
     glGenBuffers(1, &vbo); 

     const GLfloat verts[] = { 
       -1.0f, -1.0f, 0.0f, 
       1.0f, -1.0f, 0.0f, 
       0.0f, 1.0f, 0.0f 
     }; 
     glBindBuffer(GL_ARRAY_BUFFER, vbo); 
     glBufferData(GL_ARRAY_BUFFER, 
        sizeof(verts), 
        verts, 
        GL_STATIC_DRAW); 

     SDL_Event ev; 
     bool running = true; 
     while (true) { 
       while (SDL_PollEvent(&ev)) { 
         if (ev.type == SDL_WINDOWEVENT && 
          ev.window.event == SDL_WINDOWEVENT_CLOSE) { 
           std::cout << "Closing window..." << std::endl; 
           running = false; 
           break; 
         } 
       } 

       if (!running) break; 

       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
       glUseProgram(program); 

       glEnableVertexAttribArray(0); 
       glBindBuffer(GL_ARRAY_BUFFER, vbo); 
       glVertexAttribPointer(0, 
             3, 
             GL_FLOAT, 
             GL_FALSE, 
             3*sizeof(GLfloat), 
             (GLvoid*)0); 

       glDrawArrays(GL_TRIANGLES, 0, 3); 
       glDisableVertexAttribArray(0); 

       SDL_GL_SwapWindow(win); 
     } 
     std::cout << "Window closed" << std::endl; 

     glDeleteBuffers(1, &vbo); 
     glDeleteVertexArrays(1, &vao); 
     glDeleteProgram(program); 
     glDeleteShader(vertShader); 
     glDeleteShader(fragShader); 

     cleanUp(); 

     return 0; 
} 

void init() { 
     std::cout << "Initializing..." << std::endl; 

     if (SDL_Init(SDL_INIT_VIDEO) != 0) { 
       std::string m; 
       m.append("Error initializing SDL2: "); 
       m.append(SDL_GetError()); 
       throw GenError(m); 
     } 

     SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); 
     SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); 
     SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); 
     SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); 
     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); 
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4); 

     win = SDL_CreateWindow("Triangle Test", 
           SDL_WINDOWPOS_UNDEFINED, 
           SDL_WINDOWPOS_UNDEFINED, 
           800, 600, 
           SDL_WINDOW_OPENGL); 
     if (win == NULL) { 
       throw GenError(SDL_GetError()); 
     } 

     glContext = SDL_GL_CreateContext(win); 
     if (glContext == NULL) { 
       std::string m; 
       m.append("Error associating window with OpenGL: SDL Error: "); 
       m.append(SDL_GetError()); 
       throw GenError(m); 
     } 

     glewExperimental = GL_TRUE; 
     GLenum glewErr = glewInit(); 
     if (glewErr != GLEW_OK) { 
       std::string m; 
       m.append("Error initializing OpenGL GLEW extension: "); 
       m.append((const char*)glewGetErrorString(glewErr)); 
       throw GenError(m); 
     } else { 
       /* GLEW does not play nice with OpenGL 4.4. 
       * GLEW thinks OpenGL 4.4 is "pretentious" and 
       * "entitled". GLEW likes to throw an invalid 
       * enumerant error the next time glGetError is 
       * called after GLEW's initialization. 
       * glGetError must be envoked to discard this 
       * faulty error. GLEW makes my code look sloppy. 
       * We do not like GLEW. We tolerate GLEW. 
       */ 
       GLenum junk = glGetError(); 
     } 

     glClearColor(0.5f, 0.5f, 0.5f, 1.0f); 
     glFrontFace(GL_CW); 
     glCullFace(GL_BACK); 
     glEnable(GL_CULL_FACE); 
     glEnable(GL_DEPTH_TEST); 

     glEnable(GL_FRAMEBUFFER_SRGB); 

     if(SDL_GL_SetSwapInterval(1) < 0) { 
       std::cerr << "Warning: Unable to set VSync! " 
          << "SDL Error: " 
          << SDL_GetError() << std::endl; 
     } 

     GLenum error = glGetError(); 
     if (error != GL_NO_ERROR) { 
       std::string m; 
       m.append("Error initializing OpenGL: OpenGL Error: "); 
       m.append(reinterpret_cast<const char*>(gluErrorString(error))); 
       throw GenError(m); 
     } 

     std::cout << "Initialized" << std::endl; 
} 

void cleanUp() { 
     std::cout << "Cleaning up..." << std::endl; 
     SDL_GL_DeleteContext(glContext); 
     SDL_DestroyWindow(win); 
     SDL_Quit(); 
     std::cout << "Cleaned" << std::endl; 
} 

std::string loadShader(std::string filepath) { 
     std::ifstream shaderFile(filepath.c_str()); 
     if (!shaderFile.is_open()) { 
       std::cerr << "Could not load shader: " 
          << "Error opening " 
          << filepath 
          << ": " << std::strerror(errno) 
          << std::endl; 
       return std::string(""); 
     } 

     std::string content, line; 
     while (std::getline(shaderFile, line)) { 
       content += line + '\n'; 
     } 

     shaderFile.close(); 

     return content; 
} 

void checkShaderSuccess(GLuint shader) { 
     GLint success; 
     glGetShaderiv(shader, GL_COMPILE_STATUS, &success); 
     if (success == GL_FALSE) { 
       GLint logLen = 0; 
       glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLen); 
       GLchar shaderLog[logLen]; 
       glGetShaderInfoLog(shader, logLen, &logLen, shaderLog); 
       std::string m; 
       m += "Shader compilation failed: "; 
       m += (char *)gluErrorString(glGetError()); 
       m += ": "; 
       m += (char *)shaderLog; 
       glDeleteShader(shader); 
       throw GenError(m); 
     } 
} 

...沒有錯誤捕獲(更快略讀):

#include <cerrno> 
#include <cstring> 
#include <exception> 
#include <fstream> 
#include <iostream> 
#include <string> 
#include <GL/glew.h> 
#include <GL/glu.h> 
#include <SDL2/SDL.h> 
#include <SDL2/SDL_opengl.h> 

void init(); 
void cleanUp(); 
std::string loadShader(std::string filepath); 

SDL_Window* win; 
SDL_GLContext glContext; 
GLuint program, vertShader, fragShader, vao, vbo; 

int main() { 
     init(); 

     program = glCreateProgram(); 

     vertShader = glCreateShader(GL_VERTEX_SHADER); 
     fragShader = glCreateShader(GL_FRAGMENT_SHADER); 

     std::cout << "Creating vertex shader..." << std::endl; 
     std::string data = loadShader("./shaders/basicVertex.vs"); 
     const GLchar* data_c = data.c_str(); 
     glShaderSource(vertShader, 1, &data_c, NULL); 
     glCompileShader(vertShader); 
     glAttachShader(program, vertShader); 
     std::cout << "Vertex shader created" << std::endl; 

     std::cout << "Creating fragment shader..." << std::endl; 
     data = loadShader("./shaders/basicFragment.fs"); 
     data_c = data.c_str(); 
     glShaderSource(fragShader, 1, &data_c, NULL); 
     glCompileShader(fragShader); 
     glAttachShader(program, fragShader); 
     std::cout << "Fragment shader created" << std::endl; 

     glLinkProgram(program); 

     glGenVertexArrays(1, &vao); 
     glBindVertexArray(vao); 
     glGenBuffers(1, &vbo); 

     const GLfloat verts[] = { 
       -1.0f, -1.0f, 0.0f, 
       1.0f, -1.0f, 0.0f, 
       0.0f, 1.0f, 0.0f 
     }; 
     glBindBuffer(GL_ARRAY_BUFFER, vbo); 
     glBufferData(GL_ARRAY_BUFFER, 
        sizeof(verts), 
        verts, 
        GL_STATIC_DRAW); 

     SDL_Event ev; 
     bool running = true; 
     while (true) { 
       while (SDL_PollEvent(&ev)) { 
         if (ev.type == SDL_WINDOWEVENT && 
          ev.window.event == SDL_WINDOWEVENT_CLOSE) { 
           std::cout << "Closing window..." << std::endl; 
           running = false; 
           break; 
         } 
       } 

       if (!running) break; 

       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
       glUseProgram(program); 

       glEnableVertexAttribArray(0); 
       glBindBuffer(GL_ARRAY_BUFFER, vbo); 
       glVertexAttribPointer(0, 
             3, 
             GL_FLOAT, 
             GL_FALSE, 
             3*sizeof(GLfloat), 
             (GLvoid*)0); 

       glDrawArrays(GL_TRIANGLES, 0, 3); 
       glDisableVertexAttribArray(0); 

       SDL_GL_SwapWindow(win); 
     } 
     std::cout << "Window closed" << std::endl; 

     glDeleteBuffers(1, &vbo); 
     glDeleteVertexArrays(1, &vao); 
     glDeleteProgram(program); 
     glDeleteShader(vertShader); 
     glDeleteShader(fragShader); 

     cleanUp(); 

     return 0; 
} 

void init() { 
     std::cout << "Initializing..." << std::endl; 

     SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); 
     SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); 
     SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); 
     SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); 
     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); 
     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4); 

     win = SDL_CreateWindow("Triangle Test", 
           SDL_WINDOWPOS_UNDEFINED, 
           SDL_WINDOWPOS_UNDEFINED, 
           800, 600, 
           SDL_WINDOW_OPENGL); 

     glContext = SDL_GL_CreateContext(win); 

     glewExperimental = GL_TRUE; 
     GLenum glewErr = glewInit(); 

     glClearColor(0.5f, 0.5f, 0.5f, 1.0f); 
     glFrontFace(GL_CW); 
     glCullFace(GL_BACK); 
     glEnable(GL_CULL_FACE); 
     glEnable(GL_DEPTH_TEST); 

     glEnable(GL_FRAMEBUFFER_SRGB); 

     std::cout << "Initialized" << std::endl; 
} 

void cleanUp() { 
     std::cout << "Cleaning up..." << std::endl; 
     SDL_GL_DeleteContext(glContext); 
     SDL_DestroyWindow(win); 
     SDL_Quit(); 
     std::cout << "Cleaned" << std::endl; 
} 

std::string loadShader(std::string filepath) { 
     std::ifstream shaderFile(filepath.c_str()); 

     std::string content, line; 
     while (std::getline(shaderFile, line)) { 
       content += line + '\n'; 
     } 

     shaderFile.close(); 

     return content; 
} 

...我的頂點着色器(GLSL) :

#version 440 

layout (location = 0) in vec3 position; 

void main() { 
    gl_Position = vec4(0.5 * position, 1.0); 
} 

...和我的片段着色器:

#version 440 

out vec4 fragColor; 

void main() { 
    fragColor = vec4(0.0, 1.0, 1.0, 1.0); 
} 

現在奇怪的是,當我改變線路148在我的C++代碼(有錯誤捕獲)從這個...

...這(換句話說,改變步幅)。 ..

3*sizeof(GLdouble), 

...編譯和運行產生與所述頂點的三角形(-1,-1,0),(0,0,0),(0,1,0)。第二個頂點顯然變得模糊。我不是等腰三角形,而是斜角三角形。

我想1)弄清楚如何修復我的程序,使它顯示一個帶有指定頂點的三角形,2)理解我最初做錯了什麼,導致我修改上述碼。

我已經修補了近一個星期。 任何洞察力是讚賞。謝謝!

+0

你可以嘗試不啓用選擇嗎?刪除'glEnable(GL_CULL_FACE)'調用。據我所知,你指定順時針爲你三角形的方向,但繪製一個逆時針三角形。所以它會被淘汰。 –

+0

@ reto-koradi它的工作!註釋掉glEnable(GL_CULL_FACE)使三角形可見。在重新啓用面部相關多邊形剔除後,我切換了三角形的第二個和第三個頂點以吸引逆時針剔除偏差(或任何技術詞彙)。所以((-1,-1,0),(1,-1,0),(0,1,0))變成((-1,-1,0),(0,1,0), 1,-1,0))。這樣做導致我的三角形根據需要進行渲染。非常感謝!如果沒有人打我的話,我會盡力在後面添加官方的答案。 –

+0

糟糕。我的意思是**順時針**而不是逆時針。 –

回答

6

您的代碼在多邊形的繞線順序上存在問題。您指定順時針方向纏繞的前臉,使背面的撲殺:

glFrontFace(GL_CW); 
glCullFace(GL_BACK); 

但三角形具有逆時針環繞順序:

const GLfloat verts[] = { 
    -1.0f, -1.0f, 0.0f, 
    1.0f, -1.0f, 0.0f, 
    0.0f, 1.0f, 0.0f 
}; 

這意味着三角形將被淘汰撲殺。

在OpenGL中使用逆時針方向的卷繞大多是標準的,也是默認的。所以最好的辦法是,你根本刪除這行代碼:

glFrontFace(GL_CW); 

這將在GL_CCW留下的價值,你的幾何形狀相匹配。

禁用背面剔除始終是多邊形不顯示時應該做的第一件事情之一。錯誤的排列順序是不渲染事物的最常見原因之一,並且通過簡單地禁用剔除以及檢查是否會使幾何圖形顯示很容易進行分類。