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
This commit is contained in:
AzaezelX 2023-11-18 19:05:12 -06:00
parent 917cb882e9
commit 593d0ef9f0
9 changed files with 117 additions and 78 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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