2
\$\begingroup\$

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.

enter image description here

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;
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I think the line :

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, DepthBufferId);

Is the cause of your problem. It means that you are replacing the previously GL_DEPTH_ATTACHMENT bound texture by a classic render buffer.

The texture is then empty when you try to render it on screen.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .