I'm trying to render my scene's depth via FBO and Render To Texture. I have a scene that I'm rendering to a texture, then render that texture to a fullscreen quad in a second pass using a fragment shader that adds a tiny offset to the fragments giving them a pixelated look. It all works fine.
Now what I'm trying to do is basically render the depth of that scene instead of the actual colors. So I change GL_COLOR_ATTACHMENT0
to GL_ DEPTH_ATTACHMENT
in glFramebufferTexture
and GL_DEPTH_COMPONENT
instead of GL_RGB
in glTexImage2D
when configuring the render texture. I run the scene and all I get is blackness!
What am I missing? Are there any other configs that I should be aware of? Any help is appreciated!
Here's my drawing code and framebuffer setup:
int RenderToTexture(void)
{
// Initialise GLFW
if (!glfwInit())
{
fprintf(stderr, "Failed to initialize GLFW\n");
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Open a window and create its OpenGL context
window = glfwCreateWindow(1024, 768, "Playground", NULL, NULL);
if (window == NULL) {
fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
glfwSetCursorPos(window, 1024 / 2, 768 / 2);
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
// Depth test and culling
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE);
// Required for core profile
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Assets
vector<vec3> Verticies, Normals;
vector<vec2> UVs;
vector<unsigned short> Indicies;
LoadOBJFile("suzanne.obj", Verticies, UVs, Normals, Indicies, true);
GLuint Texture = LoadDDSFile("uvmap.dds");
// Create and compile our GLSL program from the shaders
GLuint Program = LoadShaders("Vertex.shader", "Fragment.shader");
// Uniforms
GLuint TextureLocation = glGetUniformLocation(Program, "TextureSampler");
GLuint LightPosLocation = glGetUniformLocation(Program, "LightPos");
GLuint ModelToWorldLocation = glGetUniformLocation(Program, "ModelToWorld");
GLuint MVPLocation = glGetUniformLocation(Program, "MVP");
GLuint CameraPosLocation = glGetUniformLocation(Program, "CameraPos");
GLuint LightIntensityLocation = glGetUniformLocation(Program, "LightIntensity");
// Verticies
GLuint VertexBufferId;
glGenBuffers(1, &VertexBufferId);
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferId);
glBufferData(GL_ARRAY_BUFFER, Verticies.size() * sizeof(vec3), &Verticies[0], GL_STATIC_DRAW);
// UVs
GLuint UVBufferId;
glGenBuffers(1, &UVBufferId);
glBindBuffer(GL_ARRAY_BUFFER, UVBufferId);
glBufferData(GL_ARRAY_BUFFER, UVs.size() * sizeof(vec2), &UVs[0], GL_STATIC_DRAW);
// Normals
GLuint NormalsBufferId;
glGenBuffers(1, &NormalsBufferId);
glBindBuffer(GL_ARRAY_BUFFER, NormalsBufferId);
glBufferData(GL_ARRAY_BUFFER, Normals.size() * sizeof(vec3), &Normals[0], GL_STATIC_DRAW);
// Index/Elements buffer
GLuint ElementIndexBufferId;
glGenBuffers(1, &ElementIndexBufferId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ElementIndexBufferId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, Indicies.size() * sizeof(unsigned short), &Indicies[0], GL_STATIC_DRAW);
#if 1
// Render to texture stuff
// Generate a Framebuffer
GLuint FramebufferId;
glGenFramebuffers(1, &FramebufferId);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferId);
// Generate render texture
GLuint RenderTextureId;
glGenTextures(1, &RenderTextureId);
glBindTexture(GL_TEXTURE_2D, RenderTextureId);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 768, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, 1024, 768, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, RenderTextureId, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, RenderTextureId, 0);
// Generate a depth buffer
GLuint DepthBufferId;
glGenRenderbuffers(1, &DepthBufferId);
glBindRenderbuffer(GL_RENDERBUFFER, DepthBufferId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 1024, 768);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, DepthBufferId);
// Draw buffers
GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, DrawBuffers);
// Are we good?
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
return false;
// Generate a quad to fill the screen with and draw our texture on
GLfloat Quad[] =
{
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
GLuint QuadId;
glGenBuffers(1, &QuadId);
glBindBuffer(GL_ARRAY_BUFFER, QuadId);
glBufferData(GL_ARRAY_BUFFER, sizeof(Quad), Quad, GL_STATIC_DRAW);
// Create and compile render texture shaders
GLuint RenderProgram = LoadShaders("Passthrough.vert", "Render.frag");
GLuint RenderTextureLocation = glGetUniformLocation(RenderProgram, "RenderTexture");
GLuint RenderTimeLocation = glGetUniformLocation(RenderProgram, "Time");
// -- end of RenderTexture --
#endif
// The idea is that we render our scene normally to our render texture (via framebuffer)
// Then render that texture to the screen (via releasing our previously bound framebuffer)
do
{
// Render scene to framebuffer / render texture
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferId);
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, 1024, 768);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(Program);
vec3 LightPos = vec3(0, 0, 0);
float LightIntensity = 1.0f;
glUniform3fv(CameraPosLocation, 1, &CameraPosition[0]);
glUniform1f(LightIntensityLocation, LightIntensity);
glUniform3fv(LightPosLocation, 1, &LightPos[0]);
ComputeMatricesFromInputs();
mat4 Rotation, Translation, ModelMatrix, MVP;
Translation = translate(mat4(), vec3(0.0f, 0.0f, -5.0f));
Rotation = rotate(Translation, 0.0f, vec3(0.0f, 1.0f, 0.0f));
ModelMatrix = Rotation;
MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
glUniformMatrix4fv(ModelToWorldLocation, 1, GL_FALSE, &ModelMatrix[0][0]);
glUniformMatrix4fv(MVPLocation, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, Indicies.size(), GL_UNSIGNED_SHORT, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
glUniform1i(TextureLocation, 0);
// location = 0 : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferId);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// location = 1 : UVs
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, UVBufferId);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
// location = 2 : normals
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, NormalsBufferId);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ElementIndexBufferId);
glDrawElements(GL_TRIANGLES, Indicies.size(), GL_UNSIGNED_SHORT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
#if 1
// Render our texture/framebuffer to screen
glBindFramebuffer(GL_FRAMEBUFFER, 0); // to indicate that we're not drawing to a framebuffer anymore!
glViewport(0, 0, 1024, 768);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(RenderProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, RenderTextureId);
// pass the render texture to our shader (has to be loaded first - slot 0 in this case)
glUniform1i(RenderTextureLocation, 0);
glUniform1f(RenderTimeLocation, (float)(glfwGetTime() * 10.0f));
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, QuadId);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
// -- end of render to target --
#endif
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0);
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}
Here's the shaders for that second/render texture pass:
Vertex shader:
#version 330 core
layout(location = 0) in vec3 VertexPos;
out vec2 UV;
void main()
{
// Since we're drawing a quad (two triangles) to fill the entire screen
// We do not need MVP because the actual quad is in projected space
// Since UV coordinates ranges [0, 1] and our screen coordinate [-1, 1]
// We need to map [-1, 1] to [0, 1]
// This is done by adding vec2(1, 1) and dividing by 2
// Now we can get the UV coordinate from the vertex position
gl_Position = vec4(VertexPos, 1);
UV = (VertexPos.xy + vec2(1, 1)) / 2.0;
}
Fragment shader:
#version 330 core
in vec2 UV;
out vec3 FinalColor;
uniform sampler2D RenderTexture;
uniform float Time;
void main()
{
FinalColor = texture(RenderTexture, UV +
0.005 * vec2(sin(Time + 1024.0 * UV.x),
cos(Time + 768.0 * UV.y))).xyz;
}