6.2. Effects that cooperate with geometry shaders

User effects that want to cooperate with geometry shaders have to override plugs PLUG_­geometry_­vertex_­xxx. The exact specification of these plugs is in Section A.4, “Geometry shader plugs”. Overriding these plugs allows to pass-through or blend custom vertex attributes needed by the effects. By correctly overriding them, the user effects can work regardless if the geometry shader is linked or not.

To override these plugs, user effects must include an EffectPart with type set to "GEOMETRY". This EffectPart code is optional. It will be used if an other effect will provide a main() entry for geometry shaders, and discarded otherwise.

Our goal throughout this paper is to make effects independent from each other, and composable with each other. See the example compositing_shaders/geometry_shader_optional.x3dv in our demo models. It shows that all kinds of effects, including geometry shader effects, may be created and applied independently from each other. As always, just placing two or more effects together on the X3D effects field makes them automatically cooperate.

There is one obstacle here. In case of user-defined vertex attributes, using the geometry shader means that the attribute name must change on its way from the vertex shader to the fragment shader. That is because you have to use different input and output names for this attribute inside the geometry shader. On the other hand, when there is no geometry shader, attribute name must be exactly the same in both the vertex shader and fragment shader. This means that creating a vertex, fragment and geometry shader combo in which the geometry shader is optional is not possible in pure shading language like GLSL. To overcome this, we automatically define a symbol HAS_GEOMETRY_SHADER for all fragment shaders' parts. This way we can write in the fragment shader code like:

#ifdef HAS_GEOMETRY_SHADER
  #define my_attribute my_attribute_fragment
#endif
in float my_attribute;

Such fragment shader can receive its input either from the geometry shader (under the name my_attribute_fragment) or straight from the vertex shader (under the name my_attribute).