2025-08-01 16:36:17 +08:00

131 lines
4.9 KiB
C#

using System;
using System.Runtime.InteropServices;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace X.Rendering.Feature
{
[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 startID, endID;
}
public class CapsuleAO : ScriptableRendererFeature
{
[Serializable]
public class Settings
{
public RenderPassEvent RenderPassEvent = RenderPassEvent.BeforeRenderingTransparents;
public float AmbientIntensity = 0.2f;
public float ShadowIntensity = 0.4f;
public float ShadowSharpness = 20;
[Range(1, 90)]
public float ConeAngle = 1;
public Material CapsuleAOMat;
}
[SerializeField]
Settings settings;
CapsuleAOPass capsuleAOPass;
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
{
renderer.EnqueuePass(capsuleAOPass);
}
}
public override void Create()
{
capsuleAOPass = new(settings);
}
class CapsuleAOPass : ScriptableRenderPass, IDisposable
{
private Settings settings;
private GraphicsBuffer capsuleDataBuffer;
private GraphicsBuffer characterDataBuffer;
private ProfilingSampler profiler;
public CapsuleAOPass(Settings settings)
{
this.settings = settings;
profiler = new (nameof(CapsuleAOPass));
renderPassEvent = settings.RenderPassEvent;
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
base.Configure(cmd, cameraTextureDescriptor);
ConfigureInput(ScriptableRenderPassInput.Depth | ScriptableRenderPassInput.Normal);
}
public void Dispose()
{
capsuleDataBuffer?.Dispose();
capsuleDataBuffer = null;
characterDataBuffer?.Dispose();
characterDataBuffer = null;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (!XRenderFeatureManager.Instance)
{
return;
}
ref var characterArray = ref XRenderFeatureManager.Instance.CharacterArray;
ref var capsuleArray = ref XRenderFeatureManager.Instance.CapsuleArray;
if (!capsuleArray.IsCreated)
{
return;
}
if(capsuleDataBuffer == null || capsuleDataBuffer.count != capsuleArray.Length)
{
capsuleDataBuffer?.Release();
capsuleDataBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capsuleArray.Length, UnsafeUtility.SizeOf<Capsule>());
}
if (characterDataBuffer == null || characterDataBuffer.count != characterArray.Length)
{
characterDataBuffer?.Release();
characterDataBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, characterArray.Length, UnsafeUtility.SizeOf<Character>());
}
capsuleDataBuffer.SetData(capsuleArray);
characterDataBuffer.SetData(characterArray);
var cmd = renderingData.commandBuffer;
using var scp = new ProfilingScope(cmd, profiler);
cmd.SetGlobalBuffer("_CapsuleData", capsuleDataBuffer);
cmd.SetGlobalBuffer("_CharacterData", characterDataBuffer);
cmd.SetGlobalInt("_CapsulesCount", capsuleArray.Length);
cmd.SetGlobalInt("_CharactersCount", characterArray.Length);
cmd.SetGlobalFloat("_AmbientIntensity", settings.AmbientIntensity);
cmd.SetGlobalFloat("_ShadowIntensity", settings.ShadowIntensity);
cmd.SetGlobalFloat("_ShadowSharpness", settings.ShadowSharpness);
cmd.SetGlobalFloat("_ConeAngle", settings.ConeAngle);
var renderer = renderingData.cameraData.renderer;
cmd.SetRenderTarget(renderer.cameraColorTargetHandle, loadAction: RenderBufferLoadAction.Load, storeAction: RenderBufferStoreAction.Store);
cmd.DrawProcedural(Matrix4x4.identity, settings.CapsuleAOMat, 0, MeshTopology.Triangles, 3);
}
}
}
}