1
\$\begingroup\$

My hobby engine has a deferred renderer that supports normal maps and specular maps. Now, some objects may have normal maps, and some may have specular maps. In some cases, an object has both maps, and in some cases, it has neither.

The question is: how should I implement the rendering of these objects? Should I have a render queue for each different object type and render them with separate shaders like this:

Queue A: Objects without normal and specular map
Queue B: Objects with normal map, without specular map
Queue C: Objects without normal map, with specular map
Queue D: Objects with both normal map and specular map

// Render loop
bind shader for type 'A' objects
for each object in Queue A:
    render object

bind shader for type 'B' objects
for each object in Queue B:
    render object

// and so forth...

Or, should I use a single shader and bind a "default" normal map and specular map for those objects that do not have such maps? By a default map, I mean for example a normal map texture that's completely colored (128, 128, 255). This would be something like this:

bind shader
bind default normal map texture
bind default specular map texture

for each object in Queue A:
    render object

for each object in Queue B:
    bind object's normal map
    render object

bind default normal map texture
for each object in Queue C:
    bind object's specular map
    render object

for each object in Queue D:
    bind object's normal map
    bind object's specular map
    render object    

Basically, the first approach would involve less texture binds and more shader binds, whereas the second approach would be the opposite. Is either of these a preferred way to approach the problem? Or have I missed something completely here?

You can assume the objects are queued correctly to the queues.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ It's really hard to tell much without additional data. Both methods look valid - they will work and are likely to be fast. Commercial engines have gotten away with much less optimal rendering setups so I'm not sure if the question has value beyond satisfation of curiosity. So why don't you try both in various scenes and measure the frame time? Surely it doesn't take much time to implement both? \$\endgroup\$
    – snake5
    Jan 1, 2015 at 15:30

2 Answers 2

1
\$\begingroup\$

You can use a tiny neutral texture to "disable" shader features you're not using which incurs a texture switch penalty but no shader switch penalty.

You can generate multiple shaders with all feature combinations and switch to the proper shader, this incurs a shader switch penalty but the simpler shaders execute faster.

Which ever is best depends on which is costlier: shader execution time due to code complexity or shader switch time.

On mobile GPUs (-2015) shader complexity tends to be more expensive than shader switch, On desktop GPUs it will depend on the GPU core speed. Low-end desktop GPUs can be more like mobile GPUs in that sense.

This will also vary depending on the 3D scene being rendered.

\$\endgroup\$
1
\$\begingroup\$

Big engines using 'premutation' that make many shaders for every specifited set of material features. But thats not solution for 'deffered' rendering, for deffered rendering you should implement material 'indexes'

Indexes will select proper render path, and all material caps. Usualy indexes created in matrial pipeline, when level builds. Small parts of shader , glues together in big Uber shader.

Modern gpus easy can handle dynamic branches. So you can have material features in uniform flag.

Thats all comes for desktop GPUs, don't sure for mobile.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .