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 _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(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 ConfigureTarget and ConfigureClear. // 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(64, Allocator.Persistent); _volumeBoundsBuffer = new ComputeBuffer(64, Marshal.SizeOf()); _visibleIndicesBuffer = new ComputeBuffer(64, Marshal.SizeOf(), ComputeBufferType.Raw); _visibleVolumeCountBuffer = new ComputeBuffer(1, Marshal.SizeOf(), ComputeBufferType.Counter); _volumeDataBuffer = new ComputeBuffer(64, Marshal.SizeOf()); _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.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.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; } }