Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: Layered rendering FBO

  1. #1
    Newbie Newbie
    Join Date
    Jun 2018
    Posts
    2

    Layered rendering FBO

    I am trying to implement layered rendering to render cascaded shadow maps in one pass via geometry shader. The idea is to use GL_TEXTURE_2D_ARRAY with 3 texture for each cascade. This is the framebuffer init code:

    Code :
    CSMTarget::CSMTarget(int w, int h) : _width(w), _height(h){
        // generate buffers:
        glGenTextures(1, &_layeredTexture);
        glGenFramebuffers(1, &_frameBuffer);
        //glGenRenderbuffers(1, &_depthrenderbuffer);
     
        // configure texture:
        glBindTexture(GL_TEXTURE_2D_ARRAY, _layeredTexture);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB32F, _width, _height, 3, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
        glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
     
        glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
        glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _layeredTexture, 0);
     
        // depth render buffer:
        //glBindRenderbuffer(GL_RENDERBUFFER, _depthrenderbuffer);
        //glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, _width, _height);
        //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthrenderbuffer);
     
        GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
        glDrawBuffers(1, DrawBuffers);
     
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

    Frame buffer is complete.
    Rendering to framebuffer:
    Code :
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
    glViewport(0, 0, _width, _height);
    //bind and update shader
    //geometry pass
    //unbind framebuffer
    geometry shader:
    Code :
    #version 330
    layout(triangles) in;
    layout(triangle_strip, max_vertices = 3) out;
    in vec2 uv_vert0[];
    out vec2 uv_frag0;
     
    uniform mat4 viewProjMatrices[3];
    void main() {
        for(int face = 0; face < 3; face++) {
            gl_Layer = face;
            for(int i = 0; i < 3; i++) {
                uv_frag0 = uv_vert0[i];
                gl_Position = viewProjMatrices[face] * gl_in[i].gl_Position;
                EmitVertex();
            }
            EndPrimitive();
        }
    }
    Matrices are updated by glUniformMatrix4fv from array of 3 4x4 matrices.
    And this is the part of directional light fragment shader that checks whether pixel is in shadow or not.
    Code :
    #version 330
    vec2 sampleSM_A(inout float bias){
        vec4 shadowUV = pc.dirLight.matrixA * vec4(data.worldPos,1);
        shadowUV.xyz = shadowUV.xyz * 0.5 + 0.5;
        if(shadowUV.x > 1 || shadowUV.y > 1 || shadowUV.x < 0 || shadowUV.y < 0) return vec2(-1.0, 0.0);
     
        bias = 0.00025;
     
        return vec2(texture(shadowMap, vec3(shadowUV.xy, 0)).x, shadowUV.z);
    }
    For sampleSM_B and C shadow map is sampled with texture(shadowMap, vec3(shadowUV.xy, LAYER_ID)). Red is first frustum split, green and pink are second and third.

    The problem is that only first split works correctly. Shadow mapping works fine for all three splits when I use 3 frame buffers with texture_2D and 3 passes.
    This is enabled glEnable(GL_TEXTURE_2D_ARRAY).

    Is it a good idea if I use MRT with 3 textures instead of layered rendering?
    Click image for larger version. 

Name:	5I9UK.jpg 
Views:	51 
Size:	19.7 KB 
ID:	2778

  2. #2
    Junior Member Newbie
    Join Date
    May 2018
    Posts
    13
    Quote Originally Posted by someRand View Post
    geometry shader:
    Code :
    #version 330
    layout(triangles) in;
    layout(triangle_strip, max_vertices = 3) out;
    in vec2 uv_vert0[];
    out vec2 uv_frag0;
     
    uniform mat4 viewProjMatrices[3];
    void main() {
        for(int face = 0; face < 3; face++) {
            gl_Layer = face;
            for(int i = 0; i < 3; i++) {
                uv_frag0 = uv_vert0[i];
                gl_Position = viewProjMatrices[face] * gl_in[i].gl_Position;
                EmitVertex();
            }
            EndPrimitive();
        }
    }
    You generate 3 triangles from 1 triangle. 3 triangles are 9 vertices, so you should set max_vertices to 9, not 3.

    Quote Originally Posted by someRand View Post
    Is it a good idea if I use MRT with 3 textures instead of layered rendering?
    From my experience, it is not a good idea to use a geometry shader to render your objects into multiple frustum splits within a single pass. In my case frustum culling on CPU was too coarse and I wasted lots of GPU-cycles just to clip triangles that weren't visible in the final image. See this thread for the details:
    https://www.opengl.org/discussion_bo...ping?p=1291643
    As always, there is no general answer to this, I would implement several methods, profile the code and then you'll see what gives the best performance.

  3. #3
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,478
    Quote Originally Posted by someRand View Post
    I am trying to implement layered rendering to render cascaded shadow maps in one pass via geometry shader. The idea is to use GL_TEXTURE_2D_ARRAY with 3 texture for each cascade.
    Quote Originally Posted by fleissna
    From my experience, it is not a good idea to use a geometry shader to render your objects into multiple frustum splits within a single pass. ... As always, there is no general answer to this, I would implement several methods, profile the code and then you'll see what gives the best performance.
    My experience agrees with fleissna's here as well. The geometry shader is an expensive way to replicate a lot of geometry, and it particularly stinks when there is a lot of out-of-frustum geometry, which there is in your case. But definitely try it both ways and see for yourself. You can find mention of this geometry shader performance issue in many graphics talks and presentations.

    This is enabled glEnable(GL_TEXTURE_2D_ARRAY).
    Yeah, "enabling" texture units drove shader generation with the ol' pre-shaders fixed-function pipeline, which you don't appear to be using (given your geometry shader). You don't enable/disable them anymore. You just bind textures to them and then use the bound textures in your shader code.

    Is it a good idea if I use MRT with 3 textures instead of layered rendering?
    No, definitely not when your replicating so much out-of-frustum geometry that's just going to get thrown in the bit bucket later. And even if you're not, they're still expensive. Use them with care.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •