【问题标题】:OpenGL shader problem (not displaying anything)OpenGL着色器问题(不显示任何东西)
【发布时间】:2019-05-17 18:20:56
【问题描述】:

我是 OpenGL 的新手,我正在关注 Shaders https://learnopengl.com/Getting-started/Textures 上的本教程。 我无法让我的工作,因为屏幕最终完全是黑色的。此代码使用 glew 和 glut 而不是教程中的 glfw。

发生了什么事?

  • 我有一个顶点列表,然后我将其存储在 VBO 中,它的属性由 VAO 绑定
  • 按 3 个顶点 + 3 个颜色 + 2 个特克斯坐标的顺序设置顶点属性
  • glEnable(GL_TEXTURE_2D);
  • 确保激活GL_TEXTURE0,以便下次调用
  • glBindTexture(GL_TEXTURE_2D, texture) 引用了这个纹理单元。
  • 我用stbi_load函数加载纹理
  • 使用glTexImage2D 加载纹理,并带有参数(widthheighttexture_data),这些参数预先作为指针传递给stbi_load,以便加载它们。
  • 创建顶点着色器,附加源(在 VertexShaders.h 中),编译着色器,打印着色器错误(不显示)
  • 创建片段着色器,附加源(在 FragmentShaders.h 中),编译着色器,打印着色器错误(不显示)
  • 创建一个着色器程序(ourShader),附加顶点着色器和片段着色器。链接“ourShader”程序,再次打印错误(没有出现)。

注意事项:

这是 myDisplay 回调:

void myDisplay(void)
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);


glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glEnable(GL_TEXTURE_2D);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); 
glTranslatef(0, 0, -10);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

glUseProgram(ourShader);
glBindVertexArray(VAO); 
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

glutSwapBuffers();
}

主要设置

int main(){
//glut initialization stuff...left this out



float vertices[] = {
        // positions          // colors           // texture coords
         0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // top right
         0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // bottom right
        -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // bottom left
        -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f    // top left 
    };
    float texCoords[] = {
    0.0f, 0.0f,  // lower-left corner  
    1.0f, 0.0f,  // lower-right corner
    0.5f, 1.0f   // top-center corner
    };

    unsigned int indices[] = {
       0, 1, 3, // first triangle
       1, 2, 3  // second triangle
    };

    //frameBuffer
    glGenBuffers(1, &FBO);
    glBindFramebuffer(GL_FRAMEBUFFER, FBO);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "ERROR: Framebuffer not bound" << std::endl;

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    //glDeleteFramebuffers(1, &fbo);


    //VAO
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // Vertex Attributes 
    glEnableVertexAttribArray(0); //pozicija
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(0));
    glEnableVertexAttribArray(1); //boja
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(2); //boja
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(6 * sizeof(GLfloat)));

    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, &texture);
    glActiveTexture(GL_TEXTURE0); 
    glBindTexture(GL_TEXTURE_2D, texture);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    std::string path = "C:\\Projects\\Myproj\\container.jpg";
    bool success = loadTexture(path,texture_data,&tex_width, &tex_height, &nchannels);
    if (success) 
    {
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else 
    {
        std::cout << "ERROR::STBI::FAILED TO LOAD TEXTURE" << std::endl;
    }

    stbi_image_free(texture_data);

    int success_f;
    char infoLog[512];

    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    getShaderStatus(vertexShader, &success_f, infoLog);

    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    getShaderStatus(fragmentShader, &success_f, infoLog);


    ourShader = glCreateProgram();
    glAttachShader(ourShader, vertexShader);
    glAttachShader(ourShader, fragmentShader);
    glLinkProgram(ourShader);
    getShaderStatus(ourShader, &success_f, infoLog);

    glUseProgram(ourShader);
    glUniform1i(glGetUniformLocation(ourShader, "ourTexture"), 0);

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);


    glutMainLoop();
}

顶点着色器

const char* vertexShaderSource =
"#version 330 core\n"
"layout(location = 0) in vec3 aPos;\n"
"layout(location = 1) in vec3 aColor;\n"
"layout(location = 2) in vec2 aTexCoord;\n"
"out vec3 ourColor;\n"
"out vec2 TexCoord;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos, 1.0);\n"
"ourColor = aColor;\n"
"TexCoord = aTexCoord;\n"
"}\n";

片段着色器

const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
"FragColor = texture(ourTexture, TexCoord);\n"
"}\n";

更新日志 - 已解决

  • 实现着色器时不需要 glEnable(GL_TEXTURE_2D)
  • 投影、视图和模型变换进入着色器,使用

    glm::projection glm::lookat

  • 在渲染之前启用属性(颜色、纹理)

  • 对 OpenGL API (>=3.2) 的 Freeglut 支持

glutInitContextVersion(3, 3); glutInitContextProfile(GLUT_CORE_PROFILE);

