Browse Source

lighting corrections:
1) fix spotlight shadow casting. we weren't properly accounting for reversedepthbuffer there
2) fix mismatched variables in forward lit spotlight param array
3) use disney diffuse in the generalized brdf, and apply it for spotlights after angular attenuation, not before
4) .provide a generailze luxTargMultiplier approach for spot and point lights (as well as future growth areas) so that range, angle ect can impact the brightness variable sent to a given light source shader without perpixel overhead
5) for spotlightParams in particular, use sizeof(point4f) for the alignedarray untill that's properly reviewed/revised
6) narrow attenuation slightly based on a given lights dot product to prevent tool vs outcome leakage, plus provide safeties for when a given spotslight's inner and outter angles match identially

AzaezelX 1 year ago
parent
commit
593d0ef9f0

+ 8 - 3
Engine/source/lighting/advanced/advancedLightBinManager.cpp

@@ -790,7 +790,7 @@ void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const Light
    MaterialParameters *matParams = matInstance->getMaterialParameters();
 
    matParams->setSafe( lightColor, lightInfo->getColor() );
-   matParams->setSafe(lightBrightness, lightInfo->getBrightness() * lightInfo->getFadeAmount());
+   F32 luxTargMultiplier = 1;
 
    switch( lightInfo->getType() )
    {
@@ -804,10 +804,10 @@ void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const Light
    case LightInfo::Spot:
       {
          const F32 outerCone = lightInfo->getOuterConeAngle();
-         const F32 innerCone = getMin(lightInfo->getInnerConeAngle(), outerCone);
+         const F32 innerCone = getMin(lightInfo->getInnerConeAngle(), outerCone-0.0001f);
          const F32 outerCos = mCos(mDegToRad(outerCone / 2.0f));
          const F32 innerCos = mCos(mDegToRad(innerCone / 2.0f));
-         Point2F spotParams(outerCos,innerCos - outerCos); 
+         Point2F spotParams(outerCos,mMax(innerCos - outerCos,0.001f));
 
          matParams->setSafe( lightSpotParams, spotParams );
          matParams->setSafe( lightDirection, lightInfo->getDirection());
@@ -817,6 +817,9 @@ void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const Light
          const F32 invSqrRadius = 1.0f / mSquared(radius);
          matParams->setSafe(lightRange, radius);
          matParams->setSafe(lightInvSqrRange, invSqrRadius);
+
+         F32 concentration = 360.0f/ outerCone;
+         luxTargMultiplier = radius * concentration;
       }
       break;
 
@@ -828,6 +831,7 @@ void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const Light
          const F32 invSqrRadius = 1.0f / (radius * radius);
          matParams->setSafe( lightRange, radius);
          matParams->setSafe( lightInvSqrRange, invSqrRadius);  
+         luxTargMultiplier =radius;
       }
       break;
 
@@ -835,6 +839,7 @@ void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const Light
       AssertFatal( false, "Bad light type!" );
       break;
    }
+   matParams->setSafe(lightBrightness, lightInfo->getBrightness()* lightInfo->getFadeAmount() * luxTargMultiplier);
 }
 
 bool LightMatInstance::setupPass( SceneRenderState *state, const SceneData &sgData )

+ 43 - 38
Engine/source/lighting/lightManager.cpp

