From 442f4f363e8b6fb6cb9e086ef281996c75a814b0 Mon Sep 17 00:00:00 2001 From: BlueRose <378100977@qq.com> Date: Thu, 12 Dec 2024 23:06:32 +0800 Subject: [PATCH] vault backup: 2024-12-12 23:06:32 --- .../渲染功能/阴影控制/ToonShadow.md | 316 +++++++++++++++++- 1 file changed, 315 insertions(+), 1 deletion(-) diff --git a/03-UnrealEngine/卡通渲染相关资料/渲染功能/阴影控制/ToonShadow.md b/03-UnrealEngine/卡通渲染相关资料/渲染功能/阴影控制/ToonShadow.md index 70946d1..965ba0a 100644 --- a/03-UnrealEngine/卡通渲染相关资料/渲染功能/阴影控制/ToonShadow.md +++ b/03-UnrealEngine/卡通渲染相关资料/渲染功能/阴影控制/ToonShadow.md @@ -218,7 +218,7 @@ void FSceneRenderer::InitDynamicShadows(FRHICommandListImmediate& RHICmdList, FG - **FProjectedShadowInfo::RenderTranslucencyDepths** ## RenderDepth -MeshDrawProcessor为***FShadowDepthPassMeshProcessor***。渲染的Shader为ShadowDepthPixelShader.usf +MeshDrawProcessor为***FShadowDepthPassMeshProcessor***。渲染的Shader为***ShadowDepthPixelShader.usf*** ```c++ void FProjectedShadowInfo::RenderDepth( FRDGBuilder& GraphBuilder, @@ -438,7 +438,321 @@ bool FShadowDepthPassMeshProcessor::TryAddMeshBatch(const FMeshBatch& RESTRICT M } ``` +## Shader +VertexShader为:ShadowDepthVertexShader.usf,有4种变体: +- IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_PerspectiveCorrect); +- IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_OutputDepth); +- IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_OnePassPointLight); +- IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_VirtualShadowMap); +PixelShader为:***ShadowDepthPixelShader.usf***,有4种变体: +- IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_NonPerspectiveCorrect); +- IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_PerspectiveCorrect); +- IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_OnePassPointLight); +- IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_VirtualShadowMap); +使用对应的Shader逻辑位于GetShadowDepthPassShaders()。只有非方向光同时不是OnePass的状态下会使用**PerspectiveCorrect**。 +```c++ +void SetShadowDepthOutputs( + float4x4 WorldToClipMatrix, + float4x4 WorldToShadowMatrix, + float4 WorldPosition, + float3 WorldVertexNormal, + out float4 OutPosition, + out float ShadowDepth +#if PERSPECTIVE_CORRECT_DEPTH + , out float OutDepthBias +#endif +) +{ + OutPosition = mul(WorldPosition, WorldToClipMatrix); + + // Clamp the vertex to the near plane if it is in front of the near plane + // This has problems if some vertices of a triangle get clamped and others do not, also causes artifacts with non-ortho projections + if (PassStruct.bClampToNearPlane > 0 && OutPosition.z > OutPosition.w) + { + OutPosition.z = 0.999999f; + OutPosition.w = 1.0f; + } + + #if ONEPASS_POINTLIGHT_SHADOW + const float3 ViewDirection = -normalize(mul(WorldPosition, WorldToShadowMatrix).xyz); + const float3 ViewNormal = mul(float4(WorldVertexNormal,0), WorldToShadowMatrix).xyz; + const float NoL = abs(dot(ViewDirection, ViewNormal)); + #else + const float NoL = abs(dot( + float3(WorldToShadowMatrix[0].z, WorldToShadowMatrix[1].z, WorldToShadowMatrix[2].z), + WorldVertexNormal)); + #endif + + const float MaxSlopeDepthBias = PassStruct.ShadowParams.z; + const float Slope = clamp(abs(NoL) > 0 ? sqrt(saturate(1 - NoL*NoL)) / NoL : MaxSlopeDepthBias, 0, MaxSlopeDepthBias); + + const float SlopeDepthBias = PassStruct.ShadowParams.y; + const float SlopeBias = SlopeDepthBias * Slope; + + const float ConstantDepthBias = PassStruct.ShadowParams.x; + const float DepthBias = SlopeBias + ConstantDepthBias; + + #if PERSPECTIVE_CORRECT_DEPTH + ShadowDepth = OutPosition.z; + OutDepthBias = DepthBias; + #elif ONEPASS_POINTLIGHT_SHADOW + ShadowDepth = 0; + //OutPosition.z += DepthBias; + #else + // Output linear, normalized depth + const float InvMaxSubjectDepth = PassStruct.ShadowParams.w; + #if PLATFORM_NEEDS_PRECISE_SHADOW_DEPTH + precise + #endif + float AdjustedDepth = ( 1 - OutPosition.z * InvMaxSubjectDepth ) + DepthBias; + ShadowDepth = AdjustedDepth; + OutPosition.z = AdjustedDepth; + #endif +} + +void Main( + FVertexFactoryInput Input, +#if ONEPASS_POINTLIGHT_SHADOW + out FShadowDepthVSToPS OutParameters, +#else + out FShadowDepthVSToPS OutParameters, +#endif +#if VIRTUAL_SM_ENABLED + out nointerpolation uint PackedPageInfo : TEXCOORD8, +#endif + out float4 OutPosition : SV_POSITION +#if ONEPASS_POINTLIGHT_SHADOW + , out uint LayerIndex : SV_RenderTargetArrayIndex +#endif +#if VIRTUAL_SM_ENABLED + // OLA-TODO: this collides with instanced stereo, which thankfully is not used with shadow maps, so should be fine, presumably. + , out float4 OutVirtualSmPageClip : SV_ClipDistance +#endif // VIRTUAL_SM_ENABLED + ) +{ + ResolvedView = ResolveView(); + + //计算FMaterialVertexParameters,最终获取顶点WorldPosition + FVertexFactoryIntermediates VFIntermediates = GetVertexFactoryIntermediates(Input); + float4 WorldPos = VertexFactoryGetWorldPosition(Input, VFIntermediates); + half3x3 TangentToLocal = VertexFactoryGetTangentToLocal(Input, VFIntermediates); + + FMaterialVertexParameters VertexParameters = GetMaterialVertexParameters(Input, VFIntermediates, WorldPos.xyz, TangentToLocal); + const float3 WorldNormal = VertexFactoryGetWorldNormal(Input, VFIntermediates); + + WorldPos.xyz += GetMaterialWorldPositionOffset(VertexParameters); + +#if ONEPASS_POINTLIGHT_SHADOW + + OutPosition = WorldPos; + + #if INTERPOLATE_VF_ATTRIBUTES + // Masked materials need texture coords to clip + OutParameters.FactoryInterpolants = VertexFactoryGetInterpolantsVSToPS(Input, VFIntermediates, VertexParameters); + #endif + + #if INTERPOLATE_POSITION + OutParameters.PixelPosition = WorldPos.xyz; + #endif + + LayerIndex = bUseGpuSceneInstancing ? VertexFactoryGetViewIndex(VFIntermediates) : LayerId; + OutPosition = mul(WorldPos, PassStruct.ShadowViewProjectionMatrices[LayerIndex]); + +#else + float Dummy; + + SetShadowDepthOutputs( + PassStruct.ProjectionMatrix, + PassStruct.ViewMatrix, + WorldPos, + WorldNormal, + OutPosition, +#if !PERSPECTIVE_CORRECT_DEPTH + Dummy +#else + OutParameters.ShadowDepth, + OutParameters.DepthBias +#endif + ); + + #if INTERPOLATE_VF_ATTRIBUTES + // Masked materials need texture coords to clip + OutParameters.FactoryInterpolants = VertexFactoryGetInterpolantsVSToPS(Input, VFIntermediates, VertexParameters); + #endif + + #if INTERPOLATE_POSITION + OutParameters.PixelPosition = WorldPos.xyz; + #endif + + #if !PERSPECTIVE_CORRECT_DEPTH && !COMPILER_SUPPORTS_EMPTY_STRUCTS + OutParameters.Dummy = 0; + #endif + +#endif + +#if VIRTUAL_SM_ENABLED + PackedPageInfo = 0; + + OutVirtualSmPageClip = float4(1.0f, 1.0f, 1.0f, 1.0f); + if (PassStruct.bRenderToVirtualShadowMap != 0) + { + // Get the offset from which we loaded the instance ID + uint InstanceIdIndex = VertexFactoryGetInstanceIdLoadIndex(VFIntermediates); + PackedPageInfo = InstanceCulling.PageInfoBuffer[InstanceIdIndex]; + + FPageInfo PageInfo = UnpackPageInfo(PackedPageInfo); + + TransformToVirtualSmPage(OutPosition, OutVirtualSmPageClip, PageInfo, WorldPos.xyz); + } +#endif // VIRTUAL_SM_ENABLED +} + +#if POSITION_ONLY +void PositionOnlyMain( + in FPositionAndNormalOnlyVertexFactoryInput Input, +#if ONEPASS_POINTLIGHT_SHADOW + out uint LayerIndex : SV_RenderTargetArrayIndex, +#endif + out FShadowDepthVSToPS OutParameters, + +#if VIRTUAL_SM_ENABLED + out nointerpolation uint PackedPageInfo : TEXCOORD8, +#endif + out float4 OutPosition : SV_POSITION +#if VIRTUAL_SM_ENABLED + // OLA-TODO: this collides with instanced stereo, which thankfully is not used with shadow maps, so should be fine, presumably. + , out float4 OutVirtualSmPageClip : SV_ClipDistance +#endif // VIRTUAL_SM_ENABLED + ) +{ + ResolvedView = ResolveView(); + + float4 WorldPos = VertexFactoryGetWorldPosition(Input); + +#if INTERPOLATE_VF_ATTRIBUTES + OutParameters.FactoryInterpolants = (FVertexFactoryInterpolantsVSToPS)0; +#endif + + float3 WorldNormal = VertexFactoryGetWorldNormal(Input); + +#if ONEPASS_POINTLIGHT_SHADOW + LayerIndex = bUseGpuSceneInstancing ? VertexFactoryGetViewIndex(Input) : LayerId; + OutPosition = mul(WorldPos, PassStruct.ShadowViewProjectionMatrices[LayerIndex]); + +#else // !ONEPASS_POINTLIGHT_SHADOW + float ShadowDepth; + SetShadowDepthOutputs( + PassStruct.ProjectionMatrix, + PassStruct.ViewMatrix, + WorldPos, + WorldNormal, + OutPosition, + #if PERSPECTIVE_CORRECT_DEPTH + OutParameters.ShadowDepth, + OutParameters.DepthBias + #else + ShadowDepth + #endif + ); + + #if !PERSPECTIVE_CORRECT_DEPTH && !COMPILER_SUPPORTS_EMPTY_STRUCTS + OutParameters.Dummy = 0; + #endif +#endif // ONEPASS_POINTLIGHT_SHADOW + +#if INTERPOLATE_POSITION + OutParameters.PixelPosition = WorldPos.xyz; +#endif + +#if VIRTUAL_SM_ENABLED + PackedPageInfo = 0; + + OutVirtualSmPageClip = float4(1.0f, 1.0f, 1.0f, 1.0f); + if (PassStruct.bRenderToVirtualShadowMap != 0) + { + // Get the offset from which we loaded the instance ID + uint InstanceIdIndex = VertexFactoryGetInstanceIdLoadIndex(Input); + // TODO: Maybe offset index to local buffer for this? We may not want to use a global since most passes are not supporting this + // Or perhaps both are different, as they are managed somewhat differently anyway, maybe. + PackedPageInfo = InstanceCulling.PageInfoBuffer[InstanceIdIndex]; + FPageInfo PageInfo = UnpackPageInfo(PackedPageInfo); + TransformToVirtualSmPage(OutPosition, OutVirtualSmPageClip, PageInfo, WorldPos.xyz); + } +#endif // VIRTUAL_SM_ENABLED +} + +#endif // POSITION_ONLY +``` + + +```c++ +void Main( + FShadowDepthVSToPS Inputs, +#if VIRTUAL_SM_ENABLED + nointerpolation uint PackedPageInfo : TEXCOORD8, +#endif + in float4 SvPosition : SV_Position // after all interpolators +#if PERSPECTIVE_CORRECT_DEPTH || COMPILER_METAL + ,out float OutDepth : SV_DEPTH +#endif + ) +{ + ResolvedView = ResolveView(); + +#if INTERPOLATE_VF_ATTRIBUTES + + FMaterialPixelParameters MaterialParameters = GetMaterialPixelParameters(Inputs.FactoryInterpolants, SvPosition);//取得材质中的PixelShader相关变量PixelMaterialInputs。 + FPixelMaterialInputs PixelMaterialInputs; + #if INTERPOLATE_POSITION + { + float4 ScreenPosition = SvPositionToResolvedScreenPosition(SvPosition); + + float3 TranslatedWorld = Inputs.PixelPosition.xyz; + + CalcMaterialParametersEx(MaterialParameters, PixelMaterialInputs, SvPosition, ScreenPosition, 1, TranslatedWorld, TranslatedWorld); + } + #else + CalcMaterialParameters(MaterialParameters, PixelMaterialInputs, SvPosition, 1); + #endif + + // Evaluate the mask for masked materials + GetMaterialClippingShadowDepth(MaterialParameters, PixelMaterialInputs); +#else + ClipLODTransition(SvPosition.xy); +#endif + +#if PERSPECTIVE_CORRECT_DEPTH + const float InvMaxSubjectDepth = PassStruct.ShadowParams.w; + Inputs.ShadowDepth = 1 - Inputs.ShadowDepth * InvMaxSubjectDepth; + Inputs.ShadowDepth += Inputs.DepthBias; + + OutDepth = saturate(Inputs.ShadowDepth); +#elif COMPILER_METAL + // Metal fragment shader must not be empty, + // so output depth value explicitly if this shader permuation was not discarded + OutDepth = SvPosition.z; +#endif + +#if ENABLE_NON_NANITE_VSM && VIRTUAL_TEXTURE_TARGET + uint2 vAddress = (uint2)SvPosition.xy; + float DeviceZ = SvPosition.z; + + FPageInfo PageInfo = UnpackPageInfo( PackedPageInfo ); + FNaniteView NaniteView = UnpackNaniteView( PassStruct.PackedNaniteViews[ PageInfo.ViewId ] ); + + FShadowPhysicalPage Page = ShadowDecodePageTable( PassStruct.VirtualSmPageTable[ CalcPageOffset( NaniteView.TargetLayerIndex, NaniteView.TargetMipLevel, vAddress >> VSM_LOG2_PAGE_SIZE ) ] ); + + if( Page.bThisLODValid ) + { + uint2 pAddress = Page.PhysicalAddress * VSM_PAGE_SIZE + (vAddress & VSM_PAGE_SIZE_MASK); + // If requested, render to the static page + const int ArrayIndex = PageInfo.bStaticPage ? GetVirtualShadowMapStaticArrayIndex() : 0; + InterlockedMax( PassStruct.OutDepthBufferArray[ uint3( pAddress, ArrayIndex ) ], asuint( DeviceZ ) ); + } +#endif +} +``` # Lights ### Shader ShadowProjectionPixelShader.usf