From 593d0ef9f0633ec0062679bb6964c77df92d4339 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Sat, 18 Nov 2023 19:05:12 -0600 Subject: [PATCH] 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 --- .../advanced/advancedLightBinManager.cpp | 11 ++- Engine/source/lighting/lightManager.cpp | 87 ++++++++++--------- .../shadowMap/singleLightShadowMap.cpp | 3 +- .../game/core/rendering/shaders/brdf.hlsl | 10 +++ .../game/core/rendering/shaders/gl/brdf.glsl | 11 +++ .../core/rendering/shaders/gl/lighting.glsl | 28 +++--- .../game/core/rendering/shaders/lighting.hlsl | 33 ++++--- .../lighting/advanced/gl/spotLightP.glsl | 6 +- .../shaders/lighting/advanced/spotLightP.hlsl | 6 +- 9 files changed, 117 insertions(+), 78 deletions(-) diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.cpp b/Engine/source/lighting/advanced/advancedLightBinManager.cpp index fd8cd6dc4..c857933dd 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.cpp +++ b/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 ) diff --git a/Engine/source/lighting/lightManager.cpp b/Engine/source/lighting/lightManager.cpp index d0652a62f..ac331ba4d 100644 --- a/Engine/source/lighting/lightManager.cpp +++ b/Engine/source/lighting/lightManager.cpp @@ -333,7 +333,7 @@ void LightManager::_update4LightConsts( const SceneData &sgData, static AlignedArray lightSpotDirs(MAX_FORWARD_LIGHTS, sizeof(Point4F)); static AlignedArray lightColors(MAX_FORWARD_LIGHTS, sizeof(Point4F)); static AlignedArray lightConfigData(MAX_FORWARD_LIGHTS, sizeof(Point4F)); //type, brightness, range, invSqrRange : rgba - static AlignedArray lightSpotParams(MAX_FORWARD_LIGHTS, sizeof(Point2F)); + static AlignedArray 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) + else { - lightConfigData[i].x = 0; + // 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; + + lightColors[i] = Point4F(light->getColor()); + + F32 range = light->getRange().x; + lightConfigData[i].z = range; + + 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; + } + + lightConfigData[i].y = light->getBrightness() * luxTargMultiplier[i]; + lightConfigData[i].w = 1.0f / (range * range); } - else if (light->getType() == LightInfo::Spot) - { - lightConfigData[i].x = 1; - - 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); - - lightSpotParams[i].x = spotParams.x; - lightSpotParams[i].y = spotParams.y; - } - - lightConfigData[i].y = light->getBrightness(); - - F32 range = light->getRange().x; - lightConfigData[i].z = range; - lightConfigData[i].w = 1.0f / (range * range); } shaderConsts->setSafe(lightPositionSC, lightPositions); diff --git a/Engine/source/lighting/shadowMap/singleLightShadowMap.cpp b/Engine/source/lighting/shadowMap/singleLightShadowMap.cpp index cd4724838..4f246bec8 100644 --- a/Engine/source/lighting/shadowMap/singleLightShadowMap.cpp +++ b/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! diff --git a/Templates/BaseGame/game/core/rendering/shaders/brdf.hlsl b/Templates/BaseGame/game/core/rendering/shaders/brdf.hlsl index e18d1d0be..e36762e6e 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/brdf.hlsl +++ b/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 diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/brdf.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/brdf.glsl index dbe4d50ac..9d76de406 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/gl/brdf.glsl +++ b/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 diff --git a/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl b/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl index a903c0896..cc66cb500 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/gl/lighting.glsl +++ b/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; diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl index 0a0f1b967..9f5659ae1 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting.hlsl +++ b/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); diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl index 1a7c42822..42654c532 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl +++ b/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); diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl index a78ed019b..d4ef36a36 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl +++ b/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);