具有多个绘制缓冲区的帧缓冲区

时间:2015-12-04 06:30:50

标签: opengl

我使用带有多个颜色附件(绘制缓冲区)的帧缓冲区,并使用多个着色器程序编写颜色。

每个着色器程序使用不同的渲染目标 例如SHADER1仅使用第一个绘制缓冲区,但SHADER2使用第二个和第三个绘制缓冲区。

但是,如果我只在片段着色器中指定渲染目标,如下所示:

// SHADER1.frag
layout(location = 0) out vec4 color;
void main() { color = vec4(1.0); }

这导致在每个绘制缓冲区中写入颜色,因此我必须清除第二个和第三个绘制缓冲区。

这是默认行为吗? 我应该为每个这样的着色器程序更新glDrawbuffers状态吗?

glUseProgram(SHADER1);
GLenum drawBuffers1[] = { GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE};
glDrawBuffers(3, drawBuffers1);

...

glUseProgram(SHADER2);
GLenum drawBuffers2[] = { GL_NONE, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
glDrawBuffers(3, drawBuffers2);

...

2 个答案:

答案 0 :(得分:3)

使用glDrawBuffers()设置的状态是帧缓冲对象(FBO)状态的一部分。因此,只要您为所有渲染使用相同的FBO,每次要绘制到不同的缓冲区时,都必须调用glDrawBuffers()

根据您的描述,我认为使用多个FBO会更容易。使用与您在问题中使用的伪表示法类似的伪表示法,您可以在设置期间进行一次这些调用:

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBO1);
glFramebufferTexture2D(..., GL_COLOR_ATTACHMENT0, ..., BUFFER1, ...);
GLenum drawBuffers1[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, drawBuffers1);

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBO2);
glFramebufferTexture2D(..., GL_COLOR_ATTACHMENT0, ..., BUFFER2, ...);
glFramebufferTexture2D(..., GL_COLOR_ATTACHMENT1, ..., BUFFER3, ...);
GLenum drawBuffers2[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
glDrawBuffers(2, drawBuffers2);

然后每次渲染:

glUseProgram(SHADER1);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBO1);
...

glUseProgram(SHADER2);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBO2);
...

要使这项工作,您的SHADER1将有一个输出(位置为0),SHADER2有两个输出(位置为0和1)。

如果由于某种原因你想坚持一个FBO,并使你的方法有效,你必须小心得到你想要的结果:

GLenum drawBuffers2[] = { GL_NONE, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
glDrawBuffers(3, drawBuffers2);

使用这些设置,并使用带有两个输出的着色器,您必须将输出的位置设置为1和2(在着色器中使用glBindFragDataLocation()location指令码)。

您也可以使用此代码:

GLenum drawBuffers2[] = {GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
glDrawBuffers(2, drawBuffers2);

片段着色器输出的位置为0和1。这样做的一个缺点是,如果您想将代码移植到OpenGL ES,它将无法工作。在ES中, i 缓冲区只能是GL_NONEGL_COLOR_ATTACHMENT i

答案 1 :(得分:1)

即使您的片段着色器未输出到特定输出位置,fragment在技术上仍然具有这些位置的输出。未写入的位置只有一个未定义的值。

因此,如果您的draw buffer setting说“将片段输出位置1并将其写入颜色附件1”,那么它就是这样做的。总是。直到你改变它。

您可以使用write masking关闭特定颜色缓冲区的写入。但实际上,适当地设置glDrawBuffers可能更好。