150 lines
5.4 KiB
C#
150 lines
5.4 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.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<Capsule>());
|
|
}
|
|
|
|
if (characterDataBuffer == null || characterDataBuffer.count != characterArray.Length)
|
|
{
|
|
characterDataBuffer?.Release();
|
|
characterDataBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, characterArray.Length, UnsafeUtility.SizeOf<Character>());
|
|
}
|
|
|
|
if (capsuleShadowDataBuffer == null || capsuleShadowDataBuffer.count != capsuleAOSettingArray.Length)
|
|
{
|
|
capsuleShadowDataBuffer?.Release();
|
|
capsuleShadowDataBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, capsuleAOSettingArray.Length, UnsafeUtility.SizeOf<CapsuleShadowAreaSetting>());
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
}
|