简体   繁体   中英

Render depth as texture from framebuffer to displaying window

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结果深度
![预期部门

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM