Implement frustum culling using job system

This commit is contained in:
2025-03-01 19:53:22 +08:00
parent 5f24e4c27d
commit e5f963e2e5
4 changed files with 177 additions and 6 deletions

View File

@@ -2,7 +2,9 @@ using Misaki.AoVolume;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Misaki.AoVolume.Shader;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
@@ -11,6 +13,7 @@ using UnityEngine.Rendering.HighDefinition;
internal class AoVolumePass : CustomPass
{
private NativeArray<OrientedBoundingBox> _volumeBounds;
private NativeList<VolumeData> _culledVolumeDatas;
private ComputeBuffer _volumeBoundsBuffer;
private ComputeBuffer _visibleIndicesBuffer;
private ComputeBuffer _visibleVolumeCountBuffer;
@@ -42,6 +45,7 @@ internal class AoVolumePass : CustomPass
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
{
_volumeBounds = new NativeArray<OrientedBoundingBox>(maxVolumeOnScreen, Allocator.Persistent);
_culledVolumeDatas = new NativeList<VolumeData>(maxVolumeOnScreen, Allocator.Persistent);
_volumeBoundsBuffer = new ComputeBuffer(maxVolumeOnScreen, Marshal.SizeOf<OrientedBoundingBox>());
_visibleIndicesBuffer = new ComputeBuffer(maxVolumeOnScreen, Marshal.SizeOf<uint>(), ComputeBufferType.Raw);
_visibleVolumeCountBuffer = new ComputeBuffer(1, Marshal.SizeOf<uint>(), ComputeBufferType.Counter);
@@ -58,13 +62,50 @@ internal class AoVolumePass : CustomPass
{
return Mathf.FloorToInt(Mathf.Log(Mathf.Min(hDCamera.actualWidth, hDCamera.actualHeight), 2)) - 1;
}
private void FrustumCulling(CustomPassContext ctx, ref int volumeCount)
{
Frustum cameraFrustum = ctx.hdCamera.frustum;
GPUFrustum frustum = new()
{
normal0 = cameraFrustum.planes[0].normal,
dist0 = cameraFrustum.planes[0].distance,
normal1 = cameraFrustum.planes[1].normal,
dist1 = cameraFrustum.planes[1].distance,
normal2 = cameraFrustum.planes[2].normal,
dist2 = cameraFrustum.planes[2].distance,
normal3 = cameraFrustum.planes[3].normal,
dist3 = cameraFrustum.planes[3].distance,
normal4 = cameraFrustum.planes[4].normal,
dist4 = cameraFrustum.planes[4].distance,
normal5 = cameraFrustum.planes[5].normal,
dist5 = cameraFrustum.planes[5].distance,
corner0 = cameraFrustum.corners[0],
corner1 = cameraFrustum.corners[1],
corner2 = cameraFrustum.corners[2],
corner3 = cameraFrustum.corners[3],
corner4 = cameraFrustum.corners[4],
corner5 = cameraFrustum.corners[5],
corner6 = cameraFrustum.corners[6],
corner7 = cameraFrustum.corners[7],
};
_culledVolumeDatas.Clear();
FrustumCullingJob cullingJob = new()
{
GPUFrustum = frustum,
InputVolumeDatas = VolumeDatabase.Instance.VolumeDatas,
InputVolumeBounds = _volumeBounds,
OutputVolumeDataWriter = _culledVolumeDatas.AsParallelWriter()
};
JobHandle cullingJobHandle = cullingJob.Schedule(volumeCount, 64);
cullingJobHandle.Complete();
volumeCount = _culledVolumeDatas.Length;
}
private void HierarchicalZCulling(CustomPassContext ctx, int volumeCount)
{
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);
@@ -81,7 +122,7 @@ internal class AoVolumePass : CustomPass
private void RenderVisibleVolumes(CustomPassContext ctx)
{
_volumeDataBuffer.SetData(VolumeDatabase.Instance.VolumeDatas);
_volumeDataBuffer.SetData(_culledVolumeDatas.AsArray());
ctx.cmd.SetComputeBufferParam(renderingShader, 0, "_VolumeDatas", _volumeDataBuffer);
ctx.cmd.SetComputeBufferParam(renderingShader, 0, "_VisibleVolumeCount", _visibleVolumeCountBuffer);
@@ -140,6 +181,7 @@ internal class AoVolumePass : CustomPass
return;
}
FrustumCulling(ctx, ref volumeCount);
HierarchicalZCulling(ctx, volumeCount);
RenderVisibleVolumes(ctx);
//DebugVisibleVolumes();
@@ -149,6 +191,7 @@ internal class AoVolumePass : CustomPass
protected override void Cleanup()
{
_volumeBounds.Dispose();
_culledVolumeDatas.Dispose();
_volumeBoundsBuffer?.Dispose();
_visibleIndicesBuffer?.Dispose();
_visibleVolumeCountBuffer?.Dispose();