OpenGL纹理写入数组后显示异常:黑色方块问题排查
问题描述
我将数组填充为1后,预期方块会显示为白色,但运行代码后方块却是黑色。我原本打算使用glBufferSubData将数组上传至缓冲区,也尝试过使用持久化映射直接写入缓冲区内存。我已实现一个用stb image读取文件纹理的函数,为何用stb image初始化数组时图像能正常显示,但自定义数组却不行?
请问glTexImage2D期望何种图像格式?为何线性RGBA颜色值数组无法生效?是与glTexSubImage2D/glTexImage2D有关,还是纹理配置不正确?
相关代码
C++ 构造函数代码
voxelEngine::BiomeMap::BiomeMap(int textureUnit) { pixels = new unsigned char[apothem*apothem*4]; for(size_t i = 0; i < sizeof(pixels); i++) { pixels[i] = 1; } _textureUnit = textureUnit; glGenBuffers(1, &vao); glGenBuffers(1, &vbo); glGenBuffers(1, &ebo); glGenBuffers(1, &tbo); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); float vertex_data[] = { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0 }; glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); unsigned int indices[] = { 0, 1, 2, 0, 2, 3 }; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glActiveTexture(GL_TEXTURE0 + _textureUnit); glBindBuffer(GL_TEXTURE_2D, tbo); glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, apothem, apothem, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, apothem, apothem, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // set the texture wrapping/filtering options (on the currently bound texture object) 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_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA, apothem, apothem); glGenerateMipmap(GL_TEXTURE_2D); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(3*sizeof(float))); glEnableVertexAttribArray(1); }
片段着色器
#version 330 core out vec4 FragColor; in vec2 oTexCoord; uniform sampler2D my_sampler; void main() { FragColor = texture(my_sampler, oTexCoord); //FragColor = vec4(1, 1, 1, 1); }
顶点着色器
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 texCoord; out vec2 oTexCoord; uniform mat4 modelMat; uniform mat4 projMat; void main() { gl_Position = projMat * modelMat * vec4(aPos.x, aPos.y, aPos.z, 1.0); oTexCoord = texCoord; }
问题分析与解决
1. 数组填充范围与颜色值错误
sizeof(pixels)获取的是指针的内存大小(通常4/8字节),不是你分配的数组总长度,导致只有前几个元素被设为1,其余都是未初始化的垃圾值(大概率为0)。正确的循环范围应该是apothem * apothem * 4。unsigned char类型的颜色值范围是0-255,1对应浮点颜色值约为0.0039,接近黑色。要显示白色,每个通道值需要设为255。
修正代码:
size_t totalBytes = apothem * apothem * 4; for(size_t i = 0; i < totalBytes; i++) { pixels[i] = 255; }
2. 纹理对象创建与绑定错误
- 纹理对象需要用
glGenTextures生成,而非glGenBuffers(后者用于顶点/索引缓冲区)。 - 绑定纹理对象要用
glBindTexture,而非glBindBuffer(后者绑定缓冲区资源)。
修正代码:
// 替换原glGenBuffers(1, &tbo); glGenTextures(1, &tbo); // 替换原glBindBuffer(GL_TEXTURE_2D, tbo); glBindTexture(GL_TEXTURE_2D, tbo);
3. Mipmap层级参数错误
glTexImage2D的第二个参数是mipmap层级,你传了1,但基础纹理应该从层级0开始创建。直接创建层级1会导致基础纹理(层级0)未初始化,glGenerateMipmap无法生成完整的mipmap链,采样时会使用未定义数据。
修正代码:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, apothem, apothem, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // 若无需更新纹理,可删除glTexSubImage2D;若保留,层级参数同样设为0 // glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, apothem, apothem, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
4. 纹理内部格式优化建议
glTexImage2D的第三个参数(内部格式)推荐用GL_RGBA8替代GL_RGBA,明确指定8位每通道的存储格式,避免驱动自动转换可能带来的问题。
为何stb image能正常工作?
stb返回的数组是完全初始化的,且你在加载流程中正确使用了glGenTextures和glBindTexture,同时用了正确的数组长度,因此没有触发上述错误。
内容的提问来源于stack exchange,提问作者SGriffeth
相关产品推荐
相关产品推荐