@@ -333,7 +333,7 @@ void LightManager::_update4LightConsts(   const SceneData &sgData,
       static AlignedArray<Point4F> lightSpotDirs(MAX_FORWARD_LIGHTS, sizeof(Point4F));
       static AlignedArray<Point4F> lightColors(MAX_FORWARD_LIGHTS, sizeof(Point4F));
       static AlignedArray<Point4F> lightConfigData(MAX_FORWARD_LIGHTS, sizeof(Point4F)); //type, brightness, range, invSqrRange : rgba
-      static AlignedArray<Point2F> lightSpotParams(MAX_FORWARD_LIGHTS, sizeof(Point2F));
+      static AlignedArray<Point2F> lightSpotParams(MAX_FORWARD_LIGHTS, sizeof(Point4F));
 
       dMemset(lightPositions.getBuffer(), 0, lightPositions.getBufferSize());
       dMemset(lightSpotDirs.getBuffer(), 0, lightSpotDirs.getBufferSize());
@@ -352,11 +352,12 @@ void LightManager::_update4LightConsts(   const SceneData &sgData,
       vectorLightDirection = Point4F::Zero;
       vectorLightColor = Point4F::Zero;
       vectorLightAmbientColor = Point4F::Zero;
-
+      F32 luxTargMultiplier[MAX_FORWARD_LIGHTS];
       // Gather the data for the first 4 lights.
       const LightInfo* light;
       for (U32 i = 0; i < MAX_FORWARD_LIGHTS; i++)
       {
+         luxTargMultiplier[i] = 1.0;
          light = sgData.lights[i];
          if (!light)
             break;
@@ -371,48 +372,52 @@ void LightManager::_update4LightConsts(   const SceneData &sgData,
             vectorLightColor = Point4F(light->getColor());
             vectorLightAmbientColor = Point4F(light->getAmbient());
             hasVectorLight = 1;
-            continue;
-         }
-
-         // The light positions and spot directions are 
-         // in SoA order to make optimal use of the GPU.
-         const Point3F& lightPos = light->getPosition();
-         lightPositions[i].x = lightPos.x;
-         lightPositions[i].y = lightPos.y;
-         lightPositions[i].z = lightPos.z;
-         lightPositions[i].w = 0;
-
-         const VectorF& lightDir = light->getDirection();
-         lightSpotDirs[i].x = lightDir.x;
-         lightSpotDirs[i].y = lightDir.y;
-         lightSpotDirs[i].z = lightDir.z;
-         lightSpotDirs[i].w = 0;
-
-         lightColors[i] = Point4F(light->getColor());
-
-         if (light->getType() == LightInfo::Point)
-         {
-            lightConfigData[i].x = 0;
          }
-         else if (light->getType() == LightInfo::Spot)
+         else
          {
-            lightConfigData[i].x = 1;
+            // The light positions and spot directions are 
+            // in SoA order to make optimal use of the GPU.
+            const Point3F& lightPos = light->getPosition();
+            lightPositions[i].x = lightPos.x;
+            lightPositions[i].y = lightPos.y;
+            lightPositions[i].z = lightPos.z;
+            lightPositions[i].w = 0;
 
-            const F32 outerCone = light->getOuterConeAngle();
-            const F32 innerCone = getMin(light->getInnerConeAngle(), outerCone);
-            const F32 outerCos = mCos(mDegToRad(outerCone / 2.0f));
-            const F32 innerCos = mCos(mDegToRad(innerCone / 2.0f));
-            Point2F spotParams(outerCos, innerCos - outerCos);
+            lightColors[i] = Point4F(light->getColor());
 
-            lightSpotParams[i].x = spotParams.x;
-            lightSpotParams[i].y = spotParams.y;
-         }
+            F32 range = light->getRange().x;
+            lightConfigData[i].z = range;
 
-         lightConfigData[i].y = light->getBrightness();
+            if (light->getType() == LightInfo::Point)
+            {
+               lightConfigData[i].x = 0;
+               luxTargMultiplier[i] = range;
+            }
+            else if (light->getType() == LightInfo::Spot)
+            {
+               const VectorF& lightDir = light->getDirection();
+               lightSpotDirs[i].x = lightDir.x;
+               lightSpotDirs[i].y = lightDir.y;
+               lightSpotDirs[i].z = lightDir.z;
+               lightSpotDirs[i].w = 0;
+
+               lightConfigData[i].x = 1;
+
+               const F32 outerCone = light->getOuterConeAngle();
+               const F32 innerCone = getMin(light->getInnerConeAngle(), outerCone - 0.0001f);
+               const F32 outerCos = mCos(mDegToRad(outerCone / 2.0f));
+               const F32 innerCos = mCos(mDegToRad(innerCone / 2.0f));
+               Point2F spotParams(outerCos, mMax(innerCos - outerCos, 0.001f));
+
+               lightSpotParams[i].x = spotParams.x;
+               lightSpotParams[i].y = spotParams.y;
+               F32 concentration = 360.0f / outerCone;
+               luxTargMultiplier[i] = range * concentration;
+            }
 
-         F32 range = light->getRange().x;
-         lightConfigData[i].z = range;
-         lightConfigData[i].w = 1.0f / (range * range);
+            lightConfigData[i].y = light->getBrightness() * luxTargMultiplier[i];
+            lightConfigData[i].w = 1.0f / (range * range);
+         }
       }
 
       shaderConsts->setSafe(lightPositionSC, lightPositions);

+ 2 - 1
Engine/source/lighting/shadowMap/singleLightShadowMap.cpp

@@ -71,7 +71,8 @@ void SingleLightShadowMap::_render( RenderPassManager* renderPass,
    lightMatrix.inverse();
    GFX->setWorldMatrix(lightMatrix);
 
-   const MatrixF& lightProj = GFX->getProjectionMatrix();
+   MatrixF lightProj = GFX->getProjectionMatrix();
+   lightProj.reverseProjection();
    mWorldToLightProj = lightProj * lightMatrix;
 
    // Render the shadowmap!

+ 10 - 0
Templates/BaseGame/game/core/rendering/shaders/brdf.hlsl

@@ -73,4 +73,14 @@ float D_GGX(float NdotH, float alphaRoughnessSq)
 	return alphaRoughnessSq / (M_PI_F * f * f);
 }
 
+float3 Fr_DisneyDiffuse(float3 F0, float NdotV, float NdotL, float LdotH, float linearRoughness)
+{
+	float energyBias = lerp (0 , 0.5 , linearRoughness );
+	float energyFactor = lerp (1.0 , 1.0 / 1.51 , linearRoughness );
+	float fd90 = energyBias + 2.0 * LdotH * LdotH * linearRoughness ;
+	float3 lightScatter = F_Schlick( F0 , fd90 , NdotL );
+	float3 viewScatter = F_Schlick(F0 , fd90 , NdotV ); 
+
+	return lightScatter * viewScatter * energyFactor ;
+}
 #endif

+ 11 - 0
Templates/BaseGame/game/core/rendering/shaders/gl/brdf.glsl

@@ -67,4 +67,15 @@ float D_GGX(float NdotH, float alphaRoughnessSq)
 	return alphaRoughnessSq / (M_PI_F * f * f);
 }
 
