using UnityEditor; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; using UnityEngine.Rendering.RendererUtils; namespace Misaki.HdrpToon { [HideInInspector] internal class UTSHairShadowPass : DrawRenderersCustomPass { public enum ShadowQuality { Low, High } private const string Hair_Shadow_RTHandle_Scale_Prop_Name = "_HairShadowRTHandleScale"; private const string Hair_Shadow_Distance_Prop_Name = "_HairShadowDistance"; private const string Hair_Shadow_Distance_Scale_Prop_Name = "_HairShadowDistanceScaleFactor"; private const string Hair_Shadow_Depth_Bias_Prop_Name = "_HairShadowDepthBias"; private const string Hair_Shadow_FadeIn_Prop_Name = "_HairShadowFadeInDistance"; private const string Hair_Shadow_Fade_Out_Prop_Name = "_HairShadowFadeOutDistance"; private const string Output_RT_Name = "_HairShadowTex"; private RTHandle _outputRTHandle; private bool _needReallocate; private ShadowQuality _shadowQuality = ShadowQuality.High; internal ShadowQuality CurrentShadowQuality { get => _shadowQuality; set { if (_shadowQuality == value) { return; } _shadowQuality = value; _needReallocate = true; } } private bool ShouldReallocateBuffer() { return _outputRTHandle == null || _outputRTHandle.rt == null || !_outputRTHandle.rt.IsCreated() || _needReallocate; } private void ReallocateBuffer() { #if UNITY_EDITOR if (EditorApplication.isCompiling) { return; } #endif var scale = _shadowQuality switch { ShadowQuality.Low => new Vector2(0.5f, 0.5f), ShadowQuality.High => Vector2.one, _ => Vector2.zero }; var format = _shadowQuality switch { ShadowQuality.Low => GraphicsFormat.D16_UNorm, ShadowQuality.High => GraphicsFormat.D32_SFloat, _ => GraphicsFormat.D16_UNorm }; _outputRTHandle?.Release(); _outputRTHandle = RTHandles.Alloc(scale, colorFormat: format, filterMode: FilterMode.Bilinear, wrapMode: TextureWrapMode.Clamp, isShadowMap: true, name: Output_RT_Name); Shader.SetGlobalTexture(Output_RT_Name, _outputRTHandle); _needReallocate = false; } protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd) { ReallocateBuffer(); } protected override void Execute(CustomPassContext ctx) { if (ShouldReallocateBuffer()) { ReallocateBuffer(); return; } CoreUtils.SetRenderTarget(ctx.cmd, _outputRTHandle, ClearFlag.DepthStencil); var utsRenderer = ctx.hdCamera.volumeStack.GetComponent(); var shouldRender = utsRenderer != null && utsRenderer.enableHairShadow.value && utsRenderer.state.value; if (!shouldRender) { CoreUtils.ClearRenderTarget(ctx.cmd, ClearFlag.DepthStencil, Color.black); return; } var mask = RenderStateMask.Nothing; var stateBlock = new RenderStateBlock(mask) { depthState = new DepthState(true, CompareFunction.LessEqual), }; var result = new RendererListDesc(UtsShaderPassName.hairShadowCasterPassId, ctx.cullingResults, ctx.hdCamera.camera) { renderQueueRange = GetRenderQueueRange(RenderQueueType.All), sortingCriteria = SortingCriteria.CommonOpaque, excludeObjectMotionVectors = false, stateBlock = stateBlock, }; CoreUtils.DrawRendererList(ctx.renderContext, ctx.cmd, ctx.renderContext.CreateRendererList(result)); Shader.SetGlobalVector(Hair_Shadow_RTHandle_Scale_Prop_Name, _outputRTHandle.rtHandleProperties.rtHandleScale); Shader.SetGlobalFloat(Hair_Shadow_Distance_Prop_Name, utsRenderer.shadowDistance.value); Shader.SetGlobalFloat(Hair_Shadow_Distance_Scale_Prop_Name, utsRenderer.shadowDistanceScale.value); Shader.SetGlobalFloat(Hair_Shadow_Depth_Bias_Prop_Name, utsRenderer.shadowDepthBias.value); Shader.SetGlobalFloat(Hair_Shadow_FadeIn_Prop_Name, utsRenderer.shadowFadeIn.value); Shader.SetGlobalFloat(Hair_Shadow_Fade_Out_Prop_Name, utsRenderer.shadowFadeOut.value); } protected override void Cleanup() { Release(); } public void Release() { #if UNITY_EDITOR if (EditorApplication.isCompiling) { return; } #endif _outputRTHandle?.Release(); } } }