Sign in to follow this  
Bow_vernon

Multiple Lights on game map with forward rendering

Recommended Posts

Bow_vernon    323

Hi guys, phew it's been like forever since I stopped game development.

 

Well, I'd go straight to the point. This is a problem that's been bugging me more than it should. I'm making a 3d rpg game for android, right now I've finished designing the game map format (no graphical thing to see yet :p) but it suddenly hit me like a thunder. How would I allow multiple light source to light my game map?

 

Well I'm using glsl (of course) + forward rendering. I couldn't use the same approach I used for game objects, because each object can only be lit by a maximum of FOUR light sources (I got that implemented already from my previous game). Each object holds a reference to a maximum of four light sources that will affect them most.

 

Now, I've seen several games using this approach too for their objects (players, npcs, items, props) it had also been mentioned here several times or so if I remember correctly. However, most of the games that use this method somehow could dynamically LIT their terrain/game maps/level with almost no limit of light sources. How would I do this for my game? I don't wanna go back to lightmapping since I'm concerned about storage and, I'd rather have my torches light up my world brilliantly.

 

NB: all the game I've seen showed like ~32 number of lights. But I'm not sure if it's "hardcoded" to their engine. (I can't imagine looping thru 32 light properties in the shader just to compute 1 pixel's color)

Share this post


Link to post
Share on other sites
Bow_vernon    323

 

However, most of the games that use this method somehow could dynamically LIT their terrain/game maps/level with almost no limit of light sources. How would I do this for my game?

Draw with 4 lights (or however many you want and can fit with the registers available in your shader) and then draw 4 more lights with additive blending (and no ambience).


L. Spiro

 

+1

Oh, dangit. Why didn't I think about it earlier? basically it's similar to those multipass forward light with additive blending right? Yeah, I could see where I'm going now. Thanks L. Spiro.

 

Well I'd still need some advice though. I planned to calculate those extra pass by setting alpha to 0.0f where the light has no effect. then I blend them in with alpha testing enabled (or maybe I could just discard those pixel, but I heard it's non-conformant). Is it a "good" approach? I think I could see good performance, although I'm not sure

Share this post


Link to post
Share on other sites
jmakitalo    668

How is your game map different from a collection of objects? Is it a terrain or some unstructured mesh? Anyway, why not split the map into smaller pieces. Then determine the four most important lights for each pice. Do you anticipate that there will be more than four lights that significantly influence small portions of the map?

Share this post


Link to post
Share on other sites
tonemgub    2008

I can't imagine looping thru 32 light properties in the shader just to compute 1 pixel's color

 

I always thought that's exactly how it's done. Wouldn't that be better performance-wise than doing multiple passes and blending them together? Even deferred rendering sends all possible light source in a single pass.

 

I think L. Spiro only proposed the blending method because for some reason you're limiting yourself to 4 lights per pass?

Edited by tonemgub

Share this post


Link to post
Share on other sites
Bow_vernon    323

How is your game map different from a collection of objects? Is it a terrain or some unstructured mesh? Anyway, why not split the map into smaller pieces. Then determine the four most important lights for each pice. Do you anticipate that there will be more than four lights that significantly influence small portions of the map?


It's a 3d tile map basically. I divided em into a quadtree structure. Then for every light they would query which node will be influenced. Thus if there's a lots of light concentrated in a node, it would get more than 4. I just cant limit it to 4 lights. It breaks realism

I can't imagine looping thru 32 light properties in the shader just to compute 1 pixel's color

 
I always thought that's exactly how it's done. Wouldn't that be better performance-wise than doing multiple passes and blending them together? Even deferred rendering sends all possible light source in a single pass.
 
I think L. Spiro only proposed the blending method because for some reason you're limiting yourself to 4 lights per pass?
Hmm I thought looping too many times in a fragment shader would slow down itself considerably. Thus the 4 lights. Plus Id save uniforms for use with another fancy effects

Another interesting approach used by UE3 was to composite all lights CPU-side into a set of spherical harmonics coefficients, then send these to the GPU for shading. This is an awesome tradeoff for mobile where the extra detail afforded by calculating things like falloff per-pixel are harder to see and the performance benefits are huge-- lighting time is completely independent of the number of lights influencing the object!

Hey Ive been thinking about it too. If only I could store light properties in a texture and read em back in the fragment shader, that'd be great. But I dunno if that's possible. Although it would require many sampling tho.

Share this post


Link to post
Share on other sites
Eklipse    294

If a lot of your lights are not changing every frame you can bake or cache those lights sources. So do multiple passes if need be render them but render the lighting to a lighting buffer and just sample from it while the lights are constant. You could mix this on a per object level too. Maybe characters are always real time while the level is baked.

You should be able to also accumulate this light buffer into the final results similar to the multipass additive lighting.

 

So it would be a simpler version light maps that can be updated dynamically. You should be able to as well change out the order so at this point x-y-z are baked and w is dynamic then some other point xyw are baked and z is dynamic.

 

You will just have to experiment with what gives the best performance. A lot will depend on your platform target and what it can handle memory and rendering performance.

 

I'm guessing these are probably going to be simple lights and not fully shadowed point lights.

Share this post


Link to post
Share on other sites
tonemgub    2008

You are over-complicating things. Really though, are you sure you can't just send all lights at once? If you have other effects, just split those over additional passes.

 

I don't know if looping in the shader with all of the lights at once is slower than looping over them on the CPU. But if you are dealing with lower-end hardware, the only way to make it work properly would be to use lightmaps, and update them only when needed (i.e., when a light moves), perhaps even separating them into static and dynamic lightmaps.

 

You can't optimize for both storage AND performance. You have to decide which is more important for you. I think storage is slowly becoming less of an issue with every new model of graphics cards though, so I would go with the lightmaps if I were you.

 

 

 


If only I could store light properties in a texture and read em back in the fragment shader, that'd be great.

Wouldn't this be the same as a lightmap (or more like deferred shading)?

Edited by tonemgub

Share this post


Link to post
Share on other sites
L. Spiro    25638

Really though, are you sure you can't just send all lights at once?

Just to expand on this question, if the original poster is believing he or she has not enough uniforms etc., this is likely because he or she are using an overly complex lighting model designed after the fixed-function pipeline.
The fixed-function pipeline has a lot of parameters that are generally not useful just because it was fixed-function. Back then that was the only way to make all artists (somewhat) happy, and also a time when accurate lighting wasn’t a thing.

For a point light, you only need a color, position, and range. This means 2 vectors: [Cr, Cg, Cb, Range], [Px, Py, Pz, 1].  You don’t need specular color (it should always be the same as the regular color), ambient color (a nonsensical value), and 3 attenuation values.

 

 

Similar madness can be avoided by not following the example of the fixed-function pipeline for directional lights and spotlights, allowing you to easily double or triple the number of lights you can have with the same number of uniforms.

 

 

L. Spiro

Edited by L. Spiro

Share this post


Link to post
Share on other sites
Krohm    5031


NB: all the game I've seen showed like ~32 number of lights. But I'm not sure if it's "hardcoded" to their engine. (I can't imagine looping thru 32 light properties in the shader just to compute 1 pixel's color)
Well, I did that as an experiment years ago on a GeForce 6600 GT, 128bit GDDR3. It did work (with quite fine parallax occlusion mapping) albeit not smooth enough to be used in production.

 

I would expect modern mobile to match that performance level at least on some silicon but since a lot of devices have hi-dpi screens I cannot really promise anything.

 

If you are sure you always have a high light count, consider deferred.

 

TL;DR: it is possible and sometimes viable to iterate them. Whatever it is in your case it's another matter. 

 

 

 


If only I could store light properties in a texture and read em back in the fragment shader, that'd be great.

Wouldn't this be the same as a lightmap (or more like deferred shading)?

 

Absolutely not. Deferred is (sort of) splatting your lights on the (not quite) "finished" scene.

What he plans to do here is to use texture as an array (as a side note, this is what I did years ago).

It is doable... but be careful with instruction counts. Your shader might get killed after a while. This will be probably both hardware and driver-dependent. Proceed with caution!

Share this post


Link to post
Share on other sites
tonemgub    2008


What he plans to do here is to use texture as an array (as a side note, this is what I did years ago).

Oh, I think I understand now. Passing the lights into a texture only to get around the uniforms limitation.

I didn't think of that first. I thought he was talking about storing those Unity 3 harmonics coefficients in that texture. I worngly imagined those being used as a sort of g-buffer. I don't suppose Unity's shaders are open source though, anyway.

Share this post


Link to post
Share on other sites
JohnnyCode    1046

You really do not have to be dependant on the pixel function registers limit. Simply do not interpolate light vectors, but feed the lights as uniforms to the pixel function, and interpolate only data necessary for the computation that stays constant for all the lights (normal, object space position). Redesign shaders if neccesary, then the limit of lights will be lifted much higher. Yet! you should never shade more than about 32 lights, apply culling and combining upon player observation of course.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this