保存单颜色OpenGL纹理时出现64x64黑块的问题排查
问题描述
我写了一段代码,想创建一个单颜色的GL纹理,把原始像素数据存到磁盘后用ffmpeg转成PNG格式。试了好几种生成和保存纹理的方式,结果总是得到1920x1080的图片,但角落有个64x64的黑块,我想要的是整张1920x1080的单颜色图。

转换命令:
ffmpeg -pix_fmt rgba -s 1920x1080 -i texture.raw -f image2 output.png
代码:
gpu::gles2::GLES2Interface* gl = GetContextProvider()->ContextGL(); GLuint texture; gl->GenTextures(1, &texture); gl->BindTexture(GL_TEXTURE_2D, texture); int width = 1920; int height = 1080; std::vector<unsigned char> data(width * height * 4, 0); for (size_t i = 2; i < data.size(); i += 4) { data[i] = 255; // 蓝色通道 } gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data()); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); std::vector<unsigned char> buffer(width * height * 4); gl->ReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data()); std::ofstream file("texture.raw", std::ios::binary); file.write(reinterpret_cast<char*>(buffer.data()), buffer.size()); file.close();
问题原因与解决方法
核心错误是:直接调用glReadPixels读不到纹理像素。glReadPixels读取的是当前绑定的帧缓冲(默认是窗口帧缓冲)的像素数据,而不是你创建的纹理内容。你现在的代码只是生成了纹理,但根本没把纹理渲染到帧缓冲里,默认帧缓冲里只有初始化的内容(64x64黑块是上下文默认尺寸)。
解决步骤:
- 创建帧缓冲对象(FBO),把生成的纹理绑定为FBO的颜色附件。
- 切换到该FBO,设置对应尺寸的视口,清空颜色缓冲(或绘制全屏矩形),将纹理内容输出到FBO。
- 再调用
glReadPixels读取FBO的像素数据,就能得到完整的纹理内容。
修正后的关键代码片段:
// 创建并绑定FBO GLuint fbo; gl->GenFramebuffers(1, &fbo); gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); // 将纹理绑定为FBO的颜色附件 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); // 检查FBO是否完整 if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { // 处理FBO创建失败的逻辑 } // 设置视口大小与纹理一致 gl->Viewport(0, 0, width, height); // 清空颜色缓冲(对应你设置的蓝色,alpha设为255可确保不透明) gl->ClearColor(0.0f, 0.0f, 1.0f, 1.0f); gl->Clear(GL_COLOR_BUFFER_BIT); // 读取FBO的像素数据 std::vector<unsigned char> buffer(width * height * 4); gl->ReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data()); // 解绑FBO并清理资源 gl->BindFramebuffer(GL_FRAMEBUFFER, 0); gl->DeleteFramebuffers(1, &fbo);
另外补充:你的原始数据里alpha通道都是0,转PNG后可能显示透明黑底。如果需要不透明,记得修改数据初始化逻辑:
for (size_t i = 0; i < data.size(); i += 4) { data[i] = 0; // 红色通道 data[i+1] = 0; // 绿色通道 data[i+2] = 255; // 蓝色通道 data[i+3] = 255; // Alpha通道(不透明) }
内容的提问来源于stack exchange,提问作者Duke Dougal
相关产品推荐
相关产品推荐

