Shadow tests

only works on vectorLight (eg sun and scatter sky) for now
This commit is contained in:
marauder2k7 2022-12-13 21:48:39 +00:00
parent abbfb634f3
commit 239c7e58d2
9 changed files with 182 additions and 121 deletions

View file

@ -807,7 +807,9 @@ void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const Light
const F32 innerCone = getMin(lightInfo->getInnerConeAngle(), outerCone);
const F32 outerCos = mCos(mDegToRad(outerCone / 2.0f));
const F32 innerCos = mCos(mDegToRad(innerCone / 2.0f));
Point2F spotParams(outerCos,innerCos - outerCos);
const F32 lightAngleScale = 1.0f / getMax(0.001f, (innerCos - outerCos));
const F32 lightAngleOffset = -outerCos * lightAngleScale;
Point2F spotParams(lightAngleScale, lightAngleOffset);
matParams->setSafe( lightSpotParams, spotParams );
matParams->setSafe( lightDirection, lightInfo->getDirection());

View file

@ -265,8 +265,16 @@ bool LightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants*
{
S32 reg = lsc->mShadowMapSC->getSamplerRegister();
if ( reg != -1 )
GFX->setTexture( reg, mShadowMapTex);
if (reg != -1)
{
GFX->setTexture(reg, mShadowMapTex);
}
reg = lsc->mShadowMapCMPSC->getSamplerRegister();
if (reg != -1)
{
GFX->setTexture(reg, mShadowMapTex);
}
return true;
} else if ( currTexFlag == Material::DynamicLightMask )
@ -427,7 +435,8 @@ LightingShaderConstants::LightingShaderConstants()
mVectorLightDirectionSC(NULL),
mVectorLightColorSC(NULL),
mVectorLightBrightnessSC(NULL),
mShadowMapSC(NULL),
mShadowMapSC(NULL),
mShadowMapCMPSC(NULL),
mShadowMapSizeSC(NULL),
mCookieMapSC(NULL),
mRandomDirsConst(NULL),
@ -487,6 +496,7 @@ void LightingShaderConstants::init(GFXShader* shader)
mVectorLightBrightnessSC = shader->getShaderConstHandle(ShaderGenVars::vectorLightBrightness);
mShadowMapSC = shader->getShaderConstHandle("$shadowMap");
mShadowMapCMPSC = shader->getShaderConstHandle("$shadowMapCMP");
mShadowMapSizeSC = shader->getShaderConstHandle("$shadowMapSize");
mCookieMapSC = shader->getShaderConstHandle("$cookieMap");

View file

@ -96,6 +96,7 @@ struct LightingShaderConstants
GFXShaderConstHandle* mVectorLightBrightnessSC;
GFXShaderConstHandle* mShadowMapSC;
GFXShaderConstHandle* mShadowMapCMPSC;
GFXShaderConstHandle* mShadowMapSizeSC;
GFXShaderConstHandle* mCookieMapSC;

View file

@ -20,6 +20,14 @@
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
singleton GFXSamplerStateData(ShadowSampler)
{
addressModeU = GFXAddressMirror;
addressModeV = GFXAddressMirror;
magFilter = GFXTextureFilterLinear;
minFilter = GFXTextureFilterLinear;
samplerFunc = GFXCmpGreater;
};
// Vector Light State
singleton GFXStateBlockData( AL_VectorLightState )
@ -44,9 +52,10 @@ singleton GFXStateBlockData( AL_VectorLightState )
samplersDefined = true;
samplerStates[0] = SamplerClampPoint; // G-buffer
samplerStates[1] = SamplerClampPoint; // Shadow Map (Do not change this to linear, as all cards can not filter equally.)
samplerStates[3] = SamplerWrapPoint; // gTapRotationTex Random Direction Map
samplerStates[4] = SamplerClampPoint; // colorBuffer
samplerStates[5] = SamplerClampPoint; // matInfoBuffer
samplerStates[2] = SamplerWrapPoint; // gTapRotationTex Random Direction Map
samplerStates[3] = SamplerClampPoint; // colorBuffer
samplerStates[4] = SamplerClampPoint; // matInfoBuffer
samplerStates[5] = ShadowSampler; // Shadow Map (Do not change this to linear, as all cards can not filter equally.)
cullDefined = true;
cullMode = GFXCullNone;
@ -69,7 +78,8 @@ singleton shaderData( AL_VectorLightShader )
samplerNames[1] = "$shadowMap";
samplerNames[2] = "$gTapRotationTex";
samplerNames[3] = "$colorBuffer";
samplerNames[4] = "$matInfoBuffer";
samplerNames[4] = "$matInfoBuffer";
samplerNames[5] = "$shadowMapCMP";
pixVersion = 3.0;
};
@ -83,6 +93,7 @@ singleton CustomMaterial( AL_VectorLightMaterial )
sampler["shadowMap"] = "$dynamiclight";
sampler["colorBuffer"] = "#color";
sampler["matInfoBuffer"] = "#matinfo";
sampler["shadowMapCMP"] = "$dynamiclight";
target = "AL_FormatToken";

