Opengl 问题:很可能是简单的纹理问题
Opengl issue: Most likely simple texture issue
当 运行 此代码时,我得到一个黑色四边形。屏幕应该是全白的。着色器本身工作得很好,我可以更改 out vec4 中的值并且它可以工作。问题是将纹理加载到着色器或生成纹理。
GLFWwindow *window = nullptr;
GLuint shaderProgram = -1;
GLuint vbo = -1;
GLuint vao = -1;
GLuint tex0 = -1;
GLuint texture = -1;
unsigned char *pixels = nullptr;
int width = -1;
int height = -1;
pixels = new unsigned char[width * height * 3];
if (glfwInit() == GLFW_FALSE) {
std::cout << "GLFW failed initialization!" << std::endl;
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(width, height, "Engine From Scratch", NULL, NULL);
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cout << "GLEW failed initialization!" << std::endl;
return -1;
}
glViewport(0, 0, width, height);
if (window == nullptr) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
// Shader generation
const char *vertexShaderSource = "#version 330 core\nlayout (location = 0) in vec3 aPos;\nout vec2 texCoords;\nvoid main()\n{\ngl_Position = vec4(aPos.x * 0.5, aPos.y * 0.5, aPos.z * 0.5, 1.0);\ntexCoords = aPos.xy;\n}[=10=]";
const char *fragmentShaderSource = "#version 330 core\nout vec4 color;\nin vec2 texCoords;\nuniform sampler2D tex0;\nvoid main()\n{\ncolor = texture(tex0, texCoords);\n}[=10=]";
unsigned int vertexShader, fragmentShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glUseProgram(shaderProgram);
tex0 = glGetUniformLocation(shaderProgram, "tex0");
glUniform1i(tex0, 0);
// Loading Data =
float points[] = { -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, -1.0f, 0.0f };
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(float), points, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindVertexArray(vao);
for(int i = 0; i < width * height * 3; i ++) {
pixels[i] = 0xFF;
}
// generating texture
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1.0, 1.0, 1.0, 1.0);
glActiveTexture(GL_TEXTURE0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwPollEvents();
glfwSwapBuffers(window);
我认为存在问题的区域:
glUseProgram(shaderProgram);
tex0 = glGetUniformLocation(shaderProgram, "tex0");
glUniform1i(tex0, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]);
你必须通过glTexParameter
设置纹理缩小功能(GL_TEXTURE_MIN_FILTER
)(这可以在glTexImage2D
之前完成):
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
如果不生成mipmaps (by glGenerateMipmap
),那么设置GL_TEXTURE_MIN_FILTER
很重要。由于默认过滤器是 GL_NEAREST_MIPMAP_LINEAR
,如果不将缩小功能更改为 GL_NEAREST
或 GL_LINEAR
,纹理将是不完整的 mipmap。
纹理单元必须在绑定纹理之前设置,分别创建。无论如何,由于您使用纹理单元 0,所以这是不必要的,因为 GL_TEXTURE0
是默认值。参见 glActiveTexture
。
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
此外,纹理坐标必须在[0.0, 1.0]范围内。由于纹理坐标也使用顶点坐标(范围[-1.0, 1.0]),因此必须转换坐标:
texCoords = aPos.xy;
texCoords = aPos.xy + 0.5 * 0.5;
当 运行 此代码时,我得到一个黑色四边形。屏幕应该是全白的。着色器本身工作得很好,我可以更改 out vec4 中的值并且它可以工作。问题是将纹理加载到着色器或生成纹理。
GLFWwindow *window = nullptr;
GLuint shaderProgram = -1;
GLuint vbo = -1;
GLuint vao = -1;
GLuint tex0 = -1;
GLuint texture = -1;
unsigned char *pixels = nullptr;
int width = -1;
int height = -1;
pixels = new unsigned char[width * height * 3];
if (glfwInit() == GLFW_FALSE) {
std::cout << "GLFW failed initialization!" << std::endl;
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(width, height, "Engine From Scratch", NULL, NULL);
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cout << "GLEW failed initialization!" << std::endl;
return -1;
}
glViewport(0, 0, width, height);
if (window == nullptr) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
// Shader generation
const char *vertexShaderSource = "#version 330 core\nlayout (location = 0) in vec3 aPos;\nout vec2 texCoords;\nvoid main()\n{\ngl_Position = vec4(aPos.x * 0.5, aPos.y * 0.5, aPos.z * 0.5, 1.0);\ntexCoords = aPos.xy;\n}[=10=]";
const char *fragmentShaderSource = "#version 330 core\nout vec4 color;\nin vec2 texCoords;\nuniform sampler2D tex0;\nvoid main()\n{\ncolor = texture(tex0, texCoords);\n}[=10=]";
unsigned int vertexShader, fragmentShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glUseProgram(shaderProgram);
tex0 = glGetUniformLocation(shaderProgram, "tex0");
glUniform1i(tex0, 0);
// Loading Data =
float points[] = { -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, -1.0f, 0.0f };
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(float), points, GL_STATIC_DRAW);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindVertexArray(vao);
for(int i = 0; i < width * height * 3; i ++) {
pixels[i] = 0xFF;
}
// generating texture
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1.0, 1.0, 1.0, 1.0);
glActiveTexture(GL_TEXTURE0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwPollEvents();
glfwSwapBuffers(window);
我认为存在问题的区域:
glUseProgram(shaderProgram);
tex0 = glGetUniformLocation(shaderProgram, "tex0");
glUniform1i(tex0, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]);
你必须通过glTexParameter
设置纹理缩小功能(GL_TEXTURE_MIN_FILTER
)(这可以在glTexImage2D
之前完成):
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
如果不生成mipmaps (by glGenerateMipmap
),那么设置GL_TEXTURE_MIN_FILTER
很重要。由于默认过滤器是 GL_NEAREST_MIPMAP_LINEAR
,如果不将缩小功能更改为 GL_NEAREST
或 GL_LINEAR
,纹理将是不完整的 mipmap。
纹理单元必须在绑定纹理之前设置,分别创建。无论如何,由于您使用纹理单元 0,所以这是不必要的,因为 GL_TEXTURE0
是默认值。参见 glActiveTexture
。
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, &pixels[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
此外,纹理坐标必须在[0.0, 1.0]范围内。由于纹理坐标也使用顶点坐标(范围[-1.0, 1.0]),因此必须转换坐标:
texCoords = aPos.xy;
texCoords = aPos.xy + 0.5 * 0.5;