Browse Source

More fixes to light pre-pass light volume rendering.

Lasse Öörni 14 years ago
parent
commit
7e3be41dfb

+ 5 - 7
Engine/Graphics/Batch.cpp

@@ -518,7 +518,6 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
             
             if (graphics->NeedParameterUpdate(PSP_SHADOWSPLITS, light))
             {
-                /// \todo Handle SM2 light pre-pass case, which draws one cascade per pass
                 Vector4 lightSplits(M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE, M_LARGE_VALUE);
                 if (lightQueue_->shadowSplits_.Size() > 1)
                     lightSplits.x_ = lightQueue_->shadowSplits_[0].farSplit_ / camera_->GetFarClip();
@@ -532,7 +531,6 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
             
             if (graphics->NeedParameterUpdate(PSP_SHADOWPROJ, light))
             {
-                /// \todo Handle SM2 light pre-pass case, which draws one cascade per pass
                 LightType type = light->GetLightType();
                 
                 if (type == LIGHT_DIRECTIONAL)
@@ -540,7 +538,7 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
                     Matrix4 shadowMatrices[MAX_CASCADE_SPLITS];
                     unsigned numSplits = lightQueue_->shadowSplits_.Size();
                     for (unsigned i = 0; i < numSplits; ++i)
-                        CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, graphics, renderer, -camera_->GetWorldPosition());
+                        CalculateShadowMatrix(shadowMatrices[i], lightQueue_, i, graphics, renderer, camera_->GetWorldPosition());
                     
                     graphics->SetShaderParameter(PSP_SHADOWPROJ, shadowMatrices[0].GetData(), 16 * numSplits);
                 }
@@ -548,17 +546,17 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
                 {
                     Matrix4 shadowMatrices[2];
                    
-                    CalculateSpotMatrix(shadowMatrices[0], light, -camera_->GetWorldPosition());
+                    CalculateSpotMatrix(shadowMatrices[0], light, camera_->GetWorldPosition());
                     bool isShadowed = lightQueue_->shadowMap_ != 0;
                     if (isShadowed)
-                        CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, graphics, renderer, -camera_->GetWorldPosition());
+                        CalculateShadowMatrix(shadowMatrices[1], lightQueue_, 0, graphics, renderer, camera_->GetWorldPosition());
                     
                     graphics->SetShaderParameter(PSP_SHADOWPROJ, shadowMatrices[0].GetData(), isShadowed ? 32 : 16);
                 }
                 if (type == LIGHT_POINT)
                 {
-                    Matrix3x4 lightVecRot(Vector3::ZERO, light->GetWorldRotation(), Vector3::ONE);
-                    graphics->SetShaderParameter(VSP_LIGHTVECROT, lightVecRot.GetData(), 12);
+                    Matrix4 lightVecRot(light->GetWorldRotation().RotationMatrix());
+                    graphics->SetShaderParameter(VSP_LIGHTVECROT, lightVecRot.GetData(), 16);
                 }
             }
         }

+ 1 - 1
Engine/Graphics/Light.cpp

@@ -386,7 +386,7 @@ const Matrix3x4& Light::GetVolumeTransform(const Camera& camera)
     switch (lightType_)
     {
     case LIGHT_DIRECTIONAL:
-        volumeTransform_ = GetDirLightTransform(camera, true);
+        volumeTransform_ = GetDirLightTransform(camera);
         break;
         
     case LIGHT_SPOT:

+ 4 - 2
Engine/Graphics/View.cpp

@@ -630,7 +630,6 @@ void View::GetBatches()
                 // In light pre-pass mode, store the light volume batch now
                 if (prepass)
                 {
-                    /// \todo Handle SM2 multiple batches for shadowed directional lights
                     Batch volumeBatch;
                     volumeBatch.geometry_ = renderer_->GetLightGeometry(light);
                     volumeBatch.worldTransform_ = &light->GetVolumeTransform(*camera_);
@@ -1438,6 +1437,9 @@ IntRect View::GetShadowMapViewport(Light* light, unsigned splitIndex, Texture2D*
     unsigned width = shadowMap->GetWidth();
     unsigned height = shadowMap->GetHeight();
     int maxCascades = renderer_->GetMaxShadowCascades();
+    // Due to instruction count limits, light prepass in SM2.0 can only support up to 3 cascades
+    if (renderer_->GetLightPrepass() && !graphics_->GetSM3Support())
+        maxCascades = Max(maxCascades, 3);
     
     switch (light->GetLightType())
     {
@@ -2045,7 +2047,7 @@ void View::SetupLightBatch(Batch& batch)
     else
     {
         graphics_->SetCullMode(CULL_NONE);
-        graphics_->SetDepthTest(CMP_ALWAYS);
+        graphics_->SetDepthTest(CMP_GREATER);
     }
     
     /// \todo Set stencil test to check for light masks

+ 6 - 18
SourceAssets/HLSLShaders/LightVolume.hlsl

@@ -118,21 +118,11 @@ void PS(
 
     #ifdef SHADOW
         #if defined(DIRLIGHT)
-            #ifdef SM3
-                float4x4 shadowMatrix = GetDirShadowMatrix(depth);
-                float4 shadowPos = mul(float4(worldPos, 1.0), shadowMatrix);
-            #else
-                // PS2.0 runs out of instructions while choosing cascade per pixel. Render cascade per pass instead
-                float4x4 shadowMatrix = float4x4(cShadowProjPS[0], cShadowProjPS[1], cShadowProjPS[2], cShadowProjPS[3]);
-                float4 shadowPos = mul(float4(worldPos, 1.0), shadowMatrix);
-                // No light outside cascade limits
-                if (depth < cShadowSplits.x || depth >= cShadowSplits.y)
-                    diff = 0.0;
-            #endif
+            float4x4 shadowMatrix = GetDirShadowMatrix(depth);
+            float4 shadowPos = mul(float4(worldPos, 1.0), shadowMatrix);
             diff *= saturate(GetShadow(shadowPos) + GetShadowFade(depth));
         #elif defined(SPOTLIGHT)
-            float4x4 shadowMatrix = float4x4(cShadowProjPS[4], cShadowProjPS[5], cShadowProjPS[6], cShadowProjPS[7]);
-            float4 shadowPos = mul(float4(worldPos, 1.0), shadowMatrix);
+            float4 shadowPos = mul(float4(worldPos, 1.0), cShadowProjPS[1]);
             diff *= GetShadow(shadowPos);
         #else
             float3 shadowPos = worldPos - cLightPosPS.xyz;
@@ -141,20 +131,18 @@ void PS(
     #endif
 
     #ifdef SPOTLIGHT
-        float4x4 spotMatrix = float4x4(cShadowProjPS[0], cShadowProjPS[1], cShadowProjPS[2], cShadowProjPS[3]);
-        float4 spotPos = mul(float4(worldPos, 1.0), spotMatrix);
+        float4 spotPos = mul(float4(worldPos, 1.0), cShadowProjPS[0]);
         lightColor = spotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : 0.0;
     #else
         #ifdef CUBEMASK
-            float3x3 lightVecRot = float3x3(cShadowProjPS[0].xyz, cShadowProjPS[1].xyz, cShadowProjPS[2].xyz);
-            lightColor = texCUBE(sLightCubeMap, mul(lightVec, lightVecRot)).rgb * cLightColor.rgb;
+            lightColor = texCUBE(sLightCubeMap, mul(lightVec, (float3x3)cShadowProjPS[0])).rgb * cLightColor.rgb;
         #else
             lightColor = cLightColor.rgb;
         #endif
     #endif
 
     #ifdef SPECULAR
-        float spec = lightColor.g * GetSpecular(normal, worldPos, lightDir, normalInput.a * 255.0);
+        float spec = lightColor.g * GetSpecular(normal, -worldPos, lightDir, normalInput.a * 255.0);
         oColor = diff * float4(lightColor, spec * cLightColor.a);
     #else
         oColor = diff * float4(lightColor, 0.0);

+ 22 - 13
SourceAssets/HLSLShaders/Lighting.hlsl

@@ -155,21 +155,30 @@ float4 GetDirShadowPos(const float4 iShadowPos[4], float depth)
         return iShadowPos[2];
     else
         return iShadowPos[3];
-}   
+}
 
 float4x4 GetDirShadowMatrix(float depth)
 {
-    float4x4 shadowMatrix;
-
-    if (depth < cShadowSplits.x)
-        shadowMatrix = float4x4(cShadowProjPS[0], cShadowProjPS[1], cShadowProjPS[2], cShadowProjPS[3]);
-    else if (depth < cShadowSplits.y)
-        shadowMatrix = float4x4(cShadowProjPS[4], cShadowProjPS[5], cShadowProjPS[6], cShadowProjPS[7]);
-    else if (depth < cShadowSplits.z)
-        shadowMatrix = float4x4(cShadowProjPS[8], cShadowProjPS[9], cShadowProjPS[10], cShadowProjPS[11]);
-    else
-        shadowMatrix = float4x4(cShadowProjPS[12], cShadowProjPS[13], cShadowProjPS[14], cShadowProjPS[15]);
-
-    return shadowMatrix;
+    #ifdef SM3
+        if (depth < cShadowSplits.x)
+            return cShadowProjPS[0];
+        else if (depth < cShadowSplits.y)
+            return cShadowProjPS[1];
+        else if (depth < cShadowSplits.z)
+            return cShadowProjPS[2];
+        else
+            return cShadowProjPS[3];
+    #else
+        if (depth < cShadowSplits.x)
+            return cShadowProjPS[0];
+        else if (depth < cShadowSplits.y)
+            return cShadowProjPS[1];
+        else
+            return cShadowProjPS[2];
+    #endif
 }
 
+float GetIntensity(float3 color)
+{
+    return dot(color, float3(0.333, 0.333, 0.333));
+}

+ 1 - 1
SourceAssets/HLSLShaders/Material.hlsl

@@ -73,7 +73,7 @@ void PS(float4 iTexCoord : TEXCOORD0,
 
     // Lights are accumulated at half intensity. Bring back to full intensity now
     float4 lightInput = 2.0 * tex2Dproj(sLightBuffer, iScreenPos);
-    float3 lightSpecColor = lightInput.a * lightInput.rgb;
+    float3 lightSpecColor = lightInput.a * (lightInput.rgb / GetIntensity(lightInput.rgb));
 
     float3 finalColor = (GetAmbient(iTexCoord.z) + iVertexLighting + lightInput.rgb) * diffColor + lightSpecColor * specIntensity;
     oColor = float4(GetFog(finalColor, iTexCoord.w), 1.0);

+ 1 - 1
SourceAssets/HLSLShaders/Uniforms.hlsl

@@ -36,4 +36,4 @@ uniform float4 cShadowCubeAdjust : register(C12);
 uniform float4 cShadowDepthFade : register(C13);
 uniform float4 cShadowIntensity : register(C14);
 uniform float4 cShadowSplits : register(C15);
-uniform float4 cShadowProjPS[16] :  register(C16);
+uniform float4x4 cShadowProjPS[4] :  register(C16);