You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 05:15:19