C++ 彩色附件';s-如何将多个纹理渲染为帧缓冲区对象内的颜色附件?
我试图将多个纹理渲染为C++ 彩色附件';s-如何将多个纹理渲染为帧缓冲区对象内的颜色附件?,c++,opengl,framebuffer,fbo,C++,Opengl,Framebuffer,Fbo,我试图将多个纹理渲染为COLOR\u附件s,但没有成功。我从显示它们中得到的只是一个黑色屏幕(带有红色的清晰填充),这意味着我的纹理已被读取,但“为空” 我的伪代码是:分别使用纹理索引1、2和3以及颜色附件0、1和2将3个纹理附加到FBO。作为一个测试用例,我尝试将我的场景渲染到3个颜色附件,以便它们应该包含相同的精确数据。然后在着色器过程2(使用2Dsampler)读取其中任何一个纹理,并将其显示在四元网格上 我对这两个额外颜色附件的最初意图是使用GPU乒乓技术将它们用作随机数据缓冲区。到目前
COLOR\u附件
s,但没有成功。我从显示它们中得到的只是一个黑色屏幕(带有红色的清晰填充),这意味着我的纹理已被读取,但“为空”
我的伪代码是:分别使用纹理索引1、2和3以及颜色附件0、1和2将3个纹理附加到FBO。作为一个测试用例,我尝试将我的场景渲染到3个颜色附件,以便它们应该包含相同的精确数据。然后在着色器过程2(使用2Dsampler)读取其中任何一个纹理,并将其显示在四元网格上
我对这两个额外颜色附件的最初意图是使用GPU乒乓技术将它们用作随机数据缓冲区。到目前为止,我只是使用它们作为纹理克隆进行测试
当尝试从GL\u TEXTURE1
(COLOR\u ATTACHMENT0
)读取时,情况会很好,但从其他2(黑屏)读取时则不会
守则:
// Texture indices - inside a 'myGlut' struct
GLenum skyboxTextureIndex = GL_TEXTURE0;
GLenum colorTextureIndex = GL_TEXTURE1;
unsigned int colorTextureIndexInt = 1;
GLenum depthTexture1Index = GL_TEXTURE2;
unsigned int depthTexture1IndexInt = 2;
GLenum depthTexture2Index = GL_TEXTURE3;
unsigned int depthTexture2IndexInt = 3;
//** Below is inside 'main()' **//
// Create frame buffer
myGlut.frameBuffer = glutils::createFrameBuffer();
// Create texture to hold color buffer
glActiveTexture(myGlut.colorTextureIndex);
glBindTexture(GL_TEXTURE_2D, myGlut.colorTexture);
myGlut.colorTexture = glutils::createTextureAttachment(myGlut.camera -> getRenderResizedWidthPx(), myGlut.camera -> getRenderResizedHeightPx());
glutils::bindTextureAttachment(GL_COLOR_ATTACHMENT0, myGlut.colorTexture);
// Create 1st texture to hold depth buffer wannabe :>
glActiveTexture(myGlut.depthTexture1Index);
glBindTexture(GL_TEXTURE_2D, myGlut.depthTexture1);
myGlut.depthTexture1 = glutils::createTextureAttachment(myGlut.camera -> getRenderResizedWidthPx(), myGlut.camera -> getRenderResizedHeightPx());
glutils::bindTextureAttachment(GL_COLOR_ATTACHMENT1, myGlut.depthTexture1);
// Create 2nd texture to hold depth buffer wannabe :>
glActiveTexture(myGlut.depthTexture2Index);
glBindTexture(GL_TEXTURE_2D, myGlut.depthTexture2);
myGlut.depthTexture2 = glutils::createTextureAttachment(myGlut.camera -> getRenderResizedWidthPx(), myGlut.camera -> getRenderResizedHeightPx());
glutils::bindTextureAttachment(GL_COLOR_ATTACHMENT2, myGlut.depthTexture2);
// Check FBO
if (!glutils::checkFBOStatus()) return 0;
使用glutils::
函数
// Clear screen
void glutils::clearScreen (float r, float g, float b, float a) {
glClearColor(r, g, b, a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
// Bind select framebuffer
void glutils::bindFrameBuffer(int frameBuffer, int width, int height) {
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glViewport(0, 0, width, height);
}
// Create frame buffer
GLuint glutils::createFrameBuffer() {
GLuint frameBuffer;
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
return frameBuffer;
}
// Create a texture attachment
GLuint glutils::createTextureAttachment(int width, int height) {
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
return texture;
}
// Bind a texture attachment to select framebuffer
void glutils::bindTextureAttachment (GLenum colorAttachment, GLuint texture) {
glFramebufferTexture2D(GL_FRAMEBUFFER, colorAttachment, GL_TEXTURE_2D, texture, 0);
}
// Check current frame buffer status
bool glutils::checkFBOStatus () {
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "##### ERROR : Frambuffer not complete... #####" << std::endl;
return false;
}
else return true;
}
相关统一绑定->通过1
glUniform1i(glGetUniformLocation(myGlut.theProgram, "depthTexture"), !myGlut.depthTextureSwitch ? myGlut.depthTexture2IndexInt : myGlut.depthTexture1IndexInt);
相关着色器代码->通过1
layout (location = 0) out vec4 outputColor;
layout (location = 1) out vec4 outputDepth1;
layout (location = 2) out vec4 outputDepth2;
uniform sampler2D depthTexture;
void main() {
// ...
outputColor = someColor;
outputDepth1 = someColor;
outputDepth2 = someColor;
}
相关统一绑定->通过2
glUniform1i(glGetUniformLocation(myGlut.theProgram2, "texFramebuffer"), myGlut.depthTextureSwitch ? myGlut.depthTexture1IndexInt : myGlut.depthTexture2IndexInt);
uniform sampler2D texFramebuffer;
out vec4 outputColor;
// ...
void main() {
outputColor = texture(texFramebuffer, vec2(gl_FragCoord.x / screenWidthPx * resRatio, gl_FragCoord.y / screenHeightPx * resRatio));
}
使用相关着色器代码->通过2
glUniform1i(glGetUniformLocation(myGlut.theProgram2, "texFramebuffer"), myGlut.depthTextureSwitch ? myGlut.depthTexture1IndexInt : myGlut.depthTexture2IndexInt);
uniform sampler2D texFramebuffer;
out vec4 outputColor;
// ...
void main() {
outputColor = texture(texFramebuffer, vec2(gl_FragCoord.x / screenWidthPx * resRatio, gl_FragCoord.y / screenHeightPx * resRatio));
}
简而言之:我的
GL_纹理0
保留场景,而GL_纹理1
和GL_纹理2
为黑色。为什么?我终于找到了罪犯。因为我在循环display()
函数中绑定帧缓冲区,所以在绑定FBO之后,我还需要绑定纹理附件。改为
// Bind to custom framebuffer
glutils::bindFrameBuffer(myGlut.frameBuffer, myGlut.camera -> getScreenWidthPx(), myGlut.camera -> getScreenHeightPx());
// Bind to select attachments
glutils::bindTextureAttachment(GL_COLOR_ATTACHMENT0, myGlut.colorTexture);
if (!myGlut.depthTextureSwitch) glutils::bindTextureAttachment(GL_COLOR_ATTACHMENT1, myGlut.depthTexture1);
else glutils::bindTextureAttachment(GL_COLOR_ATTACHMENT1, myGlut.depthTexture2);
允许我渲染到所有需要的颜色附件。基于
glDrawBuffers()
调用,您只渲染到2个纹理。对于过程2,您使用的是未渲染到的纹理。确实,我正在读取未渲染到的纹理,但这是(预期的)并且是由于“乒乓”渲染技术。所以这意味着我应该只在第一帧得到一个黑屏。因为在第2帧,我渲染到纹理2(打开)并从纹理1读取-我在第1帧渲染到的,依此类推。。。真正的问题是,我的渲染一直是黑色的,好像从来没有渲染过GL_TEXTURE1
和GL_TEXTURE2
。为什么?如果我尝试不断地从GL_TEXTURE1
或GL_TEXTURE2
读取,我会得到一个恒定的黑屏。只采样一个纹理(texFramebuffer),您不需要不同的ActiveTexture(tex插槽),令人困惑…是的,你是对的。但我需要在着色器过程1处读取depthTexture1
或depthTexture2
。因此使用了3个纹理槽。你需要的槽数与#TextureName相同,换句话说,#槽=#单个过程中采样的纹理。但是如果你真的想绑定3个纹理以避免调用bindTexture betw即使通过了,你也可以,但你必须声明3个不同的统一事实上,FBO附件保持不变,不需要重新设置。至少,如果你自己不在某个地方分离它们的话。很难从目前给出的代码片段中看出实际情况。我正在实现一个GPU乒乓()所以我需要在每一帧切换附件。例如:从0&1+写入到2@frame 1,从0&2+写入到1@frame to等等…问题是:我无法在一次过程中读取和写入纹理,因此乒乓球解决方案。无需重新附加。您所需的只是切换绘图缓冲区。顺便说一句,取决于在您实际执行的操作中,甚至可能在同一过程中读取和写入同一纹理。GL在某些特定条件下允许这样做。切换绘图缓冲区正是我开始做的事情,但由于某些原因,它对我不起作用…即绑定main()中的所有内容
-纹理和颜色附件-以及在display()
内切换绘图缓冲区都不起作用。