Lighting and Shaders

Started by
4 comments, last by MJP 16 years ago
So i've been learning about calculating how an object is lit based on its material properties and different kind of lights, using the programmable pipeling. So in the effect file i have externs for the light position and direction (depending on if we are using a point, spot or ambient light), that are use in the calculations. Which i understand when we are talking about one light, but how does this work when we are talking about many light? What about if i don't know how many lights will be effecting the vertex? Enlighten me please.
Advertisement
Multiple lights are handled by determining the contribution from each light source (which is done by evaluating the standard diffuse and specular components) and then summing those contributions together. This summing can happen in one of two places: in your shader, or in the ROPs when the shader output is blended with the current contents of the render target.

The first method is typically known as "single-pass" lighting. It's named as such because it allows you to render an object that is being lit by multiple light sources in one pass. Doing this requires that you send the parameters for all of the light source to your shader, and your shader evaluates the lighting term for each then sums the contributions. To handle different numbers of lights, there's two main approaches: create a technique for each number of light sources (perhaps 1-4), or use dynamic branching. The first way is pretty easy if you simply use a for loop in your shader, and in your technique definition you set the upper bound on that for loop. Dynamic branching is trickier and is limited to shader model 3.0 hardware. DB also requires coherent branching for good performance, which means if the size of the light contributions are small on screen you'll have problems.

The second method is typically known as "multi-pass" lighting. With this, you render each object once per light source and set the device to use additive blending on the output. This causes what you render to be automatically added to the contents of the back-buffer, effectively summing your light contributions. It's main advantages are that it's very easy to implement, it can be done in shader profiles with low instruction limits, and doesn't require you to be a hard limit on the number of lights that can affect a single object. However it can obviously be slow, since you have to render objects multiple times.
Thanks for the reply.

Quote:Original post by MJPThis summing can happen in one of two places: in your shader, or in the ROPs when the shader output is blended with the current contents of the render target.


Forgive me i'm very new to shaders, what do you mean by ROPs?

Quote:Original post by MJPDoing this requires that you send the parameters for all of the light source to your shader, and your shader evaluates the lighting term for each then sums the contributions.


Does this mean i need so send info to my shader from every light in my game?

Quote:Original post by MJPHowever it can obviously be slow, since you have to render objects multiple times.


So perhaps for Demo perposes it might be ok to use 'Multi-pass' as i won't be using loads of lights (maybe one Directional and one Spot)?

Quote:Original post by JimmyDeemo
Forgive me i'm very new to shaders, what do you mean by ROPs?


ROP's are "Render Output Units". They are essentially the final part of the pixel pipeline, where the pixel data is output into GPU memory. They're not programmable, but you can tell them to do certain blending functions. So what I was talking about was using additive blending, which means the ROP will take the color value that the pixel shader came up with, then look at the value of the pixel already in the back-buffer, then add them together and output it to memory.

Quote:Original post by JimmyDeemo
Does this mean i need so send info to my shader from every light in my game?


Well not every light source, just the all of the light sources that affect the object you're drawing. Obviously global light sources such as the sun will affect all objects, but for local spotlights and point lights you can use bounding spheres (or some other method) to determine whether the light will affect any particular object.

Quote:Original post by JimmyDeemo
So perhaps for Demo perposes it might be ok to use 'Multi-pass' as i won't be using loads of lights (maybe one Directional and one Spot)?


Oh yeah for two light sources it's fine, and will be easy for you to get it up and running. It really starts to matter more when you have a ton of geometry on screen and lots of light sources.

Ok good, thats given me a better idea of things. I understand now that you would create a bounding cone for spots for example, the length of which i guess would be dependent on the attenuation.

So for multi-pass i would i use the 'Passes' as i understand them in the Effect sense of the word like this;

	//Begin passes	UINT numPasses = 0;	HR( m_FX->Begin(&numPasses, 0) );	for(UINT i = 0; i < numPasses; ++i)	{		HR( m_FX->BeginPass(i) );		drawGrid();		drawCylinders();		drawSpheres();		HR( m_FX->EndPass() );	}	HR( m_FX->End() );


Or would i just call render on each object after each light details has been set in my effect file?
You could do it with the passes in the effect file, but it's not really necessary. It's probably better to just leave your fx file as is and do everything in your app code.

This topic is closed to new replies.

Advertisement