OpenGL 纹理渲染与原始不匹配

问题描述

我正在尝试使用 OpenGL 渲染纹理。我用来测试的纹理是一堆白底黑矩形,如下:

Some black rectangles on a white background

然而,在渲染时,纹理似乎被复制并多次叠加在自身之上:

A rendered frame with a distorted version of the texture

我使用以下方法设置场景:

std::string vertexSource = ShaderLoader::load("vertexSource.vert");
const char* vsource = vertexSource.c_str();
std::string fragmentSource = ShaderLoader::load("fragmentSource.frag");
const char* fsource = fragmentSource.c_str();

int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader,1,&vsource,NULL);
glCompileShader(vertexShader);
int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader,&fsource,NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram,vertexShader);
glAttachShader(shaderProgram,fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);

float vertices[] = {
            0.5f,0.5f,0.0f,-0.5f,1.0f,};
unsigned int indices[] = {
            0,3,2,3
};

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);
glVertexAttribPointer(0,GL_FLOAT,GL_FALSE,3 * sizeof(float),(void*)0);
glEnabLevertexAttribArray(0);
glVertexAttribPointer(1,2* sizeof(float),(void*)(sizeof(float)*12));
glEnabLevertexAttribArray(1);

glBindBuffer(GL_ARRAY_BUFFER,0);

glBindVertexArray(0);

unsigned char* data = stbi_load("image.png",&width,&height,&nrOfChannels,0);
glGenTextures(1,&textureId);
glBindTexture(GL_TEXTURE_2D,textureId);
glTexImage2D(GL_TEXTURE_2D,GL_RGB,width,height,GL_UNSIGNED_BYTE,data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free((void *) data);

我的渲染代码是:

glClearColor(0.2f,0.3f,1.0f);
glClear(GL_COLOR_BUFFER_BIT);
gluseProgram(shaderProgram);
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D,textureId);
glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0);

我的顶点着色器是:

#version 330 core
layout (location = 0) in vec3 inVertex;
layout (location = 1) in vec2 inTexture;

out vec2 TextureCoordinate;

void main()
{
    gl_Position = vec4( inVertex,1 );
    TextureCoordinate = inTexture;
}

我的片段着色器是:

#version 330 core
out vec4 FragColor;

in vec2 TextureCoordinate;

uniform sampler2D Texture;

void main() {
    FragColor = texture(Texture,TextureCoordinate);
}

解决方法

当一个有 3 个通道的图像 (./target) 加载到纹理对象时,GL_RGB 需要设置为 1。默认情况下 GL_UNPACK_ALIGNMENT 为 4,因此每行假设图像对齐到 4 个字节。缓冲区中的像素大小为 3 个字节,并且紧密排列,这会导致未对齐。

GL_UNPACK_ALIGNMENT

由于图片格式为 PNG,图片很可能有 4 个通道 (glPixelStorei(GL_UNPACK_ALIGNMENT,1); glTexImage2D(GL_TEXTURE_2D,GL_RGB,width,height,GL_UNSIGNED_BYTE,data); glPixelStorei(GL_UNPACK_ALIGNMENT,4); // default )。在指定纹理图像之前评估 GL_RGBA

nrOfChannels

也可以强制 unsigned char* data = stbi_load("image.png",&width,&height,&nrOfChannels,0); // [...] unsigned int format = nrOfChannels == 4 ? GL_RGBA : GL_RGB; glTexImage2D(GL_TEXTURE_2D,format,data); 生成具有 4 个通道的图像,通过明确地将 4 传递给最后一个参数:

stbi_load