Files
com.misaki.ao-volume/Runtime/CustomPass/AoVolumePass.cs
2025-02-22 03:04:15 +09:00

153 lines
5.6 KiB
C#

using Misaki.AoVolume;
using System.Buffers;
using System.Runtime.InteropServices;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
internal class AoVolumePass : CustomPass
{
private bool _initialized;
private NativeArray<OrientedBoundingBox> _volumeBounds;
private ComputeBuffer _volumeBoundsBuffer;
private ComputeBuffer _visibleIndicesBuffer;
private ComputeBuffer _visibleVolumeCountBuffer;
private ComputeBuffer _volumeDataBuffer;
private RTHandle _volumeBuffer;
[ResourcePath("Packages/com.misaki.ao-volume/Runtime/Shader/HzCulling.compute")]
public ComputeShader cullingShader;
[ResourcePath("Packages/com.misaki.ao-volume/Runtime/Shader/AoVolume.compute")]
public ComputeShader renderingShader;
private void ClearVisibleVolumeCounter()
{
var zeroBuffer = new NativeArray<uint>(1, Allocator.Temp);
zeroBuffer[0] = 0;
_visibleVolumeCountBuffer.SetData(zeroBuffer);
zeroBuffer.Dispose();
}
// It can be used to configure render targets and their clear state. Also to create temporary render target textures.
// When empty this render pass will render to the active camera render target.
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
// The render pipeline will ensure target setup and clearing happens in an performance manner.
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
{
if (_initialized)
{
return;
}
_volumeBounds = new NativeArray<OrientedBoundingBox>(64, Allocator.Persistent);
_volumeBoundsBuffer = new ComputeBuffer(64, Marshal.SizeOf<OrientedBoundingBox>());
_visibleIndicesBuffer = new ComputeBuffer(64, Marshal.SizeOf<uint>(), ComputeBufferType.Raw);
_visibleVolumeCountBuffer = new ComputeBuffer(1, Marshal.SizeOf<uint>(), ComputeBufferType.Counter);
_volumeDataBuffer = new ComputeBuffer(64, Marshal.SizeOf<VolumeData>());
_volumeBuffer = RTHandles.Alloc(Vector2.one, useDynamicScale: true, dimension: TextureXR.dimension, enableRandomWrite: true, format: GraphicsFormat.R8_UNorm, name: "AO Volume Buffer");
ClearVisibleVolumeCounter();
_initialized = true;
}
protected override void Execute(CustomPassContext ctx)
{
if (!_initialized)
{
return;
}
if (cullingShader == null || renderingShader == null)
{
return;
}
// Worth it to allocate a new buffer?
//if (Shader.GetGlobalTexture("_AmbientOcclusionTexture") is not RenderTexture gtaoBuffer)
//{
// return;
//}
var volumeCount = VolumeDatabase.Instance.EntityCount;
if (volumeCount <= 0)
{
return;
}
const int groupSizeX = 8;
const int groupSizeY = 8;
var threadGroupX = (ctx.hdCamera.actualWidth + (groupSizeX - 1)) / groupSizeX;
var threadGroupY = (ctx.hdCamera.actualHeight + (groupSizeY - 1)) / groupSizeY;
for (var i = 0; i < volumeCount; i++)
{
_volumeBounds[i] = new OrientedBoundingBox(VolumeDatabase.Instance.VolumeDatas[i].worldMatrix);
}
_volumeBoundsBuffer.SetData(_volumeBounds);
ctx.cmd.SetComputeBufferParam(cullingShader, 0, "_VolumeBounds", _volumeBoundsBuffer);
ctx.cmd.SetComputeIntParam(cullingShader, "_FullVolumeCount", volumeCount);
ctx.cmd.SetComputeIntParam(cullingShader, "_DepthPyramidMaxMip", ctx.cameraDepthBuffer.rt.mipmapCount - 1);
ctx.cmd.SetComputeBufferParam(cullingShader, 0, "_VisibleVolumeIndices", _visibleIndicesBuffer);
ctx.cmd.SetComputeBufferParam(cullingShader, 0, "_VisibleVolumeCount", _visibleVolumeCountBuffer);
const int groupSize = 64;
var threadGroup = (volumeCount + (groupSize - 1)) / groupSize;
ctx.cmd.DispatchCompute(cullingShader, 0, threadGroup, 1, 1);
// Debug
var visibleVolumeCount = new int[1];
_visibleVolumeCountBuffer.GetData(visibleVolumeCount);
Debug.Log($"Visible Volume Count: {visibleVolumeCount[0]}");
var visibleVolumeIndices = ArrayPool<uint>.Shared.Rent(64);
_visibleIndicesBuffer.GetData(visibleVolumeIndices);
for (var i = 0; i < visibleVolumeCount[0]; i++)
{
if (i >= 64)
{
break;
}
Debug.Log($"Visible Volume Index: {visibleVolumeIndices[i]}");
}
Debug.Log("End");
ArrayPool<uint>.Shared.Return(visibleVolumeIndices);
ClearVisibleVolumeCounter();
//return;
//_volumeDataBuffer.SetData(VolumeDatabase.Instance.VolumeDatas);
//ctx.cmd.SetComputeBufferParam(renderingShader, 0, "_VolumeDatas", _volumeDataBuffer);
//ctx.cmd.SetComputeIntParam(renderingShader, "_VolumeCount", volumeCount);
//ctx.cmd.SetComputeTextureParam(renderingShader, 0, "_AOVolumeBuffer", _volumeBuffer);
//ctx.cmd.DispatchCompute(renderingShader, 0, threadGroupX, threadGroupY, _volumeBuffer.rt.volumeDepth);
//ctx.cmd.SetGlobalTexture("_AmbientOcclusionTexture", _volumeBuffer);
}
protected override void Cleanup()
{
_volumeBounds.Dispose();
_volumeBoundsBuffer?.Dispose();
_visibleIndicesBuffer?.Dispose();
_visibleVolumeCountBuffer?.Dispose();
_volumeDataBuffer?.Dispose();
_volumeBuffer?.Release();
_initialized = false;
}
}