使用 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 @。
这里要记住的最重要的一点是 binding
和 location
限定符是完全独立的:颜色附件 0 不对应于纹理图像单元 0。
【讨论】:
感谢您的帮助,这对我来说不是很清楚。我按照你说的编辑了我的片段着色器,只把输出纹理放在FBO的GL_COLOR_ATTACHMENT0
,我想读的纹理放在GL_TEXTURE0
,但我还是黑屏;也许是drawQuad()
的问题
我编辑了代码;我不确定如何设置顶点坐标的正确方法(我的顶点着色器关于vUV
的隐藏线,我知道我必须以与drawQuad()
中的vVertex
相同的方式设置此参数,但是我不知道纹理的哪些参数是正确的。
@MikeFadeCrew:嗯,根据最近的编辑,当您第二次调用drawQuad (...)
时,您没有绑定着色器。我也没有看到您在任何地方为纹理坐标设置顶点属性指针,因此纹理坐标都将具有未定义的值。
好吧,你是对的;我修改了它,现在我可以看到一些东西(一小块纹理),这是一个进步哈哈哈。我认为现在我唯一的问题是顶点位置。非常感谢!以上是关于使用 FBO 和着色器 OpenGL 渲染到纹理的主要内容,如果未能解决你的问题,请参考以下文章