Skip to main content
GameDev.net gamedev.net
🔒 Locked

unlimited number of lights, how?

Started by billconan Nov 20, 2009 at 11:57 PM 7 replies 2k views
Original Post
billconan
billconan
hello guys, i want my program to support unlimited number of lights. i want to achieve it with shader. but i don't know how. especially how to transfer the lighting information to the gpu? through a texture map? is there any example that i can look at?
RDragon1
RDragon1

I think you're looking for "deferred shading" or "deferred lighting" - research that and you should find plenty of resources
spek
spek
Stepping over from the fixed OpenGL functionality to shaders would be the most important thing to start with. And learning howto do multipassing. Once you get a grip on it, you can decide wether to use deferred rendering (or a variant) or traditional "forward rendering".

In both cases there is no limit to your lights, although your hardware & coding quality will be the limiting factor in practice :). As for forward rendering... You can simply use multipassing. Enable "additive blending" and then:
glEnable( GL_BLEND );glBlendFunc(GL_SRC_ALPHA, GL_ONE); // Additive blending// Render the scene for each light. Because blending is enabled, all results// will be "pasted" on top of each other.for i:=0 to lights.count-1 do   lights.lightingShader.apply();   lights.affectedScenery.render();

Now since you render the scene again for each light, this will give quite some overhead. Two things can be done:
- For smaller lights: only render affected geometry, not the whole scene.
- Combine multiple lights into 1 shader...

The second solution can give you a quite a speed gain. However, it's difficult to predict which lights can be combined into a single shader. Especially if you use many different types of lights (pointlights, spotlights, with/without shadowMap, etc.) and if these lights can move.



Another alternative is Deferred lighting. Instead of drawing the scene again and again for each light, you render all required "base data" to a set of textures (ussually four). Lighting could require:
- pixel position / distance
- pixel albedo color
- pixel shininess / specular color
- pixel normal
With the help of MRT (Multi Render Target), you can render all this stuff on multiple textures in a single drawing call. For example:
texture1.rgb = pixel albedo color
texture2.rgb = pixel normal
texture3.rgba = pixel specular color, shininess
texture4.rgb = pixel position

These textures are created via a FBO, meaning you render your data to these textuers in the background. When that is done, you can use these textures as very usefull data sources for various applications. The most common one would be lighting. For example, if you render a spotlight, just render a sphere that covers the light "volume". A special shader that is used on this sphere will grab the corresponding pixels from the data buffers so we can do the lighting.

The advantages:
- Scenery only needs to be rendered once
- Using textures, calculating normals and all that kind of stuff only has to be done one time as well in this first pass. This can save alot of texture switching and calculating the same thing over and over again.

Disadvantages:
- The 4 data targets can eat up quite some video memory. Certainly not suitable for older hardware!
- Rendering transparent stuff still needs a different (forward rendering) approach. Rendering partial transparent stuff to the data textures will mess it up. You can't blend normals or positions!

Greetings,
Rick
billconan
billconan
thank you so much.

i have never done multipass before, except the kind that only write to the depth buffer during the first pass.

i didn't know the correct blending function for this. i will have a closer look at your post. and search for inferred lighting.
spek
spek
@Villem Otte
Interesting paper! But I still don't see how they manage translucent data. Just like deferred lighting, they store normals and depth into a buffer. So what happens if a 50% transparent object is in front of another (opaque or transparent) object? There is only room for 1 normal/depth value, blending them doesn't work. Or did I miss something?

Greetings,
Rick

TheUnnamable
TheUnnamable
It draws translucent objects stippled to the G-Buffer, and DSFing makes it blend nicely. ( See figure 5 in the pdf )
spek
spek
Yes, but the problem still remains. Let's say I draw transparent pixels after each 2 pixels. What happens if 2 transparent objects are placed behind each other, they still share the same pixel right? This probably doesn't happen that often, but still... Scenes with lot's of foliage for example... The half-transparent edges of grass blades could give problems I think. By the way, why not drawing the transparent part not to a second (smaller?) texture instead of stippling on the same buffer?

Cheers
Vilem Otte
Vilem Otte
Quote:
Yes, but the problem still remains. Let's say I draw transparent pixels after each 2 pixels. What happens if 2 transparent objects are placed behind each other, they still share the same pixel right? This probably doesn't happen that often, but still... Scenes with lot's of foliage for example... The half-transparent edges of grass blades could give problems I think. By the way, why not drawing the transparent part not to a second (smaller?) texture instead of stippling on the same buffer?

Cheers

Yes, transparency is quite a problem ... even here. I'm solving this with multiple G-buffers (thats quite nightmarish solution if you are optimizing it) ... this is quite similar to depth-peeling (to achieve order independent transparency/transculency), but it will still remain fillrate heavy (as my game (and not just game) engine is fillrate heavy - but it eats lots of power on other parts also (high quality massive physics, real time ray tracing, full scale dynamic global illumination, inverse cinematic driven animations, etc.), so the whole engine is computationally heavy ... deferred rendering made lots of things to run a lot faster (especially GI).

Scenes with lots of foliage can be also rendered using alpha tests (but that results in aliased edges and one needs to supersample them and that is slow), also very good solution is to render them in another pass (using forward renderer) with sampling alpha to coverage (and then just mix them within post processing).
Also notice in Stalker (very good example of game with deferred rendering) glass look very ugly (it definitely needs reflections/refractions F.e. through some trick) and foliage (and not just foliage) is very aliased - this is due to not-ability of performing antialiasing within frame buffers (well it IS POSSIBLE nowadays, but it also needs faster GPUs - in opengl through GL_EXT_framebuffer_blit and GL_EXT_framebuffer_multisample, although i don't know if it can sample alpha to coverage (I'm about to implement these two into my engine)).

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.