openglglslgeometry-shadervertex-attributes

Passing vertex attributes with layouts in geometry shader


Let's say we have a GL program consisting of the following vertex, geometry and fragment shaders.

vertex:

#version 410
layout (location = 0) in vec2 pos;
layout (location = 1) in vec2 size;
layout (location = 2) in float rot;
layout (location = 3) in vec4 color;

layout (location = 0) out vec2 p;
layout (location = 1) out vec2 s;
layout (location = 2) out float r;
layout (location = 3) out vec4 c;

void main(){
    gl_Position = vec4(pos,0.0,1.0);

    p = pos;
    s = size;
    r = rot;
    c = color;
}

geometry:

#version 410
layout (points) in;
layout (triangle_strip, max_vertices = 4) out;

layout (location = 0) in vec2 pos;
layout (location = 1) in vec2 size;
layout (location = 2) in float rot;
layout (location = 3) in vec4 color;

layout (location = 0) out vec2 p;
layout (location = 1) out vec2 s;
layout (location = 2) out float r;
layout (location = 3) out vec4 c;

void main()
{
    gl_Position = gl_in[0].gl_Position + vec4(-0.2, -0.2, 0.0, 0.0);    // 1:bottom-left
    EmitVertex();
    gl_Position = gl_in[0].gl_Position + vec4( 0.2, -0.2, 0.0, 0.0);    // 2:bottom-right
    EmitVertex();
    gl_Position = gl_in[0].gl_Position + vec4(-0.2,  0.2, 0.0, 0.0);    // 3:top-left
    EmitVertex();
    gl_Position = gl_in[0].gl_Position + vec4( 0.2,  0.2, 0.0, 0.0);    // 4:top-right
    EmitVertex();
    EndPrimitive();

    p = pos;
    s = size;
    r = rot;
    c = color;
}

fragment:

#version 410

layout (location = 0) in vec2 pos;
layout (location = 1) in vec2 size;
layout (location = 2) in float rot;
layout (location = 3) in vec4 color;

out vec4 FragColor;

void main()
{
    FragColor = color;
}

The program takes points and display them as quads.

What I'm trying to do here is to pass the 4 vertex attributes (pos, size, rot and color) to the fragment shader through the geometry shader.

If I remove the geometry shader from my program, it manages to pass the vertex attributes to the fragment shaders and it displays colored dots.

If I keep the geometry shader and remove the layouts (in and out), it displays black quads.

Am I missing something here?


Solution

  • There are a couple of issues in your code. I've renamed all of the variables so you can see what's going on (This probably wouldn't be a massive problem, since you are using layout qualifiers, but I'll stick with a naming that makes it obvious what's happening).

    #version 410
    
    // per-vertex attributes from the vertex buffers
    layout (location = 0) in vec2 vs_pos;
    layout (location = 1) in vec2 vs_size;
    layout (location = 2) in float vs_rot;
    layout (location = 3) in vec4 vs_color;
    
    // per-vertex inputs to the geometry shader
    layout (location = 0) out vec2 gs_pos;
    layout (location = 1) out vec2 gs_size;
    layout (location = 2) out float gs_rot;
    layout (location = 3) out vec4 gs_color;
    
    void main(){
        gl_Position = vec4(vs_pos,0.0,1.0);
    
        // pass vars from vertex shader, to geometry shader
        gs_pos = vs_pos;
        gs_size = vs_size;
        gs_rot = vs_rot;
        gs_color = vs_color;
    }
    
    #version 410
    layout (points) in;
    layout (triangle_strip, max_vertices = 4) out;
    
    // when passed to the geometry shader, these variables are now arrays!
    // be sure to declare them as such...
    layout (location = 0) in vec2 gs_pos[];
    layout (location = 1) in vec2 gs_size[];
    layout (location = 2) in float gs_rot[];
    layout (location = 3) in vec4 gs_color[];
    
    // the outputs to the fragment shader are presented as
    // single attributes though 
    layout (location = 0) out vec2 fs_pos;
    layout (location = 1) out vec2 fs_size;
    layout (location = 2) out float fs_rot;
    layout (location = 3) out vec4 fs_color;
    void main()
    {
        // pass vars for 1st vertex generated
        // (you may be able to get away with setting these once prior
        // to the first EmitVertex call, not sure, it's been a while!)
        fs_pos = gs_pos[0];
        fs_size = gs_size[0];
        fs_rot = gs_rot[0];
        fs_color = gs_color[0];    
        gl_Position = gl_in[0].gl_Position + vec4(-0.2, -0.2, 0.0, 0.0);
        EmitVertex(); //< emits all params above!
    
        // pass vars for 2nd vertex generated, etc... 
        fs_pos = gs_pos[0];
        fs_size = gs_size[0];
        fs_rot = gs_rot[0];
        fs_color = gs_color[0];    
        gl_Position = gl_in[0].gl_Position + vec4( 0.2, -0.2, 0.0, 0.0);
        EmitVertex(); //< emits all params above!
    
        fs_pos = gs_pos[0];
        fs_size = gs_size[0];
        fs_rot = gs_rot[0];
        fs_color = gs_color[0];    
        gl_Position = gl_in[0].gl_Position + vec4(-0.2,  0.2, 0.0, 0.0);
        EmitVertex(); //< emits all params above!
    
        fs_pos = gs_pos[0];
        fs_size = gs_size[0];
        fs_rot = gs_rot[0];
        fs_color = gs_color[0];    
        gl_Position = gl_in[0].gl_Position + vec4( 0.2,  0.2, 0.0, 0.0);
        EmitVertex(); //< emits all params above!
    
        EndPrimitive();
    
    }
    
    

    And finally the geometry shader.

    #version 410
    
    // the inputs to the fragment shader would have been interpolated
    // across the geometry primitive emitted by the GS. 
    layout (location = 0) in vec2 fs_pos;
    layout (location = 1) in vec2 fs_size;
    layout (location = 2) in float fs_rot;
    layout (location = 3) in vec4 fs_color;
    
    out vec4 FragColor;
    
    void main()
    {
        FragColor = fs_color;
    }