使用 FBO 和着色器 OpenGL 渲染到纹理

Posted

技术标签:

【中文标题】使用 FBO 和着色器 OpenGL 渲染到纹理【英文标题】:Rendering to texture using FBO and shaders OpenGL 【发布时间】:2014-11-30 18:50:57 【问题描述】:

我想在我的 FBO 中加载两个纹理,一个纹理包含一个 HDR 图像,我的第一个目标是将图像从第一个纹理“复制”到第二个(它是空的),并调用 'DownSamplingTex'。

于是我创建了FBO,在COLOR_ATTACHMENT_0中加载我想写的纹理,并绑定它;然后初始化我的着色器程序并渲染一个四边形,我想在 GL_TEXTURE_0 中读取纹理。

然后我解绑FBO并绑定'DownSamplingTex',然后画一个四边形。

不知道流程是否正确,我的输出是黑屏。

这是渲染代码:

glBindFramebuffer(GL_FRAMEBUFFER, fboA);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
FBOtex->bind();  // Set read texture bound in GL_TEXTURE_0
glDrawBuffer(GL_COLOR_ATTACHMENT0);  // draw to write texture (DownSamplingTex)
fboShad->bind();    // use program of FBO shader
  fboShad->setUniformValue4f("MVP", glm::value_ptr(MVP));  // Shader attribute
  drawQuad();   // Draw
  fboShad->unbind();
 FBOtex->unbind();
// Main FB rendering
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
fboShad->bind();
  fboShad->setUniformValue4f("MVP", glm::value_ptr(MVP)); 
  DownSamplingTex->bind();
  drawQuad(); 
  DownSamplingTex->unbind();
fboShad->unbind();

顶点着色器:

#version 420

in vec4 vUV;
in vec4 vVertex;
smooth out vec2 vTexCoord;

uniform mat4 MVP;

void main()

   vTexCoord = vUV;
   gl_Position = MVP*vVertex;

片段着色器:

#version 420
smooth in vec2 vTexCoord;
layout(location = 0) out vec4 color;
layout(binding=0) uniform sampler2D texHDR;

void main(void)

   color = texture(texHDR,vTexCoord);

在 'drawQuad()' 中,我使用 glGetAttribLocation()glVertexAttribPointer() 设置 vVertex 值。

std::vector<GLfloat> quadVerts = 
    -1, -1, 0, 0, 1,
    -1, 1, 0, 0, 0,
    1, 1, 0, 1, 0,
    -1, -1, 0, 0, 1,
    1, 1, 0, 2, 0,
    1, -1, 0, 1, 1 ;

GLuint quadVbo;
glGenBuffers(1, &quadVbo);
glBindBuffer(GL_ARRAY_BUFFER, quadVbo);
glBufferData(GL_ARRAY_BUFFER, 6*3*4, &quadVerts[0], GL_STATIC_DRAW);
GLuint vVertex = fboShad->getLocation("vVertex");
GLuint vUV = fboShad->getLocation("vUV");
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), NULL);

glEnableVertexAttribArray(vVertex);
glVertexAttribPointer(vVertex, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, 0);
glEnableVertexAttribArray(vUV);
glVertexAttribPointer(vUV, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (void*)(3 * sizeof(GLfloat)));
glDrawArrays(GL_TRIANGLES, 0, 6);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(vVertex);
glDisableVertexAttribArray(vUV);

我不知道错误是在处理过程中,还是在片段着色器中使用属性不正确(我想'layout(binding=1)',如果你使用 FBO 绑定的着色器,采用 GL_COLOR_ATTACHMENT_1 纹理);或使用“vTexCoords”作为顶点的 .xy 值。

【问题讨论】:

如果片段着色器只写入一个输出,为什么会有两个颜色附件?由于没有对glBindFragDataLocation (...) 的调用,我将假设在这种情况下仅写入附件GL_COLOR_ATTACHMENT0事实上,您现在编写的片段着色器甚至不应该编译,因为 color 未定义 是的,对不起,评论那行是我的错,修复了那个错误。 我的想法是将两个纹理加载到片段着色器中,但只写入下采样tex,使用另一个纹理,其中包含图像并附加到GL_COLOR_ATTACHMENT_1 【参考方案1】:

我认为您将采样器绑定与片段数据输出位置混淆了。虽然这两个东西都可以使用layout (...) 限定符来分配,但它们是非常不同的。

layout (location = X) out vec3 color 将输出 color 分配给 GL_COLOR_ATTACHMENT0 + X

layout (binding = Y) sampler2D texHDR 告诉 GLSL 使用纹理图像单元 GL_TEXTURE0 + Y

您的片段着色器仅写入单个输出,因此在这种情况下没有实际理由使用多个颜色附件。您将图像附加到 FBO 以便从片段着色器写入它们,而不是从它们作为纹理读取。事实上,在将纹理附加到 FBO 进行写入的同时读取纹理是未定义的行为,而无需使用特殊扩展(例如 GL_NV_texture_barrier)。


在这种情况下你真正想做的是:

修改片段着色器:

#version 420
smooth in vec2 vTexCoord;
//out vec4 vFragColor;

layout(location=0) out     vec3      color;  // Fragment Data Output Location
layout(binding=0)  uniform sampler2D texHDR; // Texture Image Unit Binding

void main(void)

//vFragColor = texture(textureMap, vTexCoord);
//color = vec4(1.0,0.5,0.5,0.5);
   color = texture(texHDR,vTexCoord);

现在,您要读取的纹理应该绑定到 GL_TEXTURE0(这是默认设置,除非您手动调用 glActiveTexture (...) somehwere)并且您要输出到的纹理应该附加到您的帧缓冲区对象 @987654331 @。

这里要记住的最重要的一点是 bindinglocation 限定符是完全独立的:颜色附件 0 不对应于纹理图像单元 0。

【讨论】:

感谢您的帮助,这对我来说不是很清楚。我按照你说的编辑了我的片段着色器,只把输出纹理放在FBO的GL_COLOR_ATTACHMENT0,我想读的纹理放在GL_TEXTURE0,但我还是黑屏;也许是drawQuad()的问题 我编辑了代码;我不确定如何设置顶点坐标的正确方法(我的顶点着色器关于vUV 的隐藏线,我知道我必须以与drawQuad() 中的vVertex 相同的方式设置此参数,但是我不知道纹理的哪些参数是正确的。 @MikeFadeCrew:嗯,根据最近的编辑,当您第二次调用drawQuad (...) 时,您没有绑定着色器。我也没有看到您在任何地方为纹理坐标设置顶点属性指针,因此纹理坐标都将具有未定义的值。 好吧,你是对的;我修改了它,现在我可以看到一些东西(一小块纹理),这是一个进步哈哈哈。我认为现在我唯一的问题是顶点位置。非常感谢!

以上是关于使用 FBO 和着色器 OpenGL 渲染到纹理的主要内容,如果未能解决你的问题,请参考以下文章

GLSL:无法从 FBO 读取纹理并使用片段着色器渲染到另一个 FBO

OpenGL渲染到多个纹理,结果是白色的

OpenGL:渲染到 FBO 时是不是支持纹理组合器功能?

OpenGL 片段着色器未写入 fbo 颜色缓冲区

渲染到窗口帧缓冲区和 FBO 以保存全尺寸纹理图像

OpenGL:使用多个纹理渲染到 FBO