Clip hero cutout in MotionVectors pass to fix HTrace depth corruption

The MotionVectors pass (drawn by HTrace and URP against the real camera
depth buffer) was stock URP: no cutout clip and ZWrite on, so it wrote
the wall depth back into the hole after opaques. The skybox then failed
the depth test there (black disc) and all screen-space effects
(SSAO/GI) shaded the hole with the occluded wall's depth.

The pass now runs ApplyHeroCutout before URP's fragment entry point.
ObjectMotionVectors.hlsl forces its own entry via include_with_pragmas,
so the pragmas are declared explicitly and the file is plain-included.
Complements the earlier GBuffer clip; XR MV pass and ShadowCaster stay
stock on purpose. Includes render-queue churn on the occluder material.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Fable 5 committed 2026-07-09 18:33:25 +02:00
1 parent fb3588cc7d
commit 2a59a32705
2 files changed
+39 -4

No files matched your search

+1 -1
View File
@@ -16,7 +16,7 @@ Material:
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
m_CustomRenderQueue: 2000
stringTagMap:
RenderType: Opaque
disabledShaderPasses: []
+38 -3
View File
@@ -4,7 +4,7 @@
//
// It is a faithful copy of URP's Lit.shader - same properties, keywords and includes, so material
// values transfer 1:1 and the inspector GUI keeps working. The ONLY change is in four passes
// (ForwardLit, ShadowCaster, DepthOnly, DepthNormals): the stock fragment entry point is replaced by
// (ForwardLit, GBuffer, DepthOnly, DepthNormals): the stock fragment entry point is replaced by
// a thin wrapper that runs ApplyHeroCutout() and then delegates to URP's original fragment. All
// shading is therefore URP's own - zero reimplementation, so it stays correct across URP updates.
Shader "Custom/HeroCutoutLit"
@@ -278,7 +278,7 @@ Shader "Custom/HeroCutoutLit"
// -------------------------------------
// Shader Stages
#pragma vertex LitGBufferPassVertex
#pragma fragment LitGBufferPassFragment
#pragma fragment HeroGBufferFragment
// -------------------------------------
// Material Keywords
@@ -337,6 +337,17 @@ Shader "Custom/HeroCutoutLit"
// Includes
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitGBufferPass.hlsl"
#include "HeroCutout.hlsl"
// Radial cutout, then delegate to URP's stock GBuffer fragment. Without this, external
// GBuffer consumers (HTrace WSGI renders its own thin GBuffer via this LightMode and
// composites GI after post-processing) still see solid occluder geometry inside the hole
// and stomp the visible skybox/background there with surface GI -> black disc.
GBufferFragOutput HeroGBufferFragment(Varyings input)
{
ApplyHeroCutout(input.positionCS);
return LitGBufferPassFragment(input);
}
ENDHLSL
}
@@ -540,12 +551,36 @@ Shader "Custom/HeroCutoutLit"
ColorMask RG
HLSLPROGRAM
// The cutout MUST also apply here: this pass has ZWrite On (default) and external
// consumers draw it against the LIVE camera depth attachment BEFORE the skybox
// (HTrace WSGI's object-motion-vectors pass at AfterRenderingOpaques). Without the
// clip it re-fills the hole with occluder depth -> the skybox fails ZTest inside the
// hole -> black disc, and the corrupted depth leaks into _CameraDepthTexture (SSAO/GI).
//
// ObjectMotionVectors.hlsl hardcodes "#pragma fragment frag" via include_with_pragmas,
// so we declare the pragmas ourselves and plain-#include it (plain includes contribute
// no pragmas), then wrap its frag().
#pragma target 3.5
#pragma vertex vert
#pragma fragment HeroMotionVectorsFragment
#pragma shader_feature_local _ALPHATEST_ON
#pragma multi_compile _ LOD_FADE_CROSSFADE
#pragma shader_feature_local_vertex _ADD_PRECOMPUTED_VELOCITY
#pragma multi_compile_instancing
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ObjectMotionVectors.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ObjectMotionVectors.hlsl"
#include "HeroCutout.hlsl"
float4 HeroMotionVectorsFragment(Varyings input) : SV_Target
{
ApplyHeroCutout(input.positionCS);
return frag(input);
}
ENDHLSL
}