Files
Cielonos/Assets/PotaToon/Runtime/Scripts/CharacterShadowPass.cs
SoulliesOfficial f7af60351b 阶段性完成
2025-12-08 05:27:53 -05:00

235 lines
12 KiB
C#

using System;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
#if UNITY_6000_0_OR_NEWER
using UnityEngine.Rendering.RenderGraphModule;
#endif
namespace PotaToon
{
public class CharacterShadowPass : ScriptableRenderPass
{
/* ID */
private static readonly ShaderTagId k_ShaderTagId = new ShaderTagId("CharacterDepth");
/* Member Variables */
private RTHandle m_CharShadowRT;
private ProfilingSampler m_ProfilingSampler;
private PassData m_PassData;
private static int[] s_TextureSize = new int[2] { 1, 1 };
private ToonCharacterShadow m_CBuffer;
public CharacterShadowPass(string featureName)
{
m_PassData = new PassData();
renderPassEvent = RenderPassEvent.BeforeRenderingPrePasses;
m_ProfilingSampler = new ProfilingSampler(featureName);
}
public void Dispose()
{
m_CharShadowRT?.Release();
#if UNITY_2021_3
ConstantBuffer.ReleaseAll();
#endif
}
public void Setup(in RenderingData renderingData, PotaToon volume)
{
m_CBuffer = new ToonCharacterShadow();
m_PassData.enabled = true;
m_PassData.bias = new Vector3(volume.bias.value * PotaToon.k_BiasScale, volume.normalBias.value * 0.01f, 0f);
var scale = (int)volume.textureScale.value;
m_PassData.cascadeResolutionScale = 1.0f;
m_PassData.cascadeMaxDistance = CharacterShadowUtils.GetCullingDistance(renderingData.cameraData.camera, volume.shadowCullingDistance.value);
s_TextureSize[0] = 1024 * scale;
s_TextureSize[1] = 1024 * scale;
m_PassData.useBrightestLight = volume.mode.value == PotaToonMode.Concert;
m_PassData.followLightLayer = volume.followLayerMask.value;
m_PassData.maxToonBrightness = volume.maxToonBrightness.value;
CharacterShadowUtils.shadowCamera.lightDirectionOffset = volume.mode.value == PotaToonMode.Normal ? volume.charShadowDirOffset.value : Vector3.zero;
CharacterShadowUtils.shadowCamera.overrideLightDirection = volume.mode.value == PotaToonMode.Normal && volume.charShadowDirOffsetMode.value == LightOffsetMode.World;
}
private static void UpdateConstantBuffer_Internal(ref ToonCharacterShadow cb, PassData passData, in CharacterShadowUtils.BrightestLightData brightestLightData)
{
var shadowCamera = CharacterShadowUtils.shadowCamera;
var textureScale = s_TextureSize[0] / 1024;
float softShadowSamples = Mathf.Clamp((int)Mathf.Log(textureScale, 2) + 1, 2, 4);
if (shadowCamera != null)
{
passData.projectM = shadowCamera.projectionMatrix;
passData.viewM = shadowCamera.GetViewMatrix();
if (shadowCamera.distanceCameraToNearestRenderer > 0.5f)
softShadowSamples = Mathf.Max(softShadowSamples - 1f, 2f);
}
float invShadowMapWidth = 1.0f / s_TextureSize[0];
float invShadowMapHeight = 1.0f / s_TextureSize[1];
float invHalfShadowMapWidth = 0.5f * invShadowMapWidth;
float invHalfShadowMapHeight = 0.5f * invShadowMapHeight;
cb._BrightestLightDirection = brightestLightData.lightDirection;
cb._BrightestLightIndex = (uint)brightestLightData.lightIndex;
cb._CharShadowParams = new Vector4(passData.bias.x, passData.bias.y, 0, 0);
cb._CharShadowViewProjM = passData.projectM * passData.viewM;
cb._CharShadowOffset0 = new Vector4(-invHalfShadowMapWidth, -invHalfShadowMapHeight, invHalfShadowMapWidth, -invHalfShadowMapHeight);
cb._CharShadowOffset1 = new Vector4(-invHalfShadowMapWidth, invHalfShadowMapHeight, invHalfShadowMapWidth, invHalfShadowMapHeight);
cb._CharShadowmapSize = new Vector4(invShadowMapWidth, invShadowMapHeight, s_TextureSize[0], s_TextureSize[1]);
invShadowMapWidth = 1.0f / TransparentShadowPass.s_TextureSize[0];
invShadowMapHeight = 1.0f / TransparentShadowPass.s_TextureSize[1];
cb._CharTransparentShadowmapSize = new Vector4(invShadowMapWidth, invShadowMapHeight, TransparentShadowPass.s_TextureSize[0], TransparentShadowPass.s_TextureSize[1]);
var rcpMaxBoundSize = 1.0f / CharacterShadowUtils.shadowCamera.maxBoundSize;
cb._CharShadowCascadeParams = new Vector4(passData.cascadeMaxDistance, passData.cascadeResolutionScale, softShadowSamples, rcpMaxBoundSize);
cb._UseBrightestLight = passData.useBrightestLight ? 1u : 0u;
cb._IsBrightestLightMain = brightestLightData.isMainLight ? 1u : 0u;
cb._MaxToonBrightness = passData.maxToonBrightness;
}
private static void UpdateConstantBuffer(ref ToonCharacterShadow cb, PassData passData, ref RenderingData renderingData)
{
CharacterShadowUtils.GetBrightestLightData(ref renderingData, passData.useBrightestLight, passData.followLightLayer, out var brightestLightData);
UpdateConstantBuffer_Internal(ref cb, passData, brightestLightData);
}
private RenderTextureDescriptor GetRenderTextureDescriptor()
{
var descriptor = new RenderTextureDescriptor(s_TextureSize[0], s_TextureSize[1], RenderTextureFormat.RG32, 0);
descriptor.dimension = TextureDimension.Tex2D;
descriptor.sRGB = false;
descriptor.depthStencilFormat = GraphicsFormat.None;
descriptor.msaaSamples = 1;
return descriptor;
}
private class PassData
{
public bool enabled;
public Matrix4x4 viewM;
public Matrix4x4 projectM;
public float maxToonBrightness;
public Vector3 bias;
public bool useBrightestLight;
public LayerMask followLightLayer;
public float cascadeMaxDistance;
public float cascadeResolutionScale;
#if UNITY_6000_0_OR_NEWER
// RenderGraph Path
public RendererListHandle rendererList;
public ToonCharacterShadow cb;
#endif
}
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
// Allocate Char Shadowmap
RenderingUtils.ReAllocateIfNeeded(ref m_CharShadowRT, GetRenderTextureDescriptor(), FilterMode.Bilinear, name:"CharShadowMap");
cmd.SetGlobalTexture(ShaderIDs._CharShadowMap, m_CharShadowRT);
}
#if !UNITY_2021_3
private static void ExecutePass(CommandBuffer cmd, RendererList rendererList)
{
cmd.DrawRendererList(rendererList);
}
#endif
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, m_ProfilingSampler))
{
var filteringSettings = new FilteringSettings(RenderQueueRange.opaque);
var drawSettings = RenderingUtils.CreateDrawingSettings(k_ShaderTagId, ref renderingData, SortingCriteria.CommonOpaque);
UpdateConstantBuffer(ref m_CBuffer, m_PassData, ref renderingData);
ConstantBuffer.PushGlobal(cmd, m_CBuffer, ShaderIDs._ToonCharacterShadow);
CoreUtils.SetRenderTarget(cmd, m_CharShadowRT, ClearFlag.Color, 0, CubemapFace.Unknown, 0);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
#if UNITY_2021_3
var rendererListDesc = new UnityEngine.Rendering.RendererUtils.RendererListDesc(k_ShaderTagId, renderingData.cullResults, renderingData.cameraData.camera);
rendererListDesc.sortingCriteria = SortingCriteria.CommonOpaque;
rendererListDesc.renderQueueRange = RenderQueueRange.opaque;
cmd.DrawRendererList(context.CreateRendererList(rendererListDesc));
#else
var param = new RendererListParams(renderingData.cullResults, drawSettings, filteringSettings);
ExecutePass(cmd, context.CreateRendererList(ref param));
#endif
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
#if UNITY_6000_0_OR_NEWER
#region RenderGraph
private static void UpdateConstantBuffer(ref ToonCharacterShadow cb, PassData passData, UniversalLightData lightData)
{
CharacterShadowUtils.GetBrightestLightData(lightData, passData.useBrightestLight, passData.followLightLayer, out var brightestLightData);
UpdateConstantBuffer_Internal(ref cb, passData, brightestLightData);
}
private static void ExecutePass(RasterCommandBuffer cmd, RendererList rendererList)
{
cmd.DrawRendererList(rendererList);
}
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
{
var renderingData = frameData.Get<UniversalRenderingData>();
var lightData = frameData.Get<UniversalLightData>();
var cameraData = frameData.Get<UniversalCameraData>();
var drawSettings = RenderingUtils.CreateDrawingSettings(k_ShaderTagId, renderingData, cameraData, lightData, SortingCriteria.CommonOpaque);
TextureHandle output = UniversalRenderer.CreateRenderGraphTexture(renderGraph, GetRenderTextureDescriptor(), "CharShadowMap", true, FilterMode.Bilinear);
using (var builder = renderGraph.AddRasterRenderPass<PassData>("[PotaToon] Character Shadow", out var passData, m_ProfilingSampler))
{
builder.AllowGlobalStateModification(true);
builder.SetRenderAttachment(output, 0);
var param = new RendererListParams(renderingData.cullResults, drawSettings, new FilteringSettings(RenderQueueRange.opaque));
passData.rendererList = renderGraph.CreateRendererList(param);
builder.UseRendererList(passData.rendererList);
if (output.IsValid())
builder.SetGlobalTextureAfterPass(output, ShaderIDs._CharShadowMap);
passData.viewM = m_PassData.viewM;
passData.projectM = m_PassData.projectM;
passData.bias = m_PassData.bias;
passData.useBrightestLight = m_PassData.useBrightestLight;
passData.followLightLayer = m_PassData.followLightLayer;
passData.enabled = m_PassData.enabled;
passData.cascadeMaxDistance = m_PassData.cascadeMaxDistance;
passData.cascadeResolutionScale = m_PassData.cascadeResolutionScale;
passData.maxToonBrightness = m_PassData.maxToonBrightness;
passData.cb = new ToonCharacterShadow();
UpdateConstantBuffer(ref passData.cb, passData, lightData);
builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
{
ConstantBuffer.PushGlobal(data.cb, ShaderIDs._ToonCharacterShadow);
ExecutePass(context.cmd, data.rendererList);
});
}
}
#endregion
#endif
}
}