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

保存单颜色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黑块是上下文默认尺寸)。

解决步骤:

  1. 创建帧缓冲对象(FBO),把生成的纹理绑定为FBO的颜色附件。
  2. 切换到该FBO,设置对应尺寸的视口,清空颜色缓冲(或绘制全屏矩形),将纹理内容输出到FBO。
  3. 再调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 12:51:56