• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Medo Mex

Most Efficient Way for Lighting in Forward Rendering

13 posts in this topic

I'm currently using Forward Lighting and trying to do my best to make sure that the FPS game will always render all the lights

 

1. In Pixel Shader 2.0, I have

DirectionalLight dirLights[maxLights];
PointLight pointLights[maxLights];
SpotLight spotLights[maxLights];

What is the appropriate number for the variable maxLights?

 

2. Since Forward Lighting is limited to a certain amount of lights, I have been thinking that I could:

- Detect collision between the light and the camera bounding frustum and only render the light if the camera can see it

- Arrange the lights from closest to farthest to the camera and remove any light if it's index is over 'maxLights' variable

 

What do you think about my idea? What is the most efficient way to work with forward lighting?

Edited by Medo3337
1

Share this post


Link to post
Share on other sites


What is the appropriate number for the variable maxLights?

That all depends on the scene you are rendering.  If you have a total of 4 lights in your scene, then of course it makes no sense to all for 8 of them in your shader.  I would recommend to take the advice that cozzie provided, and just have one combination for each number of lights so you can choose the appropriate one when you need to.

0

Share this post


Link to post
Share on other sites

@mhagain: Should I handle only one light per pass or more than one light?

 

Maybe I could set the maxLights to 4 and If the lights on a mesh exceed 4 lights, I can render it multiple times.

 

Which is better?

Edited by Medo3337
0

Share this post


Link to post
Share on other sites

@mhagain: Should I handle only one light per pass or more than one light?

 

Maybe I could set the maxLights to 4 and If the lights on a mesh exceed 4 lights, I can render it multiple times.

 

What's your suggestion?

 

Profile and find out.

 

This is an "it depends" answer.  How many lights does a typical scene have?  Of those, how many lights do you typically have per object?  How many per pixel?  Does having a 4 light shader hurt in cases where an object has fewer than 4 lights on it?  And are those cases common enough that you need to care?  What's your target hardware?  How does it perform with multipass versus how does it perform with more complex shaders?  And don't forget how you're going to (or not going to) handle shadows.

 

In other words I can't make a suggestion here.

0

Share this post


Link to post
Share on other sites

@mhagain: I'm having a problem with blending diffuse color with light using multipass, here is the Shader:

 

