【发布时间】: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加载纹理,并带有参数(width、height、texture_data),这些参数预先作为指针传递给stbi_load,以便加载它们。 - 创建顶点着色器,附加源(在 VertexShaders.h 中),编译着色器,打印着色器错误(不显示)
- 创建片段着色器,附加源(在 FragmentShaders.h 中),编译着色器,打印着色器错误(不显示)
- 创建一个着色器程序(
ourShader),附加顶点着色器和片段着色器。链接“ourShader”程序,再次打印错误(没有出现)。
注意事项:
- 投影是用
gluPerspective进行的,剪裁平面0.1 附近和1000 远(因为它向下看-z 不应该剪裁对象,我也像glTranslatef(0, 0, -10)那样平移对象) - 纹理正在加载(文件存在,当我加载它时它会生成字节数据,至于纹理图像它是这个(512x512)https://github.com/JoeyDeVries/LearnOpenGL/blob/master/resources/textures/container.jpg
这是 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);已被弃用,并且在使用着色器时毫无意义。同样使用固定函数矩阵堆栈(glMatrixMode,glLoadIdentity,...)也没有用。您必须使用Uniform variables(mat4类型) -
@MichaelMahn 这是一个回调函数,当你调用 glutMainLoop() 时会调用它,但我在我遗漏的 glut 设置中添加了回调
-
@Rabbid76 你能解释一下为什么它没有意义吗?
-
另外,我应该调用 glBindTexture(GL_TEXTURE_2D, texture);在实际使用 glTexImage2D 加载纹理之前?