+vec3 Fr_DisneyDiffuse(vec3 F0, float NdotV, float NdotL, float LdotH, float linearRoughness)
+{
+	float energyBias = lerp(0 , 0.5 , linearRoughness );
+	float energyFactor = lerp(1.0 , 1.0 / 1.51 , linearRoughness );
+	float fd90 = energyBias + 2.0 * LdotH * LdotH * linearRoughness ;
+	vec3 lightScatter = F_Schlick( F0 , fd90 , NdotL );
+	vec3 viewScatter = F_Schlick(F0 , fd90 , NdotV ); 
+
+	return lightScatter * viewScatter * energyFactor ;
+}
+
 #endif

+ 17 - 11
Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl

@@ -216,8 +216,8 @@ float getDistanceAtt( vec3 unormalizedLightVector , float invSqrAttRadius )
 
  float getSpotAngleAtt( vec3 normalizedLightVector , vec3 lightDir , vec2 lightSpotParams )
  {
-   float cd = dot ( lightDir , normalizedLightVector );
-   float attenuation = saturate ( ( cd - lightSpotParams.x ) / lightSpotParams.y );
+   float cd = max(dot( lightDir , normalizedLightVector ),0.0);
+   float attenuation = saturate ( ( cd - lightSpotParams.x/(cd*1.001) ) / lightSpotParams.y );
    // smooth the transition
    return sqr(attenuation);
 }
