So I have decided I need a forward rendering solution, and will defer deferred shading for another time. So the issue of course is how to deal with multiple lights of varying types. I have come across 3 methods, but am having trouble choosing between them.
BTW I am working in DX9, HLSL, Shader 3 (but want to avoid dynamic branching)
Method 1:
ATI's fixed function emulation style. Keep 1 list of all lights (point, spot, dir clumped into the same list). Have a start index (into the light list) per light type and the number of lights of that type. Then have a separate loop for each light type accumulating the lighting.
struct CLight{ int iType; float3 vPos; float3 vDir; float4 vAmbient; float4 vDiffuse; float4 vSpecular; float fRange; float3 vAttenuation; //1, D, D^2; float3 vSpot; //cos(theta/2), cos(phi/2), falloff};CLight lights[MAX_LIGHTS];int iLightDirIni;int iLightDirNum;int iLightPointIni;int iLightPointNum;int iLightSpotIni;int iLightSpotNum;...//directional lightsfor(int i = 0; i < iLightDirNum; i++){ COLOR_PAIR ColOut = DoDirLight(N, V, i+iLightDirIni); Out.Color += ColOut.Color; Out.ColorSpec += ColOut.ColorSpec;}//point lightsfor(int i = 0; i < iLightPointNum; i++){ COLOR_PAIR ColOut = DoPointLight(vPosition, N, V,i+iLightPointIni); Out.Color += ColOut.Color; Out.ColorSpec += ColOut.ColorSpec;}//spot lightsfor(int i = 0; i < iLightSpotNum; i++){ COLOR_PAIR ColOut = DoSpotLight(vPosition, N, V,i+iLightSpotIni); Out.Color += ColOut.Color; Out.ColorSpec += ColOut.ColorSpec;}
I am assuming this would only result in static branching.
Method 2:
Use the effects framework to auto-generate variants of the shader, by passing in different values (e.g. number of lights) to the shader function in different techniques. Like so http://mynameismjp.wordpress.com/2009/01/19/teach-your-effects-a-new-trick/. Not sure how to deal with light type variants though.
Method 3:
Multiple blended passes.
So my questions are: What is the detriment to method 1? Concerning method 1, I hear one should avoid static branching since the compiler cant optimize as well, is that true for this case? Wouldn't method 2 result in alot of switching between shaders that method 1 would avoid? Wouldn't method 3 result in alot of redundant geometry transforms (especially for skinned meshes), does this matter?
I know the answer to most of these question is "it depends". But i just wanted to query what people think in general. I wouldn't be dealing with many lights at a time, probably max of 6.