Is there a way that Geometryshaders in and out variables have the same name?

Let’s have a Vertexshader with
in vec2 vTexCoords;
out vec2 TexCoords;
and somewhere
TexCoords = vTexCoords.

The Fragmentshader takes that value with
in vec2 TexCoords

Now when i’m going to include a Geometryshader there will be two declarations with the same name
in vec2 TexCoords[];
out vec2 TexCoords;
and this yields to an compilation error “error(#198) Redefinition error: TexCoords”

This is somewhat awkward. Do i really have to rename variables based on the usage of a Geometryshader? I thought it would be a good idea to attach a geometryshader dynamically: Just hook it in between VS and FS without the necessity to change any of the sourcecode. But i don’t see how.

Somewhat related to this questions: Do you handle Shaders in packages in your projects or do you keep them seperate and link together whatever you need in a more dynamic way (if possible)? I’m still a bit unsure about best practices for managing shaders and naming conventions for in/out variables.

Thanks for your help

[QUOTE=Betrayal;1262840]
Now when i’m going to include a Geometryshader there will be two declarations with the same name
in vec2 TexCoords;
out vec2 TexCoords;
and this yields to an compilation error “error(#198) Redefinition error: TexCoords”

This is somewhat awkward.[/QUOTE]
It is not awkward. If you access TexCoords, how compiler knows whether you are accessing input attributes or output variables?

Yes, if you are using names for connecting shaders.

There are three ways to define interfaces between shaders:

  • using same variable names,
  • using variable locations and layout qualifiers,
  • using interface blocks.

Maybe the last method would be the best in your application. Blocks’ names can be the same in all shader stages.

Input and output interface blocks were designed for the expressed purpose of solving this problem. This is why interface blocks have instance names. Consider:


//Vertex Shader
in vec2 TexCoords;

out VertexData
{
  vec2 TexCoords;
} vs_out;

void main()
{
//...
  vs_out.TexCoords = TexCoords;
//...
}

Notice how the output interface block VertexData specifies an instance name (vs_out). This means that all access to variables within the interface block must be qualified by the instance name. Because this removes [var]TexCoords[/var] from the global namespace, it is OK to declare a global input variable with the same name. GLSL knows which one you’re talking about.

If you had not used an interface name, then the compiler would complain, as the variable in the output interface block would have the same name as the non-block input variable.


//Fragment Shader
in VertexData
{
  vec2 TexCoords;
} fs_in;

void main()
{
//...
  vec4 color = texture(tex, fs_in.TexCoords);
//...
}


The fragment shader’s input interface block VertexData matches the vertex shader’s output interface block VertexData. Note that the fragment shader uses the same block name, but a different instance name. That’s perfectly valid. Indeed, it could use no instance name at all and still be fine.

Now here’s where the magic happens. The following geometry shader can slip between the vertex and fragment shaders without any modification to them:


//Geometry Shader
in VertexData
{
  vec2 TexCoords;
} gs_in[];
out VertexData
{
  vec2 TexCoords;
} gs_out;

void main()
{
//...
  gs_out.TexCoords = gs_in[INDEX].TexCoords;
}

You saw before that the interface block’s instance name allows two variables to have the same basename, yet still be differentiated due to qualifying them with the instance name. Here, the same thing applies, just between two separate interface blocks.

And yes, even though the two interface blocks have the same block name, they are separate. Why? Because one is an input interface block, and the other is an output interface block. Now, you still need difference instance names there, so that the shader code can differentiate the two variables. But that’s all you need.

The input interface block VertexData matches the output interface block VertexData in the VS. While the output interface block VertexData matches the input interface block VertexData in the FS.

And everyone’s happy.

Alternatively, you can simply not link your shaders together in the same program. The above code with interface blocks would work just fine. But using separate programs also allows for direct linking by integers rather than names, so that different stages could name the variables different things.

1 Like

Thank you for that very good and interesting answer.