I have a scene with some objects and some lights of different kinds (spotlight, direct, etc) and each one of them has a different algorithm to calculate it. On the other hand each objects have a material (glsl program). Wich is the best (or the common) way to manage all this lights, i wouldn´t like to have the same light algorithms in all object script materials. Is there any way to detach materials from the different kinds of ligthing?
pd: sorry, my english is not the best, i know it jeje
Is there any way to detach materials from the different kinds of ligthing?
One of the more common ways nowadays to detach light application and material sampling is what are called “deferred” rendering techniques, such as: Deferred Shading, Deferred Lighting (aka Light Pre-pass), Light Indexed Deferred Rendering, etc.
The basic concept is to sample the materials (or lighting) at the the first surface visible from the camera at each pixel (or sample), and then go back and apply the lighting (or materials) to those (using a separate shader or compute kernel).
Challenges with deferred techniques include dealing with transparency and MSAA.
But yeah, with traditional forward rendering, you’ve got this #lights * #materials shader explosion. You can mitigate this a little by only applying one light per pass, but then you have more batches+fill, and still are left with a #light_types * #materials shader explosion.
On the flipside, more and more games using deferred last few years, including Battlefield 3 (Frostbite 2 engine), Blur, Split/Second: Velocity, Just Cause 2, Crysis 2 (Cryengine 3 engine), Halo 3, Halo 3: ODST, Pure, Call of Juarez: BiB, Killzone 2, etc.
Deferred is the future because, as you say, it separates lights and objects.
Well, it rather depends on what you’re doing. If you have a lot of lights, deferred rendering can be a performance win due to saving vertex shader time from multi-passing objects and saving fragment shader time. Even moreso if you do tessellation. Not to mention making your shaders much more manageable.
However, it isn’t free. For each pixel, for each light, you have quite a bit of overhead. Lots, lots of texture reads. The larger the framebuffer, the more reads per-light. Multisampling hurts badly too, since you effectively have multiple back-buffers. Not to mention the memory overhead. And the fact that, per fragment, per-light, you’re doing a bunch of transformations to compute the light-space (for whatever space you’re doing lighting in) vertex position (unless you store this in a buffer, in which case that’s yet another memory fetch).
This may be something of a diverging point in hardware. Small-scale GPUs (integrated CPU/GPUs, anything you find on mobile devices) will be absolutely terrible at this. CPU/GPUs have much less texture read bandwidth, so they can’t really afford the cost. And mobile GPUs don’t have the memory to throw away on a lot of G-buffers.
But small-scale GPUs are going to be where the money goes. Sure, eventually they’ll be able to do deferred too. But not for some time.
Take a look at GL 4.1’s pipeline objects extension. It lets you mix and match ondividual shaders without relinking just like D3D. Should work on any D3D10 cards from ATI and NVIDIA (should also work on D3D9 cards too if they still get driver updates).
Another option is the shader subroutine extension, but this will only work on D3D11 cards.
Thus TBDR (Tile-based Deferred Rendering), which shares texture reads across many lights.
Multisampling hurts badly too, since you effectively have multiple back-buffers.
Actually, no, not in general. On recent high-end cards (even ones generations old), it’s amazingly not that expensive to MRT rasterize with MSAA. There seems to be plenty of bandwidth there. The real trick comes in being smart about how you light to emulate MSAA’s perf benefit.
You can perform quite a few tricks with deferred to minimise performance hit… I quite recently had a go at writing one, quite fun. Rendered the pointlights using inverted 8-sided spheres. Made use of the depth buffer to only discard fragments out of range on the Z axis before any sampling is done. On my 512Mb 9500GT I pulled 25-30 FPS with 300kpolies and 128 pointlights at 1680x1050. Not terrible given I didn’t do much optimisation once it was working. More of an experiment. Some things are a bit broken, such as specular highlights being a bit… odd.