shading setup

i have been using one single lighting shader for all geometry. however, for some meshes one might not want a specific feature to be applied, e.g. no normal mapping, no specular mapping etc. how should i deal with this? i can think of 3 solutions:

  1. i stick with one shader and use if-statements. that’s slow, but works.
  2. i use #define’s and compile several shaders. i then switch to the appropiate shader for every mesh, but have to re-set all the uniforms for every mesh.
  3. i stick with one shader and create dummy textures which i then use instead of real ones, if those are not present (e.g. a plain blue 2x2 texture if no normal map is provided)

what would you suggest? thanks!

If you can think of n solutions then you actually have 2^n-1 solutions - always consider using a hybrid :slight_smile:

In your list my choice would be a hybrid of #2 and #3, but I would add one more solution to this list:
4) Create multiple small shader objects. Each shader represents one sngle effect. Link in different combinations.
This is similar to #2 but I like the idea more than putting lots of #ifdef in the code.

So main shader would look like this:

void main(void)
{
  vec3 normal = GetNormal();  /* constant or from texture */
  vec2 texCoord = GetTexCoord();  /* no offset, parallax or displacement */
  vec4 diffuse = GetDiffuse(normal, texCoord);  /* constant, texture, lightmap, subsurface scatering */
  vec4 specular = GetSpecular(normal, texCoord); /* none, constant, masked, environment reflection */
  vec4 color = MixDiffuseAndSpecular(diffuse, specular, normnal, texCoord); /* add, blend, fresnel term */
  gl_FragColor = color;
}

Now you only have to link it with different implementations of used functions.
Of course you can also use different set of main funcitons or both approaches at the same time.

hey that sounds like a great idea. i’ll do that, thanks!

mh i’ve decided against your solution in the end - having to re-set all the uniforms for every shader switch turned out to be more expensive than simply using one shader and providing dummy textures.

One offtopic question:

When you have defines for example:

#ifdef PARAM_1
   code for param 1
#endif

How do you set the PARAM_1 to be defined? The only method I can think of is to add the #define PARAM_1 line at the top of the shader but this looks bad.

Sorry for the off and for the English,
Teodor

You can add that in glShaderSource call. You can pass several shader source strings.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.