(I'm getting white meshes)

// ....
PS_OUTPUT PS_Diffuse( VS_OUTPUT IN )
{
         // ...
         OUT.Color = tex2D(diffuseMap, IN.UV).rgb;
}

PS_OUTPUT PS_Lighting( VS_OUTPUT IN )
{
         OUT.Color = CalcLighting();
}

//-----------------------------------------------------------------------------
// Techniques.
//-----------------------------------------------------------------------------
technique Lighting
{
    // Diffuse pass
    pass Pass0
    {
        AlphaBlendEnable = TRUE;
        DestBlend = INVSRCALPHA;
        SrcBlend = SRCALPHA;
        ZEnable = TRUE;
        VertexShader = compile vs_3_0 VS();
        PixelShader = compile ps_3_0 PS_Diffuse();
    }


    // Lighting pass
    pass Pass1
    {
        AlphaBlendEnable = TRUE;
        DestBlend = ONE;
        SrcBlend = ONE;
        ZEnable = FALSE;
        VertexShader = compile vs_3_0 VS();
        PixelShader = compile ps_3_0 PS_Lighting();
    }
}
0

Share this post


Link to post
Share on other sites
If you want to use forward shading and lots of lights, you almost certainly want Forward+ shading (which a lot of AAA games are moving to).

The basic gist of the idea is to use a compute shader to bin all lights into the scene into a 2D grid indicating which parts of the screen they intersect with and then using the appropriate bin for all lighting calculating for a particular fragmnet. The binning is done by breaking the screen into a grid, generated a frustrum for each part of the grid, then doing an intersection test against each light volume and the frustrum for a particular grid location. If the light intersects, add it to that bin. More advanced versions of Forward+ deal with depth more intelligently.

It's a more advanced technique than either regular forward shading or deferred shading due to the use of compute shader, but it isn't that much more complex. It's all the same math you already have to do anyway (frustrum generation, intersection tests, etc.) just now it's in a computer shader instead of CPU code.
0

Share this post


Link to post
Share on other sites

 

@mhagain: I'm having a problem with blending diffuse color with light using multipass, here is the Shader:

 

(I'm getting white meshes)

 

I don't see what's happening in your CalcLighting function, but you almost certainly don't want what I think you have.

 

The first thing is that the first pass isn't a diffuse pass, it's an ambient pass.  This can be black (just output 0 from your PS) if you don't have any ambient light, but it's critically important to do it even if so as it's laying down a baseline for the additive passes.  Alpha blending should be disabled, enable depth writing, do a standard depth test.

 

The second and subsequent passes are your additive passes.  In order to understand how to do each of these, you first need to look at what a single pass/multiple light setup would look like:

 

output = ambient + diffuse * (light0 + light1 + light2 + light3); // assume 4 lights for the purpose of this example

 

Using some basic mathematics, let's break that into 5 passes, ambient plus 1 for each light, and we get:

 

output = ambient; // initial ambient pass - I've already covered this above

output += diffuse * light0; // first additive pass

output += diffuse * light1; // second additive pass

output += diffuse * light2; // third additive pass

output += diffuse * light3; // fourth additive pass

 

So each additive pass needs to sample the diffuse texture as well as calculate the lighting.  The additive blend adds it to the result from the previous pass(es), enable depth testing but set the depth test to equal, disable depth writing, and you'll get the (mostly) correct result.

 

I put in "mostly" above because the one caveat is that if your lighting goes above 1.0 each pass will clamp, so it's not going to look 100% identical to a single pass/multiple light setup.  You can of course draw to a floating point rendertarget if this is a problem for you, but I'd encourage experimentation before making that decision - it may be just fine as is.

 

If you want to use forward shading and lots of lights, you almost certainly want Forward+ shading (which a lot of AAA games are moving to).

The basic gist of the idea is to use a compute shader to bin all lights into the scene into a 2D grid indicating which parts of the screen they intersect with and then using the appropriate bin for all lighting calculating for a particular fragmnet. The binning is done by breaking the screen into a grid, generated a frustrum for each part of the grid, then doing an intersection test against each light volume and the frustrum for a particular grid location. If the light intersects, add it to that bin. More advanced versions of Forward+ deal with depth more intelligently.

It's a more advanced technique than either regular forward shading or deferred shading due to the use of compute shader, but it isn't that much more complex. It's all the same math you already have to do anyway (frustrum generation, intersection tests, etc.) just now it's in a computer shader instead of CPU code.

 

I suspect that the OP is using D3D9 (PS2.0 in the first post, SM3 in the effect file code).

Edited by mhagain
2

Share this post


Link to post
Share on other sites

@mhagain: It's now working well, however I see Z-Fighting in the animated character (only when the animation is playing)

 

I'm using D3D9, C++

0

Share this post


Link to post
Share on other sites

@mhagain: It's now working well, however I see Z-Fighting in the animated character (only when the animation is playing)

 

I'm using D3D9, C++

 

On some hardware you may see this if you use a different D3DPT_ in some of the passes.  I got hit by it once; thinking "If I'm only drawing 4 vertices I'll draw it as a strip or fan rather than an indexed triangle list, and save on some buffer locking".  Bad idea and Z-fighting was the result.

 

So draw everything as an indexed triangle list and it should be fine.

Edited by mhagain
0

Share this post


Link to post
Share on other sites

@mhagain: I'm rendering all the meshes using LPD3DXMESH, so I only use pMesh->DrawSubset() and I still have the Z-Fighting problem when animation is playing

 

Another problem, when I draw the mesh multiple times I get very bright mesh (even if there is no lighting)

 

Here is what I have in the Shader:

 

pass0 = ambient pass (render once)

pass1 = tex2D(ColorMap, IN.UV) + light (repeat rendering according to the number of lights)

    pass pass0
    {
         AlphaBlendEnable = FALSE;
         DestBlend = ONE;
         SrcBlend = ZERO;
         BLENDOP = ADD;
         ZEnable = TRUE;
         VertexShader = compile vs_3_0 VS();
         PixelShader  = compile ps_3_0 PS_AMBIENT();
    }


    pass pass1
    {
         AlphaBlendEnable = TRUE;
         SRCBLEND = ONE;
         DESTBLEND = ONE;
         BLENDOP = ADD;
         ZWRITEENABLE = TRUE;
         ZEnable = TRUE;
         VertexShader = compile vs_3_0 VS();
         PixelShader  = compile ps_3_0 PS();
    }
0

Share this post


Link to post
Share on other sites

I figured out that the Z-Fighting was due to the animation getting updated every time the mesh is rendered, so I changed the code to only update once every frame no matter how many times I do draw calls.

 

The problem now is that I the mesh is getting very bright when I render it multiple times as the following:

 

PS Pass 0: return Ambient;

PS Pass 1: return tex2D(ColorMap, IN.UV) + Light1();

PS Pass 1: return tex2D(ColorMap, IN.UV) + Light2();

PS Pass 1: return tex2D(ColorMap, IN.UV) + Light3();

 

I believe that it's getting very bright because tex2D(ColorMap, IN.UV) is added multiple times.

 

How do I fix it?

0

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  
Followers 0