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\$
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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.