Most Efficient Way for Lighting in Forward Rendering

Started by
12 comments, last by 21st Century Moose 9 years, 10 months ago

@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.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Advertisement

@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();
    }

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?

return tex2D(ColorMap, IN.UV) + Light1();

Typically you'd use * not +.

I'm not sure why you're using +; that would be expected to make things excessively bright for sure. Think about it: if a light value is 0 that means it's fully dark so you want to return black (0); on the other hand if it's 1 that means it's fully bright so you return the texture colour; it should be clear that you use:

return tex2D(ColorMap, IN.UV) * Light1();

And not:

return tex2D(ColorMap, IN.UV) + Light1();

If you go back to my earlier post where I derive the additive blending method from basic mathematics you'll see that it's correct to also read the texture for every pass, because t * (l0 + l1 + l2 + l3) == (t * l0) + (t * l1) + (t * l2) + (t * l3). This is the same as 2 * (1 + 3) == (2 * 1) + (2 * 3).

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

This topic is closed to new replies.

Advertisement