2015-08-08 3 views
0

Я использую OpenGL 4.4 с SDL2. Я пытаюсь сделать простой треугольник с вершинами (-1, -1, 0), (1, -1, 0), (0, 1, 0). Однако, когда я думаю, что делаю все правильно, ничего не рисуется.SDL2 с OpenGL 4.4: Треугольник не отображается должным образом

я извлек и реорганизован соответствующий код из моего проекта:

#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, который соответствует вашей геометрии.

Отключение отбраковки задней поверхности всегда является одной из первых вещей, которые нужно делать, когда полигоны не отображаются. Наличие неправильного порядка намотки является одной из наиболее распространенных причин, по которым не производится рендеринг, и очень легко сортировать, просто отключая отбраковку и проверяя, создает ли это геометрию.

 Смежные вопросы

  • Нет связанных вопросов^_^