【问题标题】:OpenGL GLFW, triangle not renderingOpenGL GLFW,三角形不渲染
【发布时间】:2020-04-05 18:59:51
【问题描述】:

我一直在尝试在 macOS 上渲染一个三角形,但它不起作用。

这是我的代码:

#include <iostream>
#include <glm/glm.hpp>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

void OnError(int errorCode, const char* msg){
    throw std::runtime_error(msg);
}

int main(){
    glfwSetErrorCallback(OnError);
    if (!glfwInit()){
        throw std::runtime_error("glfwInit failed");
    }
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    GLFWwindow* window = glfwCreateWindow(512, 512, "Title", NULL, NULL);
    if (!window){
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK){
        glfwTerminate();
        return -1;
    }

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    float points[] = {
        0.0, 0.5, 0.0,
        -0.5, -0.5, 0.0,
        0.5, -0.5, 0.0
    };

    GLuint vbo = 0;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

    GLuint vao = 0;
    glGenBuffers(1, &vao);
    glBindVertexArray(vao);
    glDisableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);

    const char* vertex_shader =
    "#version 410\n"
    "in vec3 vp;"
    "void main(){"
    " gl_Position = vec4(vp, 1.0);"
    " };";

    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vs, 1, &vertex_shader, NULL);
    glCompileShader(vs);

    const char* fragment_shader =
    "#version 410\n"
    "out vec4 frag_colour;"
    "void main(){"
    " frag_colour = vec4(0.0, 1.0, 0.0, 1.0);"
    " };";

    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fs, 1, &fragment_shader, NULL);
    glCompileShader(fs);

    GLuint shader_program = glCreateProgram();
    glAttachShader(shader_program, fs);
    glAttachShader(shader_program, vs);
    glLinkProgram(shader_program);

    while (!glfwWindowShouldClose(window)){
        //glViewport(0, 0, 512, 512);
        //glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glUseProgram(shader_program);
        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glBindVertexArray(0);
        glfwSwapBuffers(window);

        glfwPollEvents();
        glClear(GL_COLOR_BUFFER_BIT);
        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glDisableVertexAttribArray(0);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

【问题讨论】:

  • 你为什么要glDisableVertexAttribArray(0)。您必须启用它。

标签: c++ opengl glsl glfw vao


【解决方案1】:

顶点数组对象名称必须由glGenVertexArrays而不是glGenBuffers生成:

glGenBuffers(1, &amp;vao);

glGenVertexArrays(1, &vao);

State 顶点数组规范和启用状态存储在顶点数组对象中。创建对象名称并绑定(创建)顶点数组对象。然后可以指定并启用顶点数组:

GLuint vao = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);

在绘制几何之前绑定顶点数组对象就足够了:

while (!glfwWindowShouldClose(window))
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(shader_program);

    glBindVertexArray(vao);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glBindVertexArray(0);

    glfwSwapBuffers(window);
    glfwPollEvents();
}

请注意,在您的应用程序中创建了一个核心配置文件OpenGL Context (GLFW_OPENGL_CORE_PROFILE)。这会导致默认的顶点数组对象 (0) 无效。
glVertexAttribPointerglEnableVertexAttribArray 这样的指令会改变顶点数组对象的状态。如果调用此函数时未绑定命名顶点数组对象,则会导致 INVALID_OPERATION 错误。


此外,您还创建了 3.2 核心配置文件 OpneGL 上下文。对应 OpenGL 3.2 的 GLSL 版本是 1.50。
更改顶点和片段着色器中的版本规范:

#version 410

#version 150

最后的三角形:


我建议检查着色器编译是否成功以及程序对象是否链接成功。

可以通过glGetShaderiv和参数GL_COMPILE_STATUS检查着色器是否编译成功。例如:

#include <iostream>
#include <vector>
bool CompileStatus( GLuint shader )
{
    GLint status = GL_TRUE;
    glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
    if (status == GL_FALSE)
    {
        GLint logLen;
        glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &logLen );
        std::vector< char >log( logLen );
        GLsizei written;
        glGetShaderInfoLog( shader, logLen, &written, log.data() );
        std::cout << "compile error:" << std::endl << log.data() << std::endl;
    }
    return status != GL_FALSE;
}

可以通过glGetProgramiv和参数GL_LINK_STATUS来检查程序链接是否成功。例如:

bool LinkStatus( GLuint program )
{
    GLint status = GL_TRUE;
    glGetProgramiv( program, GL_LINK_STATUS, &status );
    if (status == GL_FALSE)
    {
        GLint logLen;
        glGetProgramiv( program, GL_INFO_LOG_LENGTH, &logLen );
        std::vector< char >log( logLen );
        GLsizei written;
        glGetProgramInfoLog( program, logLen, &written, log.data() );
        std::cout << "link error:" << std::endl << log.data() << std::endl;
    }
    return status != GL_FALSE;
}

编译着色器后调用函数,分别链接程序:

GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vertex_shader, NULL);
glCompileShader(vs);
CompileStatus(vs);

GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fragment_shader, NULL);
glCompileShader(fs);
CompileStatus(fs);

GLuint shader_program = glCreateProgram();
glAttachShader(shader_program, fs);
glAttachShader(shader_program, vs);
glLinkProgram(shader_program);
LinkStatus(shader_program);

【讨论】:

  • 谢谢,这可能是问题的一部分。我仍然无法让它努力工作。
  • 好吧,我可能误解了你的意思。这是我当前的代码:pastebin.com/SSPJgVSe
  • 哦,对不起,它仍然无法正常工作。我究竟做错了什么? pastebin.com/7TULZLfr
  • @Theelf111 你的硬件无法处理#version 410。更改为#version 150。查看答案。
  • 我修好了,问题是“;”在着色器代码中的“}”之后。
猜你喜欢
  • 2021-04-08
  • 1970-01-01
  • 2017-02-04
  • 1970-01-01
  • 1970-01-01
  • 2021-12-29
  • 1970-01-01
  • 2016-09-12
相关资源
最近更新 更多