最终代码在这里:[https://pastebin.com/D8DgPqaT]

迷幻着色器:[https://pastebin.com/vtJ3Cr6i]

【问题讨论】:

  • 没有深入研究您的代码,但我搜索了您的函数 myDisplay ,它似乎已定义但无处使用。这可能已经是问题所在,否则您应该在使用它的地方显示代码。
  • glEnable(GL_TEXTURE_2D); 已被弃用,并且在使用着色器时毫无意义。同样使用固定函数矩阵堆栈(glMatrixModeglLoadIdentity,...)也没有用。您必须使用Uniform variablesmat4 类型)
  • @MichaelMahn 这是一个回调函数,当你调用 glutMainLoop() 时会调用它,但我在我遗漏的 glut 设置中添加了回调
  • @Rabbid76 你能解释一下为什么它没有意义吗?
  • 另外,我应该调用 glBindTexture(GL_TEXTURE_2D, texture);在实际使用 glTexImage2D 加载纹理之前?

标签: c++ opengl glsl shader


【解决方案1】:

glEnable(GL_TEXTURE_2D) 在使用着色器时是不必要的,因为使用或不使用纹理的天气是在(片段)着色器中实现的。
您的着色器代码定义是否应用纹理。 glEnable(GL_TEXTURE_2D) 用于已弃用的Fixed Function Pipeline,仅没有着色器。

同样使用固定函数矩阵栈(glMatrixModeglLoadIdentitygluPerspective,...)是没用的。您必须使用Uniform 变量(mat4 类型)。 此函数更改固定函数矩阵堆栈上的矩阵。此矩阵适用于由glVertexglVertexPointer 设置的固定函数顶点坐标,但前提是没有着色器代码。
如果有着色器,您必须自己进行矩阵转换。
在 GLSL 中存在像 gl_ModelViewMatrixgl_ProjectionMatrixgl_ModelViewProjectionMatrix 这样的内置制服,它们允许您访问固定函数矩阵堆栈上的矩阵。但是这种制服也已被弃用,并且在 GLSL #version 330 core 中不再可用。

使用 2 个制服 mat4 u_projmat4 u_view 编写一个着色器。通过着色器代码变换顶点坐标。

#version 330 core

layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCoord;

out vec3 ourColor;
out vec2 TexCoord;

uniform mat4 u_proj;
uniform mat4 u_view;

void main()
{
    gl_Position = u_proj * u_view * vec4(aPos, 1.0);
    ourColor = aColor;
    TexCoord = aTexCoord;
}

获取程序链接后的统一位置:

GLint proj_loc = glGetUniformLocation(ourShader, "u_proj");
GLint view_loc = glGetUniformLocation(ourShader, "u_view");

计算投影矩阵一个视图矩阵。我建议使用OpenGL Mathematics (GLM) 库,该库旨在进行 OpenGL 和 GLSL 相关计算并基于OpenGL Shading Language (GLSL)。另见glm::perspectiveglm::lookAt

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

>

glm::mat4 proj = glm::perspective(glm::radians(fov_degrees)), aspect, near, far);
glm::mat4 view = glm::lookAt(eye, target, up);

程序安装后设置制服(glUseProgram) by glUniformMatrix4fv:

glUniformMatrix4fv(proj_loc, 1, GL_FALSE, glm::value_ptr(proj));
glUniformMatrix4fv(view_loc, 1, GL_FALSE, glm::value_ptr(view));

审查代码 [https://pastebin.com/KWDxcEen] 和着色器 [https://pastebin.com/yq3rQEga]

如果着色器编译成功必须由glGetShaderiv检查

glGetShaderiv(shader_ID, GL_COMPILE_STATUS, &status);

比较检查程序是否链接成功,需要glGetProgramiv检查

glGetProgramiv(program_ID, GL_LINK_STATUS, success_f);

数组纹理坐标由大小为 2 (u, v) 的元组组成:

glVertexAttribPointer(2,
    2,                 // <---- 2 instead of 3 
    GL_FLOAT,
    GL_FALSE,
    8 * sizeof(GLfloat),
    (void*)(6 * sizeof(GLfloat))
); 

glDrawArrays 的第三个参数是顶点数,而不是图元数:

glDrawArrays(GL_TRIANGLES, 0, 6); // <---- 6 instead of 2

loadTexture 的第二个参数必须是输出参数。它必须是参考(unsigned char *&amp; buff):

bool loadTexture(
   const std::string &filename,
   unsigned char*& buff,           // < ---- unsigned char*&
   int* w, int* h, int* nc);

顶点属性启用或禁用的状态存储在Vertex Array Object 中。在显示功能中无需再次这样做:

void myDisplay(void) 
{

    // ....

    glBindVertexArray(VAO);

    // unecessary:
    //glEnableVertexAttribArray(0);
    //glEnableVertexAttribArray(1); 
    //glEnableVertexAttribArray(2); 

最后我建议在显示函数(myDisplay)中添加一个glutPostRedisplay()调用,以便不断更新场景。

【讨论】:

  • 非常感谢您的回答,我会尽力执行您的建议。现在我有另一个问题,如果我想应用一些转换 T 我应该在着色器 gl_Position = u_proj * u_view * T * vec4(aPos, 1.0) 中这样做吗?
  • 我已经尝试了你的建议;仍然以愚蠢的黑屏告终。我已经用尽了所有关于出了什么问题的想法......这是我的整个代码pastebin.com/D5z73pZU .Shaders: pastebin.com/yq3rQEga
  • 血腥的指针引用...非常感谢,它确实有效。
猜你喜欢
  • 1970-01-01
  • 2020-05-19
  • 2012-04-27
  • 2014-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多