View file

@ -204,23 +204,21 @@ float smoothDistanceAtt ( float squaredDistance , float invSqrAttRadius )
{
float factor = squaredDistance * invSqrAttRadius ;
float smoothFactor = saturate (1.0f - factor * factor );
return sqr(smoothFactor);
return smoothFactor * smoothFactor;
}
float getDistanceAtt( float3 unormalizedLightVector , float invSqrAttRadius )
{
float sqrDist = dot ( unormalizedLightVector , unormalizedLightVector );
float attenuation = 1.0 / (max ( sqrDist , 0.01*0.01) );
attenuation *= smoothDistanceAtt ( sqrDist , invSqrAttRadius );
float sqrDist = dot( unormalizedLightVector, unormalizedLightVector );
float attenuation = 1.0 / sqrDist * smoothDistanceAtt ( sqrDist , invSqrAttRadius );
return attenuation;
}
float getSpotAngleAtt( float3 normalizedLightVector , float3 lightDir , float2 lightSpotParams )
float getSpotAngleAtt( float3 normalizedLightVector , float3 lightDir , float2 lightSpotParams, float exponent )
{
float cd = dot ( lightDir , normalizedLightVector );
float attenuation = saturate ( ( cd - lightSpotParams.x ) / lightSpotParams.y );
float attenuation = clamp(dot(lightDir, normalizedLightVector) * lightSpotParams.x + lightSpotParams.y, 0.0, 1.0);
// smooth the transition
return sqr(attenuation);
return attenuation * attenuation;
}
float3 evaluateStandardBRDF(Surface surface, SurfaceToLight surfaceToLight)
@ -250,8 +248,11 @@ float3 getDirectionalLight(Surface surface, SurfaceToLight surfaceToLight, float
float3 getPunctualLight(Surface surface, SurfaceToLight surfaceToLight, float3 lightColor, float lightIntensity, float radius, float shadow)
{
float attenuation = getDistanceAtt(surfaceToLight.Lu, radius);
float3 factor = lightColor * max(surfaceToLight.NdotL* shadow * lightIntensity * attenuation, 0.0f) ;
float attenuation = 1;
attenuation *= getDistanceAtt(surfaceToLight.Lu, radius);
float3 lCol = lightColor.rgb *(lightIntensity / (4.0 * 3.14159265359));
float3 radince = lCol * attenuation;
float3 factor = saturate(surfaceToLight.NdotL) * shadow * radince;
return evaluateStandardBRDF(surface,surfaceToLight) * factor;
}
@ -310,7 +311,7 @@ float4 compute4Lights( Surface surface,
//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 );
lighting *= getSpotAngleAtt(-surfaceToLight.L, inLightSpotDir[i].xyz, lightSpotParams[i].xy, lightRange );
}
}
finalLighting += lighting;

View file

@ -101,7 +101,7 @@ TORQUE_UNIFORM_SAMPLER2D(deferredBuffer, 0);
#ifdef SHADOW_CUBE
TORQUE_UNIFORM_SAMPLERCUBE(shadowMap, 1);
#else
TORQUE_UNIFORM_SAMPLER2D(shadowMap, 1);
TORQUE_UNIFORM_SAMPLER2DCMP(shadowMap, 1);
#endif
//contains gTapRotationTex sampler
#include "softShadow.hlsl"
@ -174,7 +174,8 @@ float4 main( ConvexConnectP IN ) : SV_TARGET
#else
float2 shadowCoord = decodeShadowCoord( mul( worldToLightProj, -surfaceToLight.L ) ).xy;
float shadowed = softShadow_filter(TORQUE_SAMPLER2D_MAKEARG(shadowMap), ssPos.xy, shadowCoord, shadowSoftness, distToLight, surfaceToLight.NdotL, lightParams.y);
float4 shadowed = softShadow_filter(TORQUE_SAMPLER2D_MAKEARG(shadowMap), IN.pos.xy, ssPos.xy, shadowCoord, shadowSoftness, distToLight, surfaceToLight.NdotL, lightParams.y);
float shadowed = shadowed_colors.a;
#endif
#endif // !NO_SHADOW

View file

@ -22,83 +22,104 @@
#include "../../shaderModel.hlsl"
#if defined( SOFTSHADOW ) && defined( SOFTSHADOW_HIGH_QUALITY )
#define NUM_PRE_TAPS 4
#define NUM_TAPS 12
/// The non-uniform poisson disk used in the
/// high quality shadow filtering.
static float2 sNonUniformTaps[NUM_TAPS] =
{
// These first 4 taps are located around the edges
// of the disk and are used to predict fully shadowed
// or unshadowed areas.
{ 0.992833, 0.979309 },
{ -0.998585, 0.985853 },
{ 0.949299, -0.882562 },
{ -0.941358, -0.893924 },
// The rest of the samples.
{ 0.545055, -0.589072 },
{ 0.346526, 0.385821 },
{ -0.260183, 0.334412 },
{ 0.248676, -0.679605 },
{ -0.569502, -0.390637 },
{ -0.614096, 0.212577 },
{ -0.259178, 0.876272 },
{ 0.649526, 0.864333 },
};
#else
#define NUM_PRE_TAPS 5
/// The non-uniform poisson disk used in the
/// high quality shadow filtering.
static float2 sNonUniformTaps[NUM_PRE_TAPS] =
{
{ 0.892833, 0.959309 },
{ -0.941358, -0.873924 },
{ -0.260183, 0.334412 },
{ 0.348676, -0.679605 },
{ -0.569502, -0.390637 },
};
#endif
#define NUM_TAPS 16
/// The texture used to do per-pixel pseudorandom
/// rotations of the filter taps.
TORQUE_UNIFORM_SAMPLER2D(gTapRotationTex, 2);
float softShadow_sampleTaps( TORQUE_SAMPLER2D(shadowMap1),
float2 sinCos,
float2 VogelDisk(int sampleIndex, int sampleCount, float gradient)
{
float gA = 2.4f;
float r = sqrt(sampleIndex + 0.5f) / sqrt(sampleCount);
float theta = sampleIndex * gA + gradient;
float sine, cosine;
sincos(theta, sine, cosine);
return float2(r * cosine, r * sine);
}
float GradientNoise(float2 screenPos)
{
float3 mag = float3(0.06711056f, 0.00583715f, 52.9829189f);
return frac(mag.z * frac(dot(screenPos, mag.xy)));
}
float AvgOccluderDepthPenumbra(float zShadow, float avgDepth)
{
float penumbra = (zShadow - avgDepth) / avgDepth;
penumbra *= penumbra;
return saturate(80.0f * penumbra);
}
float AvgOccluderDepthPenumbra(float lightSize, float zShadow, float avgDepth)
{
float penumbra = lightSize * (zShadow - avgDepth) / avgDepth;
return penumbra;
}
float Penumbra(TORQUE_SAMPLER2D(shadowMap2), float gradient, float2 shadowUV, float zShadow, float filterRadius, float esmFactor, int sampleCount)
{
float avgOccluderDepth = 0.0f;
float occluderCount = 0.0f;
float penumbraFilterMaxSize = 8.0 / 1024.0;
for(int i = 0; i < sampleCount; i++)
{
float2 sampleUV = VogelDisk(i, sampleCount, gradient) * penumbraFilterMaxSize;
sampleUV = shadowUV + sampleUV;
float occDepth = TORQUE_TEX2DLOD( shadowMap2, float4(sampleUV,0,0) ).r;
if(occDepth < zShadow)
{
avgOccluderDepth += occDepth;
occluderCount += 1.0f;
}
}
if(occluderCount > 0.0f)
{
avgOccluderDepth /= occluderCount;
return AvgOccluderDepthPenumbra(1000.0f, zShadow, avgOccluderDepth);
}
else
{
return 0.0f;
}
}
float softShadow_sampleTaps( TORQUE_SAMPLER2DCMP(shadowMap1),
float2 screenPos,
float2 vpos,
float2 shadowPos,
float filterRadius,
float distToLight,
float esmFactor,
float gradient,
float penumbra,
int startTap,
int endTap )
{
float shadow = 0;
float2 tap = 0;
for ( int t = startTap; t < endTap; t++ )
for ( int t = 0; t < NUM_TAPS; t++ )
{
tap.x = ( sNonUniformTaps[t].x * sinCos.y - sNonUniformTaps[t].y * sinCos.x ) * filterRadius;
tap.y = ( sNonUniformTaps[t].y * sinCos.y + sNonUniformTaps[t].x * sinCos.x ) * filterRadius;
float occluder = TORQUE_TEX2DLOD( shadowMap1, float4( shadowPos + tap, 0, 0 ) ).r;
float esm = saturate( exp( esmFactor * ( occluder - distToLight ) ) );
shadow += esm / float( endTap - startTap );
tap = VogelDisk(t, NUM_TAPS, gradient);
tap = shadowPos + tap * penumbra * filterRadius;
float occluder = TORQUE_TEX2DCMP( shadowMap1, tap, distToLight).r;
float esm = saturate( exp( esmFactor * ( occluder - distToLight ) ) );
shadow += esm;
}
return shadow;
}
float softShadow_filter( TORQUE_SAMPLER2D(shadowMap),
float softShadow_filter(
TORQUE_SAMPLER2D(shadowMap),
TORQUE_SAMPLER2DCMP(shadowMapCMP),
float2 screenPos,
float2 vpos,
float2 shadowPos,
float filterRadius,
@ -111,46 +132,32 @@ float softShadow_filter( TORQUE_SAMPLER2D(shadowMap),
// If softshadow is undefined then we skip any complex
// filtering... just do a single sample ESM.
float occluder = TORQUE_TEX2DLOD(shadowMap, float4(shadowPos, 0, 0)).r;
float shadow = saturate( exp( esmFactor * ( occluder - distToLight ) ) );
float occluder = TORQUE_TEX2DLOD( shadowMap, float4(shadowPos,0,0) ).r;
float shadow = occluder;
#else
// Lookup the random rotation for this screen pixel.
float2 sinCos = ( TORQUE_TEX2DLOD(gTapRotationTex, float4(vpos * 16, 0, 0)).rg - 0.5) * 2;
// Do the prediction taps first.
float shadow = softShadow_sampleTaps( TORQUE_SAMPLER2D_MAKEARG(shadowMap),
sinCos,
shadowPos,
filterRadius,
distToLight,
esmFactor,
0,
NUM_PRE_TAPS );
// We live with only the pretap results if we don't
// have high quality shadow filtering enabled.
#ifdef SOFTSHADOW_HIGH_QUALITY
// Only do the expensive filtering if we're really
// in a partially shadowed area.
if ( shadow * ( 1.0 - shadow ) * max( dotNL, 0 ) > 0.06 )
{
shadow += softShadow_sampleTaps( TORQUE_SAMPLER2D_MAKEARG(shadowMap),
sinCos,
shadowPos,
filterRadius,
distToLight,
esmFactor,
NUM_PRE_TAPS,
NUM_TAPS );
// This averages the taps above with the results
// of the prediction samples.
shadow *= 0.5;
}
#endif // SOFTSHADOW_HIGH_QUALITY
float gradient = 6.28318530718 * GradientNoise(screenPos);
float penumbra = Penumbra(TORQUE_SAMPLER2D_MAKEARG(shadowMap), gradient, shadowPos, distToLight, filterRadius, esmFactor, NUM_TAPS);
if(penumbra < 1.0)
penumbra = 1.0;
float shadow = softShadow_sampleTaps( TORQUE_SAMPLER2D_MAKEARG(shadowMapCMP),
screenPos,
vpos,
shadowPos,
filterRadius,
distToLight,
esmFactor,
gradient,
penumbra,
0,
NUM_TAPS );
// This averages the taps above with the results
// of the prediction samples.
// if you change the number of taps, this value should be set to that.
shadow = 1.0 - shadow / float(NUM_TAPS);
#endif // SOFTSHADOW

View file

@ -153,9 +153,16 @@ float4 main( ConvexConnectP IN ) : SV_TARGET
#endif
//get Punctual light contribution
lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadowed);
//get spot angle attenuation
lighting *= getSpotAngleAtt(-surfaceToLight.L, lightDirection, lightSpotParams );
float att = 1;
att *= getDistanceAtt(surfaceToLight.L, lightInvSqrRange);
att *= getSpotAngleAtt(-surfaceToLight.L, lightDirection, lightSpotParams, lightRange);
float3 lCol = lightColor.rgb *(lightBrightness / (4.0 * 3.14159265359));
float3 radince = lCol * att;
float3 factor = saturate(surfaceToLight.NdotL) * shadowed * radince;
lighting = evaluateStandardBRDF(surface,surfaceToLight) * factor;
//
}
return float4(lighting, 0);

View file

@ -30,11 +30,11 @@
TORQUE_UNIFORM_SAMPLER2D(deferredBuffer, 0);
TORQUE_UNIFORM_SAMPLER2D(shadowMap, 1);
//contains gTapRotationTex sampler
#include "softShadow.hlsl"
TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 3);
TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 4);
TORQUE_UNIFORM_SAMPLER2DCMP(shadowMapCmp, 5);
uniform float lightBrightness;
uniform float3 lightDirection;
@ -65,6 +65,8 @@ uniform float4 offsetX;
uniform float4 offsetY;
float4 AL_VectorLightShadowCast( TORQUE_SAMPLER2D(sourceShadowMap),
TORQUE_SAMPLER2DCMP(sourceShadowMapCMP),
float2 screenPos,
float2 texCoord,
float4x4 worldToLightProj,
float3 worldPos,
@ -163,8 +165,16 @@ float4 AL_VectorLightShadowCast( TORQUE_SAMPLER2D(sourceShadowMap),
float farPlaneScale = dot( farPlaneScalePSSM, finalMask );
distToLight *= farPlaneScale;
return float4(debugColor, softShadow_filter( TORQUE_SAMPLER2D_MAKEARG(sourceShadowMap), texCoord, shadowCoord, farPlaneScale * shadowSoftness,
distToLight, dotNL, dot( finalMask, overDarkPSSM ) ) );
return float4(debugColor, softShadow_filter(
TORQUE_SAMPLER2D_MAKEARG(sourceShadowMap),
TORQUE_SAMPLER2D_MAKEARG(sourceShadowMapCMP),
screenPos,
texCoord,
shadowCoord,
farPlaneScale * shadowSoftness,
distToLight,
dotNL,
dot( finalMask, overDarkPSSM ) ) );
};
@ -197,8 +207,19 @@ float4 main(FarFrustumQuadConnectP IN) : SV_TARGET
float4 zDist = (zNearFarInvNearFar.x + zNearFarInvNearFar.y * surface.depth);
float fadeOutAmt = ( zDist.x - fadeStartLength.x ) * fadeStartLength.y;
float4 shadowed_colors = AL_VectorLightShadowCast( TORQUE_SAMPLER2D_MAKEARG(shadowMap), IN.uv0.xy, worldToLightProj, surface.P, scaleX, scaleY, offsetX, offsetY,
farPlaneScalePSSM, surfaceToLight.NdotL);
float4 shadowed_colors = AL_VectorLightShadowCast(
TORQUE_SAMPLER2D_MAKEARG(shadowMap),
TORQUE_SAMPLER2D_MAKEARG(shadowMapCmp),
IN.hpos.xy,
IN.uv0.xy,
worldToLightProj,
surface.P,
scaleX,
scaleY,
offsetX,
offsetY,
farPlaneScalePSSM,
surfaceToLight.NdotL);
float shadow = shadowed_colors.a;