• Advertisement
Sign in to follow this  

Multiple Lights [HLSL][Direct3D9]

This topic is 3227 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey, I'm trying to create a system where I can render numerous lights at the same time, as well as lights of different types (directional, point and spot lights). I've read numerous ways, but are unable to implement, the only one that I was able to was using multiple render targets, then merging all the images created from every light into a single frame, I didn't like this as it is very slow to use multiple render targets, video memory intensive and not all hardware supports it. Ok, so I'll keep it simple for now, and say, how would I render the following scenario? 1 directional light - sun 1 point light - lamp

Share this post


Link to post
Share on other sites
Advertisement
Hi,

There're different techniques you can use:

1 - Declare seperate light parameters in your shader, compute light illumination for each of'em (c1 for directional and c2 for point). Then just add c1 to c2.

2 - Use a full-screen quad render target texture. Using both SrcBlend and DestBlend as "One" and BlendOp as "add", you can render each light illumination to this texture (and this will be automatically summed with previous lighting result).

3 - Use deferred shading. This will be the best for all types of light; also serves better performance for numerous lights.

I recommend 3. 1 and 2 "eats" the performance because of rendering each model "num_of_lights" times and this is not good.

You can find a lot of document for Deferred Shading.

Hope this helps.

Share this post


Link to post
Share on other sites
I'm curious about your second method, could you explain this in a little more depth?
I've heard there's a few issues with deffered shadding including the inability to easily implement transparency.

Share this post


Link to post
Share on other sites
I recommend technique 2. But it can be done easier. You don't need to render to a separate texture. Just use the existing backbuffer.
You could do it like this:
1. Render a depthpass (z-test and z-writen enabled), including ambient lighting if you want to.
2. Enable alpha-blending as programci_84 suggests and disable z-writes.
3. Render the scene for each light
4. Finished


Deferred shading has benefits, but in my experience you need quite complex scenes with a lot of lights to really make it worthwhile. For the scenario you describe I would suggest to start with the easier method. It probably will render faster, too.

Share this post


Link to post
Share on other sites
Hi,

Quote:
I'm curious about your second method, could you explain this in a little more depth?


Of course.

* Create a texture same size as back-buffer:

D3DXCreateTexture (...);


* Assign this texture's level0 surface as device's render target #0:
LPDIRECT3DSURFACE9 pSurf, pSurfBackup;
RTTex->GetSurfaceLevel (0, &pSurf);
pD3DDevice->GetRenderTarget (0, &pSurfBackup);
pD3DDevice->SetRenderTarget (0, pSurf);


* Begin the scene, render for each light

pD3DDevice->SetRenderState (D3DRS_ALPHABLENDENABLE, TRUE);
pD3DDevice->SetRenderState (D3DRS_SRCBLEND, D3DBLEND_ONE);
pD3DDevice->SetRenderState (D3DRS_DESTBLEND, D3DBLEND_ONE);
pD3DDevice->BeginScene();
//maybe you want to clear
For each light
{
add light contribution via your shader;
drawObjects;
}
pD3DDevice->EndScene();
pD3DDevice->SetRenderState (D3DRS_ALPHABLENDENABLE, FALSE);


* Restore the original backbuffer

pD3DDevice->SetRenderTarget (0, pSurfBackup)


B_old says: "you don't need to render to a separate texture"
In this way, you can just render light pass. But if you want to add some post effects (HDR, motion blur, DoF etc.), you have to render to a seperate texture ;)

Hope this helps.

Regards,
Rohat.

Share this post


Link to post
Share on other sites
Great thanks heaps for the help!! I think I'll go with the second option, as B_old said, there benefits are only worthwhile if you have a number of complex lights.

thanks =]

Share this post


Link to post
Share on other sites
Just one more question, do I need to transform the scene in the vertex shader for every pass? it seems very expensive.

Share this post


Link to post
Share on other sites
Re-rendering each object per light affecting it is the simplest approach. Light accumulation is additive, and provided the frame buffer is in a linear color space, it will just work.


Pros:
- only need to implement 4 light shaders per material type at first (global/ambient, point, spot, directional), then 3 more if you need to handle shadows

Cons :
- z fighting issues can come up since the vertex shaders will occasionally not be perfectly exact between each pass.
- overdraw can rapidly get bad and will be view dependant
- terrain needs to be thought out so you don't render too much of it for small spot and point lights


If you have a common configuration of lights in a scene its worth making a shader that does that (say ambient and a directional light). Another set of shaders to handle common cases like 1/2/3/4 point lights all at once can help perf quite a bit as well.

Its possible to write a single shader that does all 3 (point/spot/directional) with static branching, but they will not perform as well as specialized shaders/


A deferred rendering approach has a huge up front cost but they payoff is more stability and predictability in the performance with lights. Translucent stuff basically has to fall back to the traditional forward rendering approach.

Share this post


Link to post
Share on other sites
Quote:
Original post by leet bix
Just one more question, do I need to transform the scene in the vertex shader for every pass? it seems very expensive.


Probably, and unless its doing something complex like rendering a 100,000 poly skeletal mesh with 4 bone influences per vertex I wouldn't worry about it a whole lot. You should always try to put as much math into the vertex shader as possible, so that the pixel shader doesn't have to. Now the real trick is doing that and also using as few interpolators as possible :)

Share this post


Link to post
Share on other sites
Alright, one more question. So I have say 3 different effects, Directional light, point light and spot light, should I have 3 different effect files, or 3 different techniques within a single effect file?

Share this post


Link to post
Share on other sites
Personally I use 3 different techniques in one effect file. And then I have different effect files. For example one for normal mapping, another one for normal/parallax mapping and so on. In my opinion it makes it easier to structure.

Share this post


Link to post
Share on other sites
Hi,

Quote:
So I have say 3 different effects, Directional light, point light and spot light, should I have 3 different effect files, or 3 different techniques within a single effect file?


Whatever you want :)
* You can write a .fxh file and declare your shader variables/data types in it, then write seperate .fx files (for each light equation/type) that use this .fxh file with #include lines.

* Or, you can write a single .fx file, seperate shaders (for each light equation/type) and seperate techniques in it (maybe one technique, seperate "passes").

* Or, you can write a single .fx file, single technique and single shader in it. How can you manage your code with light type? You can use "if" statemens:

...
if (light_type == LIGHT_DIR)
{
...
}

if (light_type == LIGHT_SPOT)
{
...
}

if (light_type == LIGHT_POINT)
{
...
}


Hope this helps.

Share this post


Link to post
Share on other sites
I was thinking more along the lines of what is fastest, it's cheaper to change techniques rather than effects isn't it?

Share this post


Link to post
Share on other sites
I would suppose you are right. That's what I think at least, as you still can use all the constants you uploaded.

Share this post


Link to post
Share on other sites
That's what I was thinking, also, you may have the same vertex shader for all of them and you just compile that in each of the techniques, then, things like the matrices only need to be passed in regardless of how many lights or differnet types of lights are being used.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement