GLSL clarification: combining more effects

Well, this is probably a stupid question but: suppose you have scene with a terrain engine and some objects, and that i want to use shadows, lighting, bump mapping and more effects.

How should be “queued” correctly ?
I mean, i have to build a unique shader that does all the effects, and then apply it to every object ?
Or i can have several shaders (one for lighting, one for shadows etc.) and i can apply those in sequence to each object ?

It is never a good idea to run several shaders in sequence for each object, for all objects maybe, though a single large shader would be best, just remember to first render the depth to avoid unnecessary fragments, it could be done at the same time you do the shadows.

An alternative is to make several textures containing the depth, texture environment, normals, shadows and so on, then combine them in a universal shader using a method called deferred rendering.

Although this all depends on what is going to be rendered.

Or i can have several shaders (one for lighting, one for shadows etc.) and i can apply those in sequence to each object ?
Not in the way you mean.

You can certainly design a shader system to work that way. But glslang does not directly work that way. Shader programs are comprised of a vertex shader and a fragment shader (if you’re hardware is hardcore enough, you can get a geometry shader too). You can combine multiple vertex shaders into one linked program, but they have to be designed specifically to work together.

well writing the all the shader code in a single file is good idea when we want to have all effects on all of the objects.
But what if we want to have only some effects on the some of the objects & some diff. effects on diff. objects

Say i Have sphere, cube & plane surface.
I want “shadow & occlusion” 4 all the objects,
“Bump mapping” 4 cube & plane surface.
And “Phong Illumination” 4 Sphere & plane surface.

Now if i write a single shader file 4 all this effects than dont u think that i will b waisting the GPU 4 calculating unwanted effects. :confused:

in this case do u think writing single shader file is a good option??? :confused:

You can write a single shader with some conditional compiling:

#ifdef BUMP
 .. bump mapping
#ifdef PHONG
 .. phong ligting

Then you create different shader objects for each combination by defining the corresponding tokens.

  1. One shader file with #ifdef directives
  2. One shader with if statements
  3. One shader doing all the stuff - providing dummy textures for inactive effects
  4. Multiple shader files linked in different combinations

#1 and #4 create multiple shaders. #2 and #3 can produce slower shader, but it’s actually one shader so you can save a lot on shader switching.
#3 is a good approach if most of your objects use most of effects in that shader.
Note that you can use #1 and #4 to create such full-featured shader, too. You could actually make application that dynamically switches between both approaches to maximize performance (just try the other technique once every n frames. n depends on when was the technique changed last time and how big was the difference in last few tests).

My preferred is #4. It’s actually not that different from #1, but it improves reusability of code. You can, for example, put fresnel term equation in fragment or vertex shader depending on surface - if you use normal maps you need per-pixel fresnel term, but with flat surface and good tesselation you can calculate it per-vertex.
Same goes for scattering effects. Sometimes you need it per-pixel (human skin) and sometimes per-vertex (atmosphere).

But if you want to apply all effects to all objects then you don’t need any of that. Note that applying “dummy” effects (solution #3) to objects can be faster than switching shader. So if you don’t need shadow mapping/normal mapping on object, you can provide 1x1 empty shadow map/normal map for that object and use the same shader.

I don’t do any of this.
I generate programs automatically as required from currently active shader modules. The order in which the shader modules are executed is determined by a stage number.
A light can have a shader module, and when its enabled that shader module is added to the currently active shader state, along with its uniform values. Same for a material.
When I reach a drawable, a check is done with some hash tables to determine if a program has been linked containing the currently active modules. If not, a couple of main’s are generated that call those modules and a new program is linked. This programs id is added to the drawables bucket entry along with the values of the uniforms gathered from the shader state. The bucket is sorted by program id etc. and drawn.
It seems to work ok, if it weren’t for the heavy amount of instancing I’m doing I could optimise the shader selection much more.

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