@@ -225,7 +225,7 @@ float getDistanceAtt( vec3 unormalizedLightVector , float invSqrAttRadius )
 vec3 evaluateStandardBRDF(Surface surface, SurfaceToLight surfaceToLight)
 {
    //lambert diffuse
-   vec3 Fd = surface.albedo.rgb * M_1OVER_PI_F;
+   vec3 Fd = Fr_DisneyDiffuse(surface.f0, surface.NdotV, surfaceToLight.NdotL, surfaceToLight.NdotH, surface.linearRoughness);
     
    //GGX specular
    vec3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
@@ -236,7 +236,7 @@ vec3 evaluateStandardBRDF(Surface surface, SurfaceToLight surfaceToLight)
 #if CAPTURING == 1
    return saturate(mix(Fd + Fr,surface.f0,surface.metalness));
 #else
-   return saturate(Fd + Fr);
+   return Fd + Fr;
 #endif
 
 }
@@ -254,6 +254,15 @@ vec3 getPunctualLight(Surface surface, SurfaceToLight surfaceToLight, vec3 light
    return evaluateStandardBRDF(surface,surfaceToLight) * factor;
 }
 
+vec3 getSpotlight(Surface surface, SurfaceToLight surfaceToLight, vec3 lightColor, float lightIntensity, float radius, vec3 lightDir, vec2 lightSpotParams, float shadow)
+{
+   float attenuation = 1.0f;
+   attenuation *= getDistanceAtt(surfaceToLight.Lu, radius);
+   attenuation *= getSpotAngleAtt(-surfaceToLight.L, lightDir, lightSpotParams.xy);
+   vec3 factor = lightColor * max(surfaceToLight.NdotL* shadow * lightIntensity * attenuation, 0.0f) ;
+   return evaluateStandardBRDF(surface,surfaceToLight) * factor;
+}
+
 float computeSpecOcclusion( float NdotV , float AO , float roughness )
 {
    return saturate (pow( abs(NdotV + AO) , exp2 ( -16.0f * roughness - 1.0f )) - 1.0f + AO );
@@ -270,7 +279,7 @@ vec4 compute4Lights( Surface surface,
                      vec4 inLightConfigData[4],
                      vec4 inLightColor[4],
                      vec4 inLightSpotDir[4],
-                     vec2 lightSpotParams[4],
+                     vec2 inlightSpotParams[4],
                      int hasVectorLight,
                      vec4 vectorLightDirection,
                      vec4 vectorLightingColor,
@@ -305,13 +314,10 @@ vec4 compute4Lights( Surface surface,
             //get punctual light contribution   
             lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadowed);
          }
-         else //spot
+         else if(inLightConfigData[i].x == 1) //spot
          {
-               
-            //get Punctual light contribution   
-            lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadowed);
-            //get spot angle attenuation
-            lighting *= getSpotAngleAtt(-surfaceToLight.L, inLightSpotDir[i].xyz, lightSpotParams[i].xy );
+            //get spot light contribution   
+            lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, inLightSpotDir[i].xyz, inlightSpotParams[i], shadowed);
          }
       }
       finalLighting += lighting;

+ 19 - 14
Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl

@@ -217,16 +217,16 @@ float getDistanceAtt( float3 unormalizedLightVector , float invSqrAttRadius )
 
  float getSpotAngleAtt( float3 normalizedLightVector , float3 lightDir , float2 lightSpotParams )
  {
-   float cd = dot ( lightDir , normalizedLightVector );
-   float attenuation = saturate ( ( cd - lightSpotParams.x ) / lightSpotParams.y );
+   float cd = max(dot ( lightDir , normalizedLightVector ),0.0);
+   float attenuation = saturate(((cd - lightSpotParams.x/(cd*1.001))/lightSpotParams.y));
    // smooth the transition
    return sqr(attenuation);
 }
 
 float3 evaluateStandardBRDF(Surface surface, SurfaceToLight surfaceToLight)
 {
-   //lambert diffuse
-   float3 Fd = surface.albedo.rgb * M_1OVER_PI_F;
+   //disney diffuse
+   float3 Fd = Fr_DisneyDiffuse(surface.f0, surface.NdotV, surfaceToLight.NdotL, surfaceToLight.NdotH, surface.linearRoughness);
     
    //GGX specular
    float3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
@@ -237,7 +237,7 @@ float3 evaluateStandardBRDF(Surface surface, SurfaceToLight surfaceToLight)
 #if CAPTURING == 1
     return saturate(lerp(Fd + Fr,surface.f0,surface.metalness));
 #else
-   return saturate(Fd + Fr);
+   return Fd + Fr;
 #endif
 
 }
