using System; using System.Runtime.InteropServices; using Unity.Collections.LowLevel.Unsafe; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; namespace X.Rendering.Scene { [StructLayout(LayoutKind.Sequential)] public struct Capsule { public Vector3 a, b; public float radius; } [StructLayout(LayoutKind.Sequential)] public struct Character { public Vector3 position; public float radius; //public Vector4 lightDir; //xyz:lightDir, w:根据 lightColor 算个系数 public int capsuleStartID, capsuleEndID; public uint capsuleAOSettingMask; } [StructLayout(LayoutKind.Sequential), Serializable] public struct CapsuleShadowAreaSetting { public float AmbientIntensity; //[Range(1, 90)] public float ConeAngle; public float ShadowIntensity; public float ShadowSharpness; public int lightStartID, lightEndID; public static CapsuleShadowAreaSetting GetDefault() { return new CapsuleShadowAreaSetting() { AmbientIntensity = 0.2f, ShadowIntensity = 0.4f, ShadowSharpness = 20, ConeAngle = 1 }; } } [Serializable] public class LightData { public Vector3 lightPosition; public float lightIntensity = 1; public bool isPointLight = true; } internal class CapsuleShadowPass : ScriptableRenderPass, IDisposable { [Serializable] public class CapsuleShadowSettings { public bool Enable = true; public RenderPassEvent RenderPassEvent = RenderPassEvent.BeforeRenderingTransparents; } private CapsuleShadowSettings settings; private readonly SceneEffect sceneEffect; private GraphicsBuffer capsuleDataBuffer; private GraphicsBuffer characterDataBuffer; private GraphicsBuffer capsuleShadowDataBuffer; private ProfilingSampler profiler; private CommandBuffer commandBuffer; public CapsuleShadowPass(CapsuleShadowSettings settings, SceneEffect sceneEffect) { this.settings = settings; this.sceneEffect = sceneEffect; profiler = new(nameof(CapsuleShadowPass)); renderPassEvent = settings.RenderPassEvent; commandBuffer = new CommandBuffer(); commandBuffer.name = nameof(CapsuleShadowPass) + sceneEffect.name; } public void Dispose() { capsuleDataBuffer?.Dispose(); capsuleDataBuffer = null; characterDataBuffer?.Dispose(); characterDataBuffer = null; capsuleShadowDataBuffer?.Dispose(); capsuleShadowDataBuffer = null; commandBuffer.Dispose(); } public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { ref var characterArray = ref sceneEffect.CharacterArray; ref var capsuleArray = ref sceneEffect.CapsuleArray; ref var capsuleAOSettingArray = ref sceneEffect.CapsuleAOSettingArray; if (!capsuleArray.IsCreated || !capsuleAOSettingArray.IsCreated) { return; } if (capsuleDataBuffer == null || capsuleDataBuffer.count != capsuleArray.Length) { capsuleDataBuffer?.Release(); capsuleDataBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capsuleArray.Length, UnsafeUtility.SizeOf()); } if (characterDataBuffer == null || characterDataBuffer.count != characterArray.Length) { characterDataBuffer?.Release(); characterDataBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, characterArray.Length, UnsafeUtility.SizeOf()); } if (capsuleShadowDataBuffer == null || capsuleShadowDataBuffer.count != capsuleAOSettingArray.Length) { capsuleShadowDataBuffer?.Release(); capsuleShadowDataBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capsuleAOSettingArray.Length, UnsafeUtility.SizeOf()); } capsuleDataBuffer.SetData(capsuleArray); characterDataBuffer.SetData(characterArray); var cmd = commandBuffer; using var scp = new ProfilingScope(cmd, profiler); cmd.SetGlobalBuffer("_CapsuleData", capsuleDataBuffer); cmd.SetGlobalBuffer("_CharacterData", characterDataBuffer); capsuleShadowDataBuffer.SetData(capsuleAOSettingArray); cmd.SetGlobalBuffer("_CapsuleShadowData", capsuleShadowDataBuffer); cmd.SetGlobalInt("_CapsuleShadowDataCount", capsuleAOSettingArray.Length); cmd.SetGlobalInt("_CapsulesCount", capsuleArray.Length); cmd.SetGlobalInt("_CharactersCount", characterArray.Length); cmd.SetGlobalInt("_CapsuleLightsCount", sceneEffect.CapsuleLightsDirCount); if(sceneEffect.CapsuleLightsDirCount > 0) { cmd.SetGlobalVectorArray("_CapsuleLightsDir", sceneEffect.CapsuleLightsDir); } context.ExecuteCommandBuffer(cmd); cmd.Clear(); } } }