I am trying to render to multiple textures as COLOR_ATTACHMENT
s without success. All I get from displaying them is a black screen (with a red clear fill) meaning my texture is read but is 'empty'.
My pseudo code is : attach 3 textures to an FBO with texture indexes 1, 2 and 3 and color attachments 0, 1 and 2 respectively. As a test case, I tried to render my scene to the 3 color attachments so they are supposed to hold the same exact data. Then read either of those textures at shader pass 2 (with a 2Dsampler) and display them on a quad.
My original intent for those 2 extra color attachments is to use them as random data buffers using the GPU ping-pong technique. So far I just use them as texture clones for testing purpose.
When trying to read from GL_TEXTURE1
(COLOR_ATTACHMENT0
) things go fine but not from the other 2 (black screen).
The code :
// 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;
With glutils::
functions
// 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;
}
Then the glut display func :
// Clear screen
glutils::clearScreen(1.f, 0.f, 0.f, 1.f);
// Bind to custom framebuffer
glutils::bindFrameBuffer(myGlut.frameBuffer, myGlut.camera -> getScreenWidthPx(), myGlut.camera -> getScreenHeightPx());
// Set draw context
GLuint drawBuffers[2];
if (myGlut.depthTextureSwitch) { drawBuffers[0] = GL_COLOR_ATTACHMENT0;
drawBuffers[1] = GL_COLOR_ATTACHMENT2;
} else { drawBuffers[0] = GL_COLOR_ATTACHMENT0;
drawBuffers[1] = GL_COLOR_ATTACHMENT1;
} glDrawBuffers(2, drawBuffers);
// Use main program and bind uniforms
glUseProgram(myGlut.theProgram);
myGlut.refreshUniformsPass_1();
// Draw quad to sample
glutils::drawQuad();
// Unbind custom framebuffer -> use default (screen)
glutils::unbindCurrentFrameBuffer(myGlut.camera -> getScreenWidthPx(), myGlut.camera -> getScreenHeightPx());
// Use secondary program and bind uniforms
glUseProgram(myGlut.theProgram2);
myGlut.refreshUniformsPass_2();
// Draw quad to apply texture to
glutils::drawQuad();
// Switch
myGlut.depthTextureSwitch = !myGlut.depthTextureSwitch;
// Display & loop
glutSwapBuffers();
glutPostRedisplay();
Relevant uniform bindings -> pass 1
glUniform1i(glGetUniformLocation(myGlut.theProgram, "depthTexture"), !myGlut.depthTextureSwitch ? myGlut.depthTexture2IndexInt : myGlut.depthTexture1IndexInt);
Relevant shader code -> Pass 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;
}
Relevant uniform bindings -> pass 2
glUniform1i(glGetUniformLocation(myGlut.theProgram2, "texFramebuffer"), myGlut.depthTextureSwitch ? myGlut.depthTexture1IndexInt : myGlut.depthTexture2IndexInt);
With relevant shader code -> pass 2
uniform sampler2D texFramebuffer;
out vec4 outputColor;
// ...
void main() {
outputColor = texture(texFramebuffer, vec2(gl_FragCoord.x / screenWidthPx * resRatio, gl_FragCoord.y / screenHeightPx * resRatio));
}
In a nutshell : my GL_TEXTURE0
holds the scene while GL_TEXTURE1
and GL_TEXTURE2
are black. Why ?
glDrawBuffers()
call, you're only rendering to 2 textures. And it looks like for pass 2, you're using the texture you did not render to. – UnpaidGL_TEXTURE1
andGL_TEXTURE2
are never rendered to. Why ? If I try to constantly read fromGL_TEXTURE1
orGL_TEXTURE2
I get a constant black screen. – FarthestdepthTexture1
ordepthTexture2
at shader pass 1. Hence the 3 used texture slots. – FarthestglUniform1i(glGetUniformLocation(myGlut.theProgram, "depthTexture"), !myGlut.depthTextureSwitch ? myGlut.depthTexture2IndexInt : myGlut.depthTexture1IndexInt);
to get access to the right texture I need at this point. Then another uniform binding for the skybox. – Farthestuniform sample
, so you only need texture0 slot, to switch, you just have to call bindTexture with correct texID generated with genTexture. With uniform call, you attach the name used in your shader (texFramebuffer) with the ActiveTexture slot (Texture0), you should normaly call it only once. – ScalyglClearColor()
andglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
each frame with a red color (255, 0, 0) - but my color attachments 1 & 2 are black when displaying corresponding textures (2 & 3). I am attaching a depth buffer too but didn't show in the code above. Also when displaying textures 2 & 3 they are black not red from the glClear() call. – Farthest