我正在尝试渲染带纹理的三角形。我正在使用机顶盒图像加载png。对于我尝试过的许多不同图像,三角形显示为单色。颜色似乎是图像中显示的全部颜色的平均值。
我研究了许多类似问题的解决方案,并确保(或我认为)我没有陷入常见的“陷阱”:被称为glEnable(GL_TEXTURE_2D)
。我对glVertexAttribPoitners()
的呼叫设置正确。我试图告诉OpenGl我不想对glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
使用mipmapping,并且已经通过glEnableVertexAttribArray()
启用了相关的顶点数组。我的着色器编译没有错误。
#include <practice/practice.h>
#include <test_dep/stb_image.h>
void
initRenderer_practice()
{
const char* vertex_shader = GLSL(450 core,
layout (location = 0) in vec2 vCoords;
layout (location = 1) in vec2 tCoords;
out vec2 ftCoords;
void main()
{
gl_Position = vec4(vCoords.x, vCoords.y, 0.0, 1.0);
ftCoords = tCoords;
}
);
const char* fragment_shader = GLSL(450 core,
uniform sampler2D texture_data;
in vec2 ftCoords;
out vec4 fragColor;
void main()
{
fragColor = texture(texture_data, ftCoords.st);
}
);
GLfloat vCoordsLocal[] =
{
//
// POSITION COORDS
//
// bottom left
-0.5, -0.5,
// bottom right
0.5, -0.5,
// top center
0.0, 0.5,
//
// TEXTURE COORDS
//
// left bottom
0.0, 0.0,
// right bottom
1.0, 0.0,
// center top
0.5, 1.0,
};
if (!practice_target)
{
practice_target = (uGLRenderTarget*)malloc(sizeof(uGLRenderTarget));
practice_target->shader_program = 0;
practice_target->vertex_array_object = (GLuint) -1;
practice_target->vertex_buffer_object = (GLuint) -1;
}
practice_target->shader_program = uGLCreateShaderProgram_vf(&vertex_shader,
&fragment_shader);
assert(practice_target->shader_program);
glUseProgram(practice_target->shader_program);
glError;
glGenVertexArrays(1, &practice_target->vertex_array_object);
glBindVertexArray(practice_target->vertex_array_object);
glError;
glGenBuffers(1, &practice_target->vertex_buffer_object);
glBindBuffer(GL_ARRAY_BUFFER, practice_target->vertex_buffer_object);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vCoordsLocal),
vCoordsLocal,
GL_STATIC_DRAW);
glError;
glGenTextures(1, &practice_target->texture_id);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, practice_target->texture_id);
practice_target->shdr_texture_2d_location = glGetUniformLocation(practice_target->shader_program, "texture_data");
glUniform1i(practice_target->shdr_texture_2d_location, 0);
assert(practice_target->shdr_texture_2d_location != -1);
glError;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glError;
stbi_set_flip_vertically_on_load(true);
u8* texture_data = NULL;
GLint width, height, channels = 0;
texture_data = stbi_load("./assets/index.png", &width, &height, &channels, 0);
if (texture_data)
{
/*
void glTexImage2D(GLenum target,
GLint level,
GLint internalFormat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
const GLvoid * data);
*/
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGB,
width,
height,
0,
GL_RGB,
GL_UNSIGNED_BYTE,
texture_data);
glGenerateMipmap(GL_TEXTURE_2D);
glError;
printf("\n\n numchannels: %d\n\n", channels);
}
else
{
puts("[ debug ] Load texture failed\n");
assert(0);
}
stbi_image_free(texture_data);
/*
void glVertexAttribPointer(GLuint index,
GLint size,
GLenum type,
GLboolean normalized,
GLsizei stride,
const GLvoid * pointer);
*/
// Vertex coordinate attribute
glVertexAttribPointer(0,
2,
GL_FLOAT,
GL_FALSE,
0,
(void*) 0);
glEnableVertexAttribArray(0);
// Texture coordinate attribute
glVertexAttribPointer(1,
2,
GL_FLOAT,
GL_FALSE,
0,
(void*) 6);
glEnableVertexAttribArray(1);
glError;
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
glError;
}
void
render_practice()
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(practice_target->shader_program);
glEnable(GL_TEXTURE_2D);
glBindVertexArray(practice_target->vertex_array_object);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, practice_target->texture_id);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
glError;
}
预期结果是将纹理映射到三角形上,而不是单色上。
答案 0 :(得分:2)
纹理坐标的顶点属性规范未对齐。
属性的内存布局为
x0 y0, x1, y1, x2, y2, u0 v0, u1, v1, u2, v2
因此,第一个纹理坐标是缓冲区中的第6个元素。
但是,glVertexAttribPointer
的最后一个参数是缓冲区对象数据存储区中的 byte 偏移量。
这意味着偏移量必须为6*sizeof(GLfloat)
而不是6
glVertexAttribPointer(1,
2,
GL_FLOAT,
GL_FALSE,
0,
(void*)(6*sizeof(GLfloat)); // <-----
我建议将顶点属性的排列更改为可扩展的布局:
x0 y0 u0 v0 x1 y1 u1 v1 x2 y2 u2 v2 ...
并使用相应的顶点属性规范:
GLsizei stride = (GLsizei)(4*sizeof(GLfloat)); // 4 because of (x, y, u ,v)
void* vertOffset = (void*)(0); // 0 because the vertex coords are 1st
void* texOffset = (void*)(2*sizeof(GLfloat)); // 2 because u, v are after x, y
// Vertex coordinate attribute
glVertexAttribPointer(0,
2,
GL_FLOAT,
GL_FALSE,
stride,
vertOffset);
glEnableVertexAttribArray(0);
// Texture coordinate attribute
glVertexAttribPointer(1,
2,
GL_FLOAT,
GL_FALSE,
stride,
texOffset;
glEnableVertexAttribArray(1);