@@ -255,6 +255,14 @@ float3 getPunctualLight(Surface surface, SurfaceToLight surfaceToLight, float3 l
    return evaluateStandardBRDF(surface,surfaceToLight) * factor;
 }
 
+float3 getSpotlight(Surface surface, SurfaceToLight surfaceToLight, float3 lightColor, float lightIntensity, float radius, float3 lightDir, float2 lightSpotParams, float shadow)
+{
+   float attenuation = 1.0f;
+   attenuation *= getDistanceAtt(surfaceToLight.Lu, radius);
+   attenuation *= getSpotAngleAtt(-surfaceToLight.L, lightDir, lightSpotParams.xy);
+   float3 factor = lightColor * max(surfaceToLight.NdotL* shadow * lightIntensity * attenuation, 0.0f) ;
+   return evaluateStandardBRDF(surface,surfaceToLight) * factor;
+}
 float computeSpecOcclusion( float NdotV , float AO , float roughness )
 {
    return saturate (pow( abs(NdotV + AO) , exp2 ( -16.0f * roughness - 1.0f )) - 1.0f + AO );
@@ -271,7 +279,7 @@ float4 compute4Lights( Surface surface,
                      float4 inLightConfigData[4],
                      float4 inLightColor[4],
                      float4 inLightSpotDir[4],
-                     float2 lightSpotParams[4],
+                     float2 inlightSpotParams[4],
                      int hasVectorLight,
                      float4 vectorLightDirection,
                      float4 vectorLightingColor,
@@ -296,7 +304,7 @@ float4 compute4Lights( Surface surface,
       float lightBrightness = inLightConfigData[i].y;
       float lightInvSqrRange= inLightConfigData[i].a;
 
-      float3 lighting = 0.0.xxx;
+      float3 lighting = float3(0.0,0.0,0.0);
 
       [branch]
       if(dist < lightRange)
@@ -307,13 +315,10 @@ float4 compute4Lights( Surface surface,
             //get punctual light contribution   
             lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadowed);
          }
-         else //spot
+         else if(inLightConfigData[i].x == 1) //spot
          {
-               
-            //get Punctual light contribution   
-            lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadowed);
-            //get spot angle attenuation
-            lighting *= getSpotAngleAtt(-surfaceToLight.L, inLightSpotDir[i].xyz, lightSpotParams[i].xy );
+            //get spot light contribution   
+            lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, inLightSpotDir[i].xyz, inlightSpotParams[i], shadowed);
          }
       }
       finalLighting += lighting;
@@ -321,7 +326,7 @@ float4 compute4Lights( Surface surface,
 
    //Vector light
    [branch]
-   if(hasVectorLight)
+   if(hasVectorLight == 1)
    {
       SurfaceToLight surfaceToVecLight = createSurfaceToLight(surface, -vectorLightDirection.xyz);
 

+ 2 - 4
Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl

@@ -154,10 +154,8 @@ void main()
       return;
    #endif
 
-      //get Punctual light contribution   
-      lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadow);
-      //get spot angle attenuation
-      lighting *= getSpotAngleAtt(-surfaceToLight.L, lightDirection, lightSpotParams );
+      //get spot light contribution   
+      lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, lightDirection, lightSpotParams, shadow);
    }
 
    OUT_col = vec4(lighting, 0);

+ 2 - 4
Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl

@@ -151,10 +151,8 @@ float4 main(   ConvexConnectP IN ) : SV_TARGET
       return final;
    #endif
 
-      //get Punctual light contribution   
-      lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadow);
-      //get spot angle attenuation
-      lighting *= getSpotAngleAtt(-surfaceToLight.L, lightDirection, lightSpotParams );
+      //get spot light contribution   
+      lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, lightDirection, lightSpotParams, shadow);
    }
    
    return float4(lighting, 0);