Start working on Cluster;
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
using Misaki.AoVolume;
|
using Misaki.AoVolume;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Unity.Collections;
|
using Unity.Collections;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -23,10 +24,13 @@ internal class AoVolumePass : CustomPass
|
|||||||
[ResourcePath("Packages/com.misaki.ao-volume/Runtime/Shader/AoVolume.compute")]
|
[ResourcePath("Packages/com.misaki.ao-volume/Runtime/Shader/AoVolume.compute")]
|
||||||
public ComputeShader renderingShader;
|
public ComputeShader renderingShader;
|
||||||
|
|
||||||
private void ClearVisibleVolumeCounter()
|
[Range(16, 256)]
|
||||||
|
public int maxVolumeOnScreen = 64;
|
||||||
|
|
||||||
|
private void ClearCounterBuffer()
|
||||||
{
|
{
|
||||||
var zeroBuffer = new NativeArray<uint>(1, Allocator.Temp);
|
var zeroBuffer = new NativeArray<uint>(1, Allocator.Temp);
|
||||||
zeroBuffer[0] = 0;
|
zeroBuffer[0] = 0u;
|
||||||
_visibleVolumeCountBuffer.SetData(zeroBuffer);
|
_visibleVolumeCountBuffer.SetData(zeroBuffer);
|
||||||
zeroBuffer.Dispose();
|
zeroBuffer.Dispose();
|
||||||
}
|
}
|
||||||
@@ -37,48 +41,24 @@ internal class AoVolumePass : CustomPass
|
|||||||
// The render pipeline will ensure target setup and clearing happens in an performance manner.
|
// The render pipeline will ensure target setup and clearing happens in an performance manner.
|
||||||
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
|
protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd)
|
||||||
{
|
{
|
||||||
_volumeBounds = new NativeArray<OrientedBoundingBox>(64, Allocator.Persistent);
|
_volumeBounds = new NativeArray<OrientedBoundingBox>(maxVolumeOnScreen, Allocator.Persistent);
|
||||||
_volumeBoundsBuffer = new ComputeBuffer(64, Marshal.SizeOf<OrientedBoundingBox>());
|
_volumeBoundsBuffer = new ComputeBuffer(maxVolumeOnScreen, Marshal.SizeOf<OrientedBoundingBox>());
|
||||||
_visibleIndicesBuffer = new ComputeBuffer(64, Marshal.SizeOf<uint>(), ComputeBufferType.Raw);
|
_visibleIndicesBuffer = new ComputeBuffer(maxVolumeOnScreen, Marshal.SizeOf<uint>(), ComputeBufferType.Raw);
|
||||||
_visibleVolumeCountBuffer = new ComputeBuffer(1, Marshal.SizeOf<uint>(), ComputeBufferType.Counter);
|
_visibleVolumeCountBuffer = new ComputeBuffer(1, Marshal.SizeOf<uint>(), ComputeBufferType.Counter);
|
||||||
|
|
||||||
_volumeDataBuffer = new ComputeBuffer(64, Marshal.SizeOf<VolumeData>());
|
_volumeDataBuffer = new ComputeBuffer(maxVolumeOnScreen, Marshal.SizeOf<VolumeData>());
|
||||||
|
|
||||||
_volumeBuffer = RTHandles.Alloc(Vector2.one, useDynamicScale: true, dimension: TextureXR.dimension, enableRandomWrite: true, format: GraphicsFormat.R8_UNorm, name: "AO Volume Buffer");
|
_volumeBuffer = RTHandles.Alloc(Vector2.one, useDynamicScale: true, dimension: TextureXR.dimension, enableRandomWrite: true, format: GraphicsFormat.R8_UNorm, name: "AO Volume Buffer");
|
||||||
|
|
||||||
ClearVisibleVolumeCounter();
|
ClearCounterBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static int GetDepthPyramidMaxMipLevel(HDCamera hDCamera)
|
private static int GetDepthPyramidMaxMipLevel(HDCamera hDCamera)
|
||||||
{
|
{
|
||||||
return Mathf.FloorToInt(Mathf.Log(Mathf.Min(hDCamera.actualWidth, hDCamera.actualHeight), 2)) - 1;
|
return Mathf.FloorToInt(Mathf.Log(Mathf.Min(hDCamera.actualWidth, hDCamera.actualHeight), 2)) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Execute(CustomPassContext ctx)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
HierarchicalZCulling(ctx, volumeCount);
|
|
||||||
RenderVisibleVolumes(ctx);
|
|
||||||
//DebugVisibleVolumes();
|
|
||||||
ClearVisibleVolumeCounter();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HierarchicalZCulling(CustomPassContext ctx, int volumeCount)
|
private void HierarchicalZCulling(CustomPassContext ctx, int volumeCount)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < volumeCount; i++)
|
for (var i = 0; i < volumeCount; i++)
|
||||||
@@ -141,6 +121,31 @@ internal class AoVolumePass : CustomPass
|
|||||||
ArrayPool<uint>.Shared.Return(visibleVolumeIndices);
|
ArrayPool<uint>.Shared.Return(visibleVolumeIndices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Execute(CustomPassContext ctx)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
HierarchicalZCulling(ctx, volumeCount);
|
||||||
|
RenderVisibleVolumes(ctx);
|
||||||
|
//DebugVisibleVolumes();
|
||||||
|
ClearCounterBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void Cleanup()
|
protected override void Cleanup()
|
||||||
{
|
{
|
||||||
_volumeBounds.Dispose();
|
_volumeBounds.Dispose();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
||||||
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
|
||||||
#include "Packages/com.misaki.ao-volume/Runtime/Shader/Includes/GeometryData.cs.hlsl"
|
#include "Packages/com.misaki.ao-volume/Runtime/Shader/Includes/GeometryData.cs.hlsl"
|
||||||
|
#include "Packages/com.misaki.ao-volume/Runtime/Shader/Includes/Common.hlsl"
|
||||||
|
|
||||||
#define _FLT_MIN 1.175494351e-38 // Minimum representable positive floating-point number
|
#define _FLT_MIN 1.175494351e-38 // Minimum representable positive floating-point number
|
||||||
#define _FLT_MAX 3.402823466e+38 // Maximum representable floating-point number
|
#define _FLT_MAX 3.402823466e+38 // Maximum representable floating-point number
|
||||||
@@ -19,16 +20,6 @@ StructuredBuffer<int2> _DepthPyramidMipLevelOffsets;
|
|||||||
RWByteAddressBuffer _VisibleVolumeCount : register(u0);
|
RWByteAddressBuffer _VisibleVolumeCount : register(u0);
|
||||||
RWByteAddressBuffer _VisibleVolumeIndices : register(u1);
|
RWByteAddressBuffer _VisibleVolumeIndices : register(u1);
|
||||||
|
|
||||||
RW_TEXTURE2D_X(float, _DebugTexture);
|
|
||||||
|
|
||||||
float4 ComputeScreenPos(float4 pos, float projectionSign)
|
|
||||||
{
|
|
||||||
float4 o = pos * 0.5f;
|
|
||||||
o.xy = float2(o.x, o.y * projectionSign) + o.w;
|
|
||||||
o.zw = pos.zw;
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
float SampleDepthLod(int2 uv, int lod)
|
float SampleDepthLod(int2 uv, int lod)
|
||||||
{
|
{
|
||||||
int2 mipCoord = uv >> lod;
|
int2 mipCoord = uv >> lod;
|
||||||
@@ -80,13 +71,13 @@ void CSMain(uint3 dispatchThreadId : SV_DispatchThreadID)
|
|||||||
float4 positionCS = TransformWorldToHClip(cornerRWS);
|
float4 positionCS = TransformWorldToHClip(cornerRWS);
|
||||||
positionCS /= positionCS.w;
|
positionCS /= positionCS.w;
|
||||||
|
|
||||||
float2 screenPos = ComputeScreenPos(positionCS, _ProjectionParams.x).xy;
|
float2 positionNDC = ComputePositionNDC(positionCS, _ProjectionParams.x).xy;
|
||||||
|
|
||||||
screenMin = min(screenMin, screenPos);
|
screenMin = min(screenMin, positionNDC);
|
||||||
screenMax = max(screenMax, screenPos);
|
screenMax = max(screenMax, positionNDC);
|
||||||
|
|
||||||
boxMaxDepth = max(boxMaxDepth, positionCS.z);
|
boxMaxDepth = max(boxMaxDepth, positionCS.z);
|
||||||
cornerPositionSS[i] = screenPos * _ScreenSize.xy;
|
cornerPositionSS[i] = positionNDC * _ScreenSize.xy;
|
||||||
}
|
}
|
||||||
|
|
||||||
float rectWidth = (screenMax.x - screenMin.x);
|
float rectWidth = (screenMax.x - screenMin.x);
|
||||||
|
|||||||
31
Runtime/Shader/Includes/Common.hlsl
Normal file
31
Runtime/Shader/Includes/Common.hlsl
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef VOLUME_COMMON
|
||||||
|
#define VOLUME_COMMON
|
||||||
|
|
||||||
|
#define _MAX_CLUSTER_COUNT 16
|
||||||
|
#define _DEPTH_STEP (1.0 / _MAX_CLUSTER_COUNT)
|
||||||
|
|
||||||
|
float4 ComputePositionNDC(float4 positionCS, float projectionSign)
|
||||||
|
{
|
||||||
|
float4 positionNDC = positionCS * 0.5f;
|
||||||
|
positionNDC.xy = float2(positionNDC.x, positionNDC.y * projectionSign) + positionNDC.w;
|
||||||
|
positionNDC.zw = positionCS.zw;
|
||||||
|
return positionNDC;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint GetClusterIndex(float linearDepth)
|
||||||
|
{
|
||||||
|
return (uint)clamp(floor(linearDepth / _DEPTH_STEP), 0.0, (float)_MAX_CLUSTER_COUNT - 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetClusterVolumeCount(uint clusterIndex, out uint count)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
uint FetchVolumeIndex(uint clusterIndex, uint offset)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 3231123e01a82c04797c5cd8cb634e31
|
guid: 9733756ad1176ce4983ca1a172f79e15
|
||||||
NativeFormatImporter:
|
ShaderIncludeImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
mainObjectFileID: 8400000
|
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
assetBundleVariant:
|
assetBundleVariant:
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!84 &8400000
|
|
||||||
RenderTexture:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_Name: New Render Texture
|
|
||||||
m_ImageContentsHash:
|
|
||||||
serializedVersion: 2
|
|
||||||
Hash: 00000000000000000000000000000000
|
|
||||||
m_IsAlphaChannelOptional: 0
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Width: 256
|
|
||||||
m_Height: 256
|
|
||||||
m_AntiAliasing: 1
|
|
||||||
m_MipCount: -1
|
|
||||||
m_DepthStencilFormat: 94
|
|
||||||
m_ColorFormat: 0
|
|
||||||
m_MipMap: 0
|
|
||||||
m_GenerateMips: 1
|
|
||||||
m_SRGB: 0
|
|
||||||
m_UseDynamicScale: 0
|
|
||||||
m_UseDynamicScaleExplicit: 0
|
|
||||||
m_BindMS: 0
|
|
||||||
m_EnableCompatibleFormat: 1
|
|
||||||
m_EnableRandomWrite: 0
|
|
||||||
m_TextureSettings:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_FilterMode: 1
|
|
||||||
m_Aniso: 0
|
|
||||||
m_MipBias: 0
|
|
||||||
m_WrapU: 1
|
|
||||||
m_WrapV: 1
|
|
||||||
m_WrapW: 1
|
|
||||||
m_Dimension: 2
|
|
||||||
m_VolumeDepth: 1
|
|
||||||
m_ShadowSamplingMode: 2
|
|
||||||
@@ -1,14 +1,19 @@
|
|||||||
// Each #kernel tells which function to compile; you can have many kernels
|
|
||||||
#pragma kernel CSMain
|
#pragma kernel CSMain
|
||||||
|
|
||||||
// Create a RenderTexture with enableRandomWrite flag and set it
|
#include "Packages/com.misaki.ao-volume/Runtime/Shader/Includes/GeometryData.cs.hlsl"
|
||||||
// with cs.SetTexture
|
|
||||||
RWTexture2D<float4> Result;
|
|
||||||
|
|
||||||
[numthreads(8,8,1)]
|
StructuredBuffer<OrientedBoundingBox> _VolumeBounds;
|
||||||
void CSMain (uint3 id : SV_DispatchThreadID)
|
ByteAddressBuffer _VisibleVolumeCount;
|
||||||
|
ByteAddressBuffer _VisibleVolumeIndices;
|
||||||
|
|
||||||
|
// For the volume list buffer, we allocate a buffer with the size of "cluster count" * "max volume count on screen" / 4.
|
||||||
|
// The first slot of each cluster group is always reserved for the count of volumes in the cluster.
|
||||||
|
// The rest of the slots are used for the indices of the volumes in the cluster, each slot are packed with 2 16 bits indices.
|
||||||
|
// To total number of indices in each cluster is "max volume count on screen" / 4 - 1.
|
||||||
|
RWByteAddressBuffer _VolumeListCluster : register(u0);
|
||||||
|
|
||||||
|
[numthreads(64,1,1)]
|
||||||
|
void CSMain(uint3 dispatchThreadId : SV_DispatchThreadID)
|
||||||
{
|
{
|
||||||
// TODO: insert actual code here!
|
|
||||||
|
}
|
||||||
Result[id.xy] = float4(id.x & id.y, (id.x & 15)/15.0, (id.y & 15)/15.0, 0.0);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user