Reputation: 57
I am new to OpenGL. I want to read and save all the depth values from the rendered scene using framebuffers. I managed to set it up as a framebuffer attached to the depth component. But when I render the depth texture to the default framebuffer (displaying window) it only shows the color white, even though I linearized the depth value (tutorial followed from https://learnopengl.com/). I get a depth map when I access the depth value from gl_FragCoord.z in the default framebuffer fragment shader and the plot is also ok, but when sending depth as texture from a separate framebuffer to the default, the depth image is strong white.
The code that I wrote for this is given below:
Custom framebuffer vertex and fragment shader
const char* vertexShaderFBO =
"#version 330\n"
"layout (location = 0) in vec3 vp;"
"uniform mat4 camera;"
"uniform mat4 projection;"
"void main() {"
" gl_Position = camera * projection * vec4(vp.x, vp.y, vp.z, 1.0);"
"}";
const char* fragmentShaderFBO =
"#version 330\n"
"layout (location = 0) out float frag_depth;"
"float near = 0.1;"
"float far = 100;"
"float LinearizeDepth(float depth)"
"{"
" float z = depth * 2.0 - 1.0;"
" return (2.0 * near * far) / (far + near - z * (far - near));"
"}"
"void main() {"
" float linearDepth = LinearizeDepth(gl_FragCoord.z) / far;" // divided by far is just to visualize depth
" frag_depth = linearDepth ;"
"}";
Default framebuffer vertex and fragment shader
const char* vertexShader =
"#version 330\n"
"layout (location = 0) in vec3 vp;"
"uniform mat4 camera;"
"uniform mat4 projection;"
"void main() {"
" gl_Position = camera * projection * vec4(vp.x, vp.y, vp.z, 1.0);"
"}";
const char* fragmentShader =
"#version 330\n"
"out vec4 frag_colour;"
"uniform sampler2D depthSampler;"
"in vec2 texCoords;"
"void main() {"
" float depthVal = texture(depthSampler, texCoords).r;"
" frag_colour = vec4(vec3(depthVal), 1);"
"}";
Depth Texture
GLuint setDepthTexture()
{
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SCREEN_SIZE.x, SCREEN_SIZE.y, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
return texture;
}
Render OFF files
int renderOFF(Vertices* vertices, Faces* faces, Views* views)
{
// initializaion
...
...
glEnable(GL_DEPTH_TEST); // enable depth buffer
glDepthFunc(GL_LESS); // If pixel closer to camera then overwrite the existing pixel
...
...
// create framebuffer shader
GLuint shaderProgramFBO = createShader(vertexShaderFBO, fragmentShaderFBO);
// create renderer shader
GLuint shaderProgram = createShader(vertexShader, fragmentShader);
//set texture
GLuint depthTexture = setDepthTexture();
// set framebuffer
unsigned int fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// attach texture to framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
std::cout << "Failed to bind framebuffer" << std::endl;
return -1;
}
// Use no color attachment
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(shaderProgram);
glUniform1i(glGetUniformLocation(shaderProgram, "depthSampler"), 0);
// set camera
...
...
while(!glfwWindowShouldClose(glfWwindow))
{
// check OpenGL error
GLenum err;
while ((err = glGetError()) != GL_NO_ERROR) {
std::cout << "OpenGL error: " << err << std::endl;
}
// bind to custom framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glClearColor(0, 0, 0, 1); // clear screen to black
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shaderProgramFBO);
...
glEnable(GL_DEPTH_TEST);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, faces->size, GL_UNSIGNED_INT, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// default framebuffer
glClearColor(0, 0, 0, 1); // clear screen to black
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
processKeyBoardInput(glfWwindow);
...
//glDisable(GL_DEPTH_TEST);
glBindVertexArray(vao);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glDrawElements(GL_TRIANGLES, faces->size, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(glfWwindow);
glfwPollEvents();
sleep(1);
}
glDeleteFramebuffers(1, &fbo);
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glfwTerminate();
return 0;
}
The resulted rendered image vs expected image results are given below
Upvotes: 1
Views: 2279
Reputation: 210909
The fragment shader assigns the depth values in the range [near, far] to the color values in range [0.0, 1.0]. If all of the geometry is in an area close to 0.0, the rendering will appear almost black as 0.1 is rendered black and 100 is rendered white. Move the near and far plane of the viewing volume (viewing frustum) as close to the geometry as possible to take advantage of the entire range between 0.0 and 1.0.
Your fragment shader will work fine when the near plane is close to 0. As the near plane gets larger, you should use:
float linearDepth = LinearizeDepth(gl_FragCoord.z) / far;
float linearDepth = (LinearizeDepth(gl_FragCoord.z) - near) / (far - near);
Upvotes: 0