mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-14 08:04:40 +00:00
Merge db07f3d8d5 into 0b73e701ac
This commit is contained in:
commit
4fe95631e6
4 changed files with 212 additions and 149 deletions
|
|
@ -191,6 +191,16 @@ void PSSMLightShadowMap::_roundProjection(const MatrixF& lightMat, const MatrixF
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSSMLightShadowMap::_adjustScaleAndOffset(Box3F& clipAABB, Point3F& scale, Point3F& offset) {
|
void PSSMLightShadowMap::_adjustScaleAndOffset(Box3F& clipAABB, Point3F& scale, Point3F& offset) {
|
||||||
|
|
||||||
|
const ShadowMapParams* params = mLight->getExtended<ShadowMapParams>();
|
||||||
|
|
||||||
|
F32 padding = params->shadowSoftness * (2.0f / (F32)mTexSize);
|
||||||
|
|
||||||
|
clipAABB.minExtents.x -= padding;
|
||||||
|
clipAABB.minExtents.y -= padding;
|
||||||
|
clipAABB.maxExtents.x += padding;
|
||||||
|
clipAABB.maxExtents.y += padding;
|
||||||
|
|
||||||
scale.x = 2.0f / (clipAABB.maxExtents.x - clipAABB.minExtents.x);
|
scale.x = 2.0f / (clipAABB.maxExtents.x - clipAABB.minExtents.x);
|
||||||
scale.y = 2.0f / (clipAABB.maxExtents.y - clipAABB.minExtents.y);
|
scale.y = 2.0f / (clipAABB.maxExtents.y - clipAABB.minExtents.y);
|
||||||
scale.z = 1.0f;
|
scale.z = 1.0f;
|
||||||
|
|
@ -469,7 +479,7 @@ void PSSMLightShadowMap::setShaderParameters(GFXShaderConstBuffer* params, Light
|
||||||
params->setSafe( lsc->mOverDarkFactorPSSM, p->overDarkFactor);
|
params->setSafe( lsc->mOverDarkFactorPSSM, p->overDarkFactor);
|
||||||
|
|
||||||
// The softness is a factor of the texel size.
|
// The softness is a factor of the texel size.
|
||||||
params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 1.0f / mTexSize ) );
|
params->setSafe( lsc->mShadowSoftnessConst, p->shadowSoftness * ( 2.0f / mTexSize ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSSMLightShadowMap::_calcPlanesCullForShadowCasters(Vector< Vector<PlaneF> > &out, const Frustum &viewFrustum, const Point3F &_ligthDir)
|
void PSSMLightShadowMap::_calcPlanesCullForShadowCasters(Vector< Vector<PlaneF> > &out, const Frustum &viewFrustum, const Point3F &_ligthDir)
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,18 @@ void ShadowMaterialHook::init( BaseMatInstance *inMat )
|
||||||
|
|
||||||
mShadowMat[ShadowType_Spot] = newMat;
|
mShadowMat[ShadowType_Spot] = newMat;
|
||||||
|
|
||||||
|
newMat = new ShadowMatInstance(shadowMat);
|
||||||
|
newMat->setUserObject(inMat->getUserObject());
|
||||||
|
newMat->getFeaturesDelegate().bind(&ShadowMaterialHook::_overrideFeatures);
|
||||||
|
forced.setCullMode(GFXCullCW);
|
||||||
|
forced.zBias = 1000.0f;
|
||||||
|
forced.zSlopeBias = 1.0f;
|
||||||
|
forced.setFillModeSolid();
|
||||||
|
newMat->addStateBlockDesc(forced);
|
||||||
|
forced.cullDefined = true;
|
||||||
|
newMat->init(features, inMat->getVertexFormat());
|
||||||
|
mShadowMat[ShadowType_PSSM] = newMat;
|
||||||
|
|
||||||
newMat = new ShadowMatInstance( shadowMat );
|
newMat = new ShadowMatInstance( shadowMat );
|
||||||
newMat->setUserObject( inMat->getUserObject() );
|
newMat->setUserObject( inMat->getUserObject() );
|
||||||
newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
|
newMat->getFeaturesDelegate().bind( &ShadowMaterialHook::_overrideFeatures );
|
||||||
|
|
@ -162,12 +174,6 @@ BaseMatInstance* ShadowMaterialHook::getShadowMat( ShadowType type ) const
|
||||||
{
|
{
|
||||||
AssertFatal( type < ShadowType_Count, "ShadowMaterialHook::getShadowMat() - Bad light type!" );
|
AssertFatal( type < ShadowType_Count, "ShadowMaterialHook::getShadowMat() - Bad light type!" );
|
||||||
|
|
||||||
// The cubemap and pssm shadows use the same
|
|
||||||
// spotlight material for shadows.
|
|
||||||
if ( type == ShadowType_Spot ||
|
|
||||||
type == ShadowType_PSSM )
|
|
||||||
return mShadowMat[ShadowType_Spot];
|
|
||||||
|
|
||||||
// Get the specialized shadow material.
|
// Get the specialized shadow material.
|
||||||
return mShadowMat[type];
|
return mShadowMat[type];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,37 @@ static float2 sNonUniformTaps[NUM_PRE_TAPS] =
|
||||||
/// rotations of the filter taps.
|
/// rotations of the filter taps.
|
||||||
TORQUE_UNIFORM_SAMPLER2D(gTapRotationTex, 2);
|
TORQUE_UNIFORM_SAMPLER2D(gTapRotationTex, 2);
|
||||||
|
|
||||||
|
float shadowCompare(float occluderDepth, float receiverDepth)
|
||||||
|
{
|
||||||
|
return receiverDepth > occluderDepth ? 0.0 : 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float pcf_sampleTaps(
|
||||||
|
TORQUE_SAMPLER2D(shadowMap),
|
||||||
|
float2 sinCos,
|
||||||
|
float2 shadowPos,
|
||||||
|
float filterRadius,
|
||||||
|
float receiverDepth,
|
||||||
|
float factor_bias,
|
||||||
|
int startTap,
|
||||||
|
int endTap )
|
||||||
|
{
|
||||||
|
float result = 0;
|
||||||
|
|
||||||
|
float2 tap;
|
||||||
|
for(int t = startTap; t < endTap; 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(shadowMap, float4(shadowPos + tap,0,0)).r;
|
||||||
|
|
||||||
|
result += shadowCompare(occluder, receiverDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result / float(endTap - startTap);
|
||||||
|
}
|
||||||
|
|
||||||
float softShadow_sampleTaps( TORQUE_SAMPLER2D(shadowMap1),
|
float softShadow_sampleTaps( TORQUE_SAMPLER2D(shadowMap1),
|
||||||
float2 sinCos,
|
float2 sinCos,
|
||||||
float2 shadowPos,
|
float2 shadowPos,
|
||||||
|
|
@ -81,6 +112,7 @@ float softShadow_sampleTaps( TORQUE_SAMPLER2D(shadowMap1),
|
||||||
int startTap,
|
int startTap,
|
||||||
int endTap )
|
int endTap )
|
||||||
{
|
{
|
||||||
|
|
||||||
float shadow = 0;
|
float shadow = 0;
|
||||||
|
|
||||||
float2 tap = 0;
|
float2 tap = 0;
|
||||||
|
|
@ -88,9 +120,11 @@ float softShadow_sampleTaps( TORQUE_SAMPLER2D(shadowMap1),
|
||||||
{
|
{
|
||||||
tap.x = ( sNonUniformTaps[t].x * sinCos.y - sNonUniformTaps[t].y * sinCos.x ) * filterRadius;
|
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;
|
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 occluder = TORQUE_TEX2DLOD( shadowMap1, float4( shadowPos + tap, 0, 0 ) ).r;
|
||||||
|
|
||||||
float esm = saturate( exp( esmFactor * ( occluder - distToLight ) ) );
|
float esm = exp( clamp(esmFactor * (occluder - distToLight), -80.0, 0.0) );
|
||||||
|
esm = saturate(esm);
|
||||||
shadow += esm / float( endTap - startTap );
|
shadow += esm / float( endTap - startTap );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,61 +132,45 @@ float softShadow_sampleTaps( TORQUE_SAMPLER2D(shadowMap1),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float softShadow_filter( TORQUE_SAMPLER2D(shadowMap),
|
float softShadow_filter(
|
||||||
float2 vpos,
|
TORQUE_SAMPLER2D(shadowMap),
|
||||||
float2 shadowPos,
|
float2 vpos,
|
||||||
float filterRadius,
|
float2 shadowPos,
|
||||||
float distToLight,
|
float filterRadius,
|
||||||
float dotNL,
|
float distToLight,
|
||||||
float esmFactor )
|
float dotNL,
|
||||||
|
float esmFactor)
|
||||||
{
|
{
|
||||||
#ifndef SOFTSHADOW
|
float2 sinCos = (TORQUE_TEX2DLOD(gTapRotationTex, float4(vpos * 16,0,0)).rg - 0.5) * 2;
|
||||||
|
|
||||||
// If softshadow is undefined then we skip any complex
|
float shadow = pcf_sampleTaps(
|
||||||
// filtering... just do a single sample ESM.
|
TORQUE_SAMPLER2D_MAKEARG(shadowMap),
|
||||||
|
sinCos,
|
||||||
|
shadowPos,
|
||||||
|
filterRadius,
|
||||||
|
distToLight,
|
||||||
|
esmFactor,
|
||||||
|
0,
|
||||||
|
NUM_PRE_TAPS);
|
||||||
|
|
||||||
float occluder = TORQUE_TEX2DLOD(shadowMap, float4(shadowPos, 0, 0)).r;
|
#ifdef SOFTSHADOW_HIGH_QUALITY
|
||||||
float shadow = saturate( exp( esmFactor * ( occluder - distToLight ) ) );
|
|
||||||
|
|
||||||
#else
|
if(shadow * (1.0-shadow) * max(dotNL,0) > 0.06)
|
||||||
// Lookup the random rotation for this screen pixel.
|
{
|
||||||
float2 sinCos = ( TORQUE_TEX2DLOD(gTapRotationTex, float4(vpos * 16, 0, 0)).rg - 0.5) * 2;
|
shadow += pcf_sampleTaps(
|
||||||
|
TORQUE_SAMPLER2D_MAKEARG(shadowMap),
|
||||||
|
sinCos,
|
||||||
|
shadowPos,
|
||||||
|
filterRadius,
|
||||||
|
distToLight,
|
||||||
|
esmFactor,
|
||||||
|
NUM_PRE_TAPS,
|
||||||
|
NUM_TAPS);
|
||||||
|
|
||||||
// Do the prediction taps first.
|
shadow *= 0.5;
|
||||||
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
|
#endif
|
||||||
// have high quality shadow filtering enabled.
|
|
||||||
#ifdef SOFTSHADOW_HIGH_QUALITY
|
|
||||||
|
|
||||||
// Only do the expensive filtering if we're really
|
return shadow;
|
||||||
// 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
|
|
||||||
|
|
||||||
#endif // SOFTSHADOW
|
|
||||||
|
|
||||||
return shadow;
|
|
||||||
}
|
}
|
||||||
|
|
@ -64,109 +64,138 @@ uniform float4 scaleY;
|
||||||
uniform float4 offsetX;
|
uniform float4 offsetX;
|
||||||
uniform float4 offsetY;
|
uniform float4 offsetY;
|
||||||
|
|
||||||
float4 AL_VectorLightShadowCast( TORQUE_SAMPLER2D(sourceShadowMap),
|
float ComputeESMFactor(float cascadeNear, float cascadeFar, int shadowMapResolution, float targetShadow = 0.1)
|
||||||
float2 texCoord,
|
|
||||||
float4x4 worldToLightProj,
|
|
||||||
float3 worldPos,
|
|
||||||
float4 scaleX,
|
|
||||||
float4 scaleY,
|
|
||||||
float4 offsetX,
|
|
||||||
float4 offsetY,
|
|
||||||
float4 farPlaneScalePSSM,
|
|
||||||
float dotNL)
|
|
||||||
{
|
{
|
||||||
// Compute shadow map coordinate
|
float delta = (cascadeFar - cascadeNear) / shadowMapResolution;
|
||||||
float4 pxlPosLightProj = mul(worldToLightProj, float4(worldPos,1));
|
float esmFactor = -log(targetShadow) / delta;
|
||||||
float2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w;
|
return esmFactor;
|
||||||
|
}
|
||||||
|
|
||||||
// Distance to light, in shadowmap space
|
float4 AL_VectorLightShadowCast(
|
||||||
float distToLight = pxlPosLightProj.z / pxlPosLightProj.w;
|
TORQUE_SAMPLER2D(sourceShadowMap),
|
||||||
|
float2 texCoord,
|
||||||
// Figure out which split to sample from. Basically, we compute the shadowmap sample coord
|
float4x4 worldToLightProj,
|
||||||
// for all of the splits and then check if its valid.
|
float3 worldPos,
|
||||||
float4 shadowCoordX = baseShadowCoord.xxxx;
|
float4 scaleX,
|
||||||
float4 shadowCoordY = baseShadowCoord.yyyy;
|
float4 scaleY,
|
||||||
float4 farPlaneDists = distToLight.xxxx;
|
float4 offsetX,
|
||||||
shadowCoordX *= scaleX;
|
float4 offsetY,
|
||||||
shadowCoordY *= scaleY;
|
float4 farPlaneScalePSSM,
|
||||||
shadowCoordX += offsetX;
|
float dotNL)
|
||||||
shadowCoordY += offsetY;
|
{
|
||||||
farPlaneDists *= farPlaneScalePSSM;
|
// Compute shadow map coordinate
|
||||||
|
float4 pxlPosLightProj = mul(worldToLightProj, float4(worldPos,1));
|
||||||
// If the shadow sample is within -1..1 and the distance
|
float2 baseShadowCoord = pxlPosLightProj.xy / pxlPosLightProj.w;
|
||||||
// to the light for this pixel is less than the far plane
|
float distToLight = pxlPosLightProj.z / pxlPosLightProj.w;
|
||||||
// of the split, use it.
|
|
||||||
float4 finalMask;
|
|
||||||
if ( shadowCoordX.x > -0.99 && shadowCoordX.x < 0.99 &&
|
|
||||||
shadowCoordY.x > -0.99 && shadowCoordY.x < 0.99 &&
|
|
||||||
farPlaneDists.x < 1.0 )
|
|
||||||
finalMask = float4(1, 0, 0, 0);
|
|
||||||
|
|
||||||
else if ( shadowCoordX.y > -0.99 && shadowCoordX.y < 0.99 &&
|
// PSSM split handling
|
||||||
shadowCoordY.y > -0.99 && shadowCoordY.y < 0.99 &&
|
float4 shadowCoordX = baseShadowCoord.xxxx;
|
||||||
farPlaneDists.y < 1.0 )
|
float4 shadowCoordY = baseShadowCoord.yyyy;
|
||||||
finalMask = float4(0, 1, 0, 0);
|
float4 farPlaneDists = distToLight.xxxx;
|
||||||
|
shadowCoordX *= scaleX;
|
||||||
|
shadowCoordY *= scaleY;
|
||||||
|
shadowCoordX += offsetX;
|
||||||
|
shadowCoordY += offsetY;
|
||||||
|
farPlaneDists *= farPlaneScalePSSM;
|
||||||
|
|
||||||
else if ( shadowCoordX.z > -0.99 && shadowCoordX.z < 0.99 &&
|
const float cascadeBorder = 0.02;
|
||||||
shadowCoordY.z > -0.99 && shadowCoordY.z < 0.99 &&
|
float4 insideX = step(-1.0 + cascadeBorder, shadowCoordX) * step(shadowCoordX, 1.0 - cascadeBorder);
|
||||||
farPlaneDists.z < 1.0 )
|
float4 insideY = step(-1.0 + cascadeBorder, shadowCoordY) * step(shadowCoordY, 1.0 - cascadeBorder);
|
||||||
finalMask = float4(0, 0, 1, 0);
|
float4 insideZ = step(farPlaneDists, 1.0);
|
||||||
|
|
||||||
else
|
|
||||||
finalMask = float4(0, 0, 0, 1);
|
|
||||||
|
|
||||||
float3 debugColor = float3(0,0,0);
|
|
||||||
|
|
||||||
#ifdef NO_SHADOW
|
|
||||||
debugColor = float3(1.0,1.0,1.0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PSSM_DEBUG_RENDER
|
|
||||||
if ( finalMask.x > 0 )
|
|
||||||
debugColor += float3( 1, 0, 0 );
|
|
||||||
else if ( finalMask.y > 0 )
|
|
||||||
debugColor += float3( 0, 1, 0 );
|
|
||||||
else if ( finalMask.z > 0 )
|
|
||||||
debugColor += float3( 0, 0, 1 );
|
|
||||||
else if ( finalMask.w > 0 )
|
|
||||||
debugColor += float3( 1, 1, 0 );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Here we know what split we're sampling from, so recompute the texcoord location
|
float4 cascadeValid = insideX * insideY * insideZ;
|
||||||
// Yes, we could just use the result from above, but doing it this way actually saves
|
|
||||||
// shader instructions.
|
|
||||||
float2 finalScale;
|
|
||||||
finalScale.x = dot(finalMask, scaleX);
|
|
||||||
finalScale.y = dot(finalMask, scaleY);
|
|
||||||
|
|
||||||
float2 finalOffset;
|
float4 finalMask;
|
||||||
finalOffset.x = dot(finalMask, offsetX);
|
|
||||||
finalOffset.y = dot(finalMask, offsetY);
|
|
||||||
|
|
||||||
float2 shadowCoord;
|
finalMask.x = cascadeValid.x;
|
||||||
shadowCoord = baseShadowCoord * finalScale;
|
finalMask.y = (1 - finalMask.x) * cascadeValid.y;
|
||||||
shadowCoord += finalOffset;
|
finalMask.z = (1 - finalMask.x - finalMask.y) * cascadeValid.z;
|
||||||
|
finalMask.w = 1 - finalMask.x - finalMask.y - finalMask.z;
|
||||||
|
|
||||||
// Convert to texcoord space
|
float3 debugColor = float3(0,0,0);
|
||||||
shadowCoord = 0.5 * shadowCoord + float2(0.5, 0.5);
|
|
||||||
shadowCoord.y = 1.0f - shadowCoord.y;
|
|
||||||
|
|
||||||
// Move around inside of atlas
|
#ifdef NO_SHADOW
|
||||||
float2 aOffset;
|
debugColor = float3(1.0,1.0,1.0);
|
||||||
aOffset.x = dot(finalMask, atlasXOffset);
|
#endif
|
||||||
aOffset.y = dot(finalMask, atlasYOffset);
|
|
||||||
|
|
||||||
shadowCoord *= atlasScale;
|
#ifdef PSSM_DEBUG_RENDER
|
||||||
shadowCoord += aOffset;
|
if ( finalMask.x > 0 )
|
||||||
|
debugColor += float3( 1, 0, 0 );
|
||||||
// Each split has a different far plane, take this into account.
|
else if ( finalMask.y > 0 )
|
||||||
float farPlaneScale = dot( farPlaneScalePSSM, finalMask );
|
debugColor += float3( 0, 1, 0 );
|
||||||
distToLight *= farPlaneScale;
|
else if ( finalMask.z > 0 )
|
||||||
|
debugColor += float3( 0, 0, 1 );
|
||||||
|
else if ( finalMask.w > 0 )
|
||||||
|
debugColor += float3( 1, 1, 0 );
|
||||||
|
#endif
|
||||||
|
|
||||||
return float4(debugColor, softShadow_filter( TORQUE_SAMPLER2D_MAKEARG(sourceShadowMap), texCoord, shadowCoord, farPlaneScale * shadowSoftness,
|
// Compute final scale & offset for PSSM atlas
|
||||||
distToLight, dotNL, dot( finalMask, overDarkPSSM ) ) );
|
float2 finalScale;
|
||||||
};
|
finalScale.x = dot(finalMask, scaleX);
|
||||||
|
finalScale.y = dot(finalMask, scaleY);
|
||||||
|
float2 finalOffset;
|
||||||
|
finalOffset.x = dot(finalMask, offsetX);
|
||||||
|
finalOffset.y = dot(finalMask, offsetY);
|
||||||
|
|
||||||
|
float2 shadowCoord = baseShadowCoord * finalScale + finalOffset;
|
||||||
|
|
||||||
|
// Convert to texcoord space and atlas
|
||||||
|
shadowCoord = 0.5 *shadowCoord + 0.5;
|
||||||
|
shadowCoord.y = 1.0 - shadowCoord.y;
|
||||||
|
float2 aOffset;
|
||||||
|
aOffset.x = dot(finalMask, atlasXOffset);
|
||||||
|
aOffset.y = dot(finalMask, atlasYOffset);
|
||||||
|
shadowCoord = shadowCoord * atlasScale + aOffset;
|
||||||
|
|
||||||
|
// Compute atlas tile bounds
|
||||||
|
float2 tileMin = aOffset;
|
||||||
|
float2 tileMax = aOffset + atlasScale;
|
||||||
|
|
||||||
|
// Convert filter radius to atlas UV space
|
||||||
|
float2 filterRadiusUV = shadowSoftness * atlasScale;
|
||||||
|
|
||||||
|
// Adjust for PSSM far plane
|
||||||
|
float farPlaneScale = dot(farPlaneScalePSSM, finalMask);
|
||||||
|
distToLight *= farPlaneScale;
|
||||||
|
|
||||||
|
|
||||||
|
// Shadow map resolution per cascade
|
||||||
|
int shadowRes = 1024;
|
||||||
|
float cascadeTexel = 1.0 / shadowRes;
|
||||||
|
float4 depthBiasPSSM = float4(
|
||||||
|
0.2 * cascadeTexel,
|
||||||
|
0.3 * cascadeTexel,
|
||||||
|
0.7 * cascadeTexel,
|
||||||
|
1.5 * cascadeTexel
|
||||||
|
);
|
||||||
|
|
||||||
|
float shadow_bias = dot(finalMask, depthBiasPSSM);
|
||||||
|
distToLight += shadow_bias;
|
||||||
|
distToLight = saturate(distToLight);
|
||||||
|
|
||||||
|
// Example cascade ranges
|
||||||
|
float cascadeNear[4] = { 0.0, 0.2, 0.5, 0.75 };
|
||||||
|
float cascadeFar[4] = { 0.2, 0.5, 0.75, 1.0 };
|
||||||
|
|
||||||
|
float4 overDarkPSSM;
|
||||||
|
for(int i=0;i<4;i++)
|
||||||
|
{
|
||||||
|
overDarkPSSM[i] = ComputeESMFactor(cascadeNear[i], cascadeFar[i], shadowRes, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return float4(
|
||||||
|
debugColor,
|
||||||
|
softShadow_filter(
|
||||||
|
TORQUE_SAMPLER2D_MAKEARG(sourceShadowMap),
|
||||||
|
texCoord,
|
||||||
|
shadowCoord,
|
||||||
|
shadowSoftness,
|
||||||
|
distToLight,
|
||||||
|
dotNL,
|
||||||
|
dot(finalMask, overDarkPSSM) // replace this with shadowBias for pcf.
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
float4 main(FarFrustumQuadConnectP IN) : SV_TARGET
|
float4 main(FarFrustumQuadConnectP IN) : SV_TARGET
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue