Skip to content

Commit

Permalink
Unhooking Metal shadows from the lighting system
Browse files Browse the repository at this point in the history
The D3D9 shadow system would manipulate lights to properly cast shadows. This change decouples Metal shadows from the lighting system and instead passes the required variables directly to the shadow renderer. This allows Metal to avoid expensive light changes to require shadows.

Also includes a fix for high shadow strength causing shadows to be too dark. The Metal pipeline was not clamping the output diffuse color into a valid range.
  • Loading branch information
colincornaby committed Jan 1, 2025
1 parent c4cbb98 commit ba6607b
Show file tree
Hide file tree
Showing 3 changed files with 4 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -623,8 +623,6 @@ vertex ColorInOut shadowCastVertexShader(Vertex in

float4 position = (float4(in.position, 1.f) * uniforms.localToWorldMatrix);
const float3 Ndirection = normalize(float4(in.normal, 0.f) * uniforms.localToWorldMatrix).xyz;
// Shadow casting uses the diffuse material color to control opacity
const half4 MDiffuse = uniforms.diffuseCol;

//w is attenation
float4 direction;
Expand All @@ -640,7 +638,8 @@ vertex ColorInOut shadowCastVertexShader(Vertex in
}

const float3 dotResult = dot(Ndirection, direction.xyz);
const half3 diffuse = MDiffuse.rgb * half3(max(0.h, dotResult)) * shadowState.power;
// Post lighting diffuse color needs to be clamped to the 0..1 range even though >1.f is valid.
const half3 diffuse = clamp(shadowState.opacity * half3(max(0.h, dotResult)) * shadowState.power, 0.f, 1.f);
out.vtxColor = half4(diffuse, 1.f);

const float4 vCamPosition = position * uniforms.worldToCameraMatrix;
Expand Down
27 changes: 1 addition & 26 deletions Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3202,9 +3202,6 @@ bool plMetalPipeline::IPushShadowCastState(plShadowSlave* slave)
if (!slave->SetupViewTransform(this))
return false;

// Set texture to U_LUT
fCurrentRenderPassUniforms->specularSrc = 0.0;

// if( !ref->fTexture )
//{
// if( ref->fData )
Expand Down Expand Up @@ -3759,6 +3756,7 @@ void plMetalPipeline::IRenderShadowsOntoSpan(const plRenderPrimFunc& render, con
// The shadow light isn't used in generating the shadow map, it's used
// in projecting the shadow map onto the scene.
plShadowState shadowState;
shadowState.opacity = first? mat->GetLayer(0)->GetOpacity() : 1.f;
ISetupShadowState(fShadows[i], shadowState);

struct plMetalFragmentShaderDescription passDescription{};
Expand Down Expand Up @@ -3846,9 +3844,6 @@ void plMetalPipeline::ISetupShadowRcvTextureStages(hsGMaterial* mat)
// same one.
fForceMatHandle = true;

// Set the D3D lighting/material model
ISetShadowLightState(mat);

// Zbuffering on read-only

if (fState.fCurrentDepthStencilState != fDevice.fNoZWriteStencilState) {
Expand Down Expand Up @@ -3885,26 +3880,6 @@ void plMetalPipeline::ISetupShadowRcvTextureStages(hsGMaterial* mat)
fDevice.CurrentRenderCommandEncoder()->setFragmentBytes(&layerIndex, sizeof(int), FragmentShaderArgumentShadowCastAlphaSrc);
}

// ISetShadowLightState //////////////////////////////////////////////////////////////////
// Set the D3D lighting/material model for projecting the shadow map onto this material.
void plMetalPipeline::ISetShadowLightState(hsGMaterial* mat)
{
fCurrLightingMethod = plSpan::kLiteShadow;

if (mat && mat->GetNumLayers() && mat->GetLayer(0))
fCurrentRenderPassUniforms->diffuseCol.r = fCurrentRenderPassUniforms->diffuseCol.g = fCurrentRenderPassUniforms->diffuseCol.b = mat->GetLayer(0)->GetOpacity();
else
fCurrentRenderPassUniforms->diffuseCol.r = fCurrentRenderPassUniforms->diffuseCol.g = fCurrentRenderPassUniforms->diffuseCol.b = 1.f;
fCurrentRenderPassUniforms->diffuseCol.a = 1.f;

fCurrentRenderPassUniforms->diffuseSrc = 1.0f;
fCurrentRenderPassUniforms->emissiveSrc = 1.0f;
fCurrentRenderPassUniforms->emissiveCol = 0.0f;
fCurrentRenderPassUniforms->specularSrc = 0.0f;
fCurrentRenderPassUniforms->ambientSrc = 0.0f;
fCurrentRenderPassUniforms->globalAmb = 0.0f;
}

// IDisableLightsForShadow ///////////////////////////////////////////////////////////
// Disable any lights that are enabled. We'll only want the shadow light illuminating
// the surface.
Expand Down
3 changes: 1 addition & 2 deletions Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,7 @@ class plMetalPipeline : public pl3DPipeline<plMetalDevice>
hsGDeviceRef* SharedRenderTargetRef(plRenderTarget* share, plRenderTarget* owner);
void IRenderShadowsOntoSpan(const plRenderPrimFunc& render, const plSpan* span, hsGMaterial* mat, plMetalVertexBufferRef* vRef);
void ISetupShadowRcvTextureStages(hsGMaterial* mat);
void ISetupShadowSlaveTextures(plShadowSlave* slave);
void ISetShadowLightState(hsGMaterial* mat);
void ISetupShadowSlaveTextures(plShadowSlave* slave);
void ISetupShadowState(plShadowSlave* slave, plShadowState& shadowState);
void IDisableLightsForShadow();
void IReleaseRenderTargetPools();
Expand Down

0 comments on commit ba6607b

Please sign in to comment.