c++ - SDL2 与 OpenGL 4.4 : Triangle Not Rendering Properly

标签 c++ glsl sdl-2 opengl-4

我正在使用带有 SDL2 的 OpenGL 4.4。我正在尝试渲染一个带有顶点 (-1, -1, 0), (1, -1, 0), (0, 1, 0) 的简单三角形。然而,当我认为我做的一切都正确时,什么也没有画出来。

我从我的项目中提取并重组了相关代码:

#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);
}

现在很奇怪,当我从这里更改我的 C++ 代码中的第 148 行(带有错误捕获)时...

3*sizeof(GLfloat),

...对此(换句话说,改变步幅)...

3*sizeof(GLdouble),

...编译并运行生成一个顶点为 (-1, -1, 0), (0, 0, 0), (0, 1, 0) 的三角形。第二个顶点显然变得模糊了。我得到的不是等腰三角形,而是不等边三角形。

我想 1) 弄清楚如何修复我的程序,使其显示具有指定顶点的三角形,以及 2) 了解我最初做错了什么,导致我在修改上述代码行时出现如此奇怪的结果.

我已经研究了将近一个星期了。 任何的见解表示赞赏。谢谢!

最佳答案

您的代码在多边形的缠绕顺序方面存在问题。您为正面指定顺时针缠绕,并启用背面的剔除:

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,这与您的几何形状相匹配。

当多边形不显示时,禁用背面剔除始终是您应该做的第一件事。缠绕顺序错误是不渲染的最常见原因之一,通过简单地禁用剔除并检查是否使几何体显示出来,可以很容易地进行分类。

关于c++ - SDL2 与 OpenGL 4.4 : Triangle Not Rendering Properly,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31890151/

相关文章:

c++ - 将变量引用转换为值?

javascript - 如何在 2D 环境中 'unbunch' (余)正弦波?

c++ - 如何在ubuntu中安装SFML?

c++ - CGAL 不计算完整的 delaunay 三角剖分

c++ - Windows 10 上带有 mingw 的 CMake : Detecting CXX compiler ABI info - failed

graphics - 使用 2D 元球绘制具有恒定厚度的轮廓

opengl - 计算着色器不修改 3d 纹理

c - SDL 物理键码和 SDL 虚拟键码有什么区别?

c++ - C++ 软体引擎

c++ - 抛出异常返回内存异常错误