122 lines
5.2 KiB
C#
Raw Normal View History

using System;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
2025-07-17 17:21:42 +08:00
using static UnityEngine.Rendering.Universal.UniversalRenderPipeline.Profiling.Pipeline;
namespace X.Rendering.Feature
{
public class SoftShadowMask : ScriptableRendererFeature
{
[Serializable]
private class Settings
{
public bool BlurMask = false;
public Material MaskMat = null;
public Material BlurMat = null;
2025-07-17 17:21:42 +08:00
public int BlurIterations = 3;
public float BlurSpread = 0.6f;
}
[SerializeField]
private Settings settings = new();
SoftShadowMaskPass shadowMaskPass;
public override void Create()
{
shadowMaskPass = new(settings);
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
renderer.EnqueuePass(shadowMaskPass);
}
class SoftShadowMaskPass : ScriptableRenderPass
{
internal static readonly int SoftShadowMaskTextureId = Shader.PropertyToID("_SoftShadowMaskTexture");
internal static readonly GlobalKeyword softShadowMaskKeyword = GlobalKeyword.Create("_SOFTSHADOW_MASK");
private Settings settings;
private ProfilingSampler profiler;
2025-07-17 17:21:42 +08:00
Vector4[] offsetArray = new Vector4[4];
RTHandle softShadowMask;
2025-07-17 17:21:42 +08:00
RTHandle buffer0;
RTHandle buffer1;
public SoftShadowMaskPass(Settings settings)
{
this.settings = settings;
renderPassEvent = RenderPassEvent.AfterRenderingPrePasses;
profiler = new(nameof(SoftShadowMaskPass));
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
var cmd = renderingData.commandBuffer;
using var scp = new ProfilingScope(cmd, profiler);
cmd.EnableKeyword(softShadowMaskKeyword);
var w = renderingData.cameraData.cameraTargetDescriptor.width;
var h = renderingData.cameraData.cameraTargetDescriptor.height;
float2 wh = new float2 { x = w, y = h };
{
2025-07-17 17:21:42 +08:00
offsetArray[0] = new float4(new float2(-1, 1) / wh, new float2(1, 1) / wh);
offsetArray[1] = new float4(new float2(-1, -1) / wh, new float2(1, -1) / wh);
offsetArray[2] = new float4(new float2(-2, -2) / wh, new float2(2, 2) / wh);
offsetArray[3] = new float4(new float2(-2, 2) / wh, new float2(2, -2) / wh);
cmd.SetGlobalVectorArray("_Offset5", offsetArray);
}
2025-07-17 17:21:42 +08:00
cmd.SetGlobalVector("_MaskSizeAndInvRenderSize", new Vector4(w / 4, h / 4, 1f / w, 1f / h));
var desc = new RenderTextureDescriptor()
{
bindMS = false,
colorFormat = RenderTextureFormat.R8,
width = w / 4,
height = h / 4,
enableRandomWrite = false,
2025-07-17 17:21:42 +08:00
depthBufferBits = 0,
dimension = TextureDimension.Tex2D,
msaaSamples = 1,
2025-07-17 17:21:42 +08:00
};
RenderingUtils.ReAllocateIfNeeded(ref softShadowMask, desc);
cmd.SetGlobalTexture("_CameraDepthTexture", renderingData.cameraData.renderer.cameraDepthTargetHandle);
cmd.SetRenderTarget(softShadowMask);
cmd.DrawProcedural(Matrix4x4.identity, settings.MaskMat, 0, MeshTopology.Triangles, 3);
2025-07-17 17:21:42 +08:00
if (settings.BlurMask)
{
cmd.BeginSample("SoftShadowMask Blur");
//desc.memoryless = RenderTextureMemoryless.Color;
RenderingUtils.ReAllocateIfNeeded(ref buffer0, desc, name: "buffer0");
RenderingUtils.ReAllocateIfNeeded(ref buffer1, desc, name: "buffer1");
cmd.SetGlobalTexture("_MainTex", softShadowMask);
for (int i = 0; i < settings.BlurIterations; i++)
{
settings.BlurMat.SetFloat("_BlurSize", i * settings.BlurSpread);
cmd.SetRenderTarget(buffer0);
cmd.DrawProcedural(Matrix4x4.identity, settings.BlurMat, 0, MeshTopology.Triangles, 3);
cmd.SetGlobalTexture("_MainTex", buffer0);
cmd.SetRenderTarget(buffer1);
cmd.DrawProcedural(Matrix4x4.identity, settings.BlurMat, 1, MeshTopology.Triangles, 3);
cmd.SetGlobalTexture("_MainTex", buffer1);
}
cmd.EndSample("SoftShadowMask Blur");
cmd.SetGlobalTexture(SoftShadowMaskTextureId, buffer1);
}
else
{
cmd.SetGlobalTexture(SoftShadowMaskTextureId, softShadowMask);
}
}
public override void OnFinishCameraStackRendering(CommandBuffer cmd)
{
base.OnFinishCameraStackRendering(cmd);
cmd.DisableKeyword(softShadowMaskKeyword);
}
}
}
}