Optimization + Start of clustering
This commit is contained in:
@ -1,24 +1,24 @@
|
||||
using UnityEngine;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Diagnostics;
|
||||
|
||||
public class VoxelRaycastGpuManager
|
||||
{
|
||||
ComputeShader raycastShader;
|
||||
OctreeNode root; // assign your built octree root
|
||||
public VoxelRaycastGpuManager(ComputeShader computeShader, OctreeNode octreeRoot)
|
||||
{
|
||||
raycastShader = computeShader;
|
||||
root = octreeRoot;
|
||||
}
|
||||
|
||||
//---------------- Octree ----------------------------------------------------
|
||||
OctreeNode root; // assign your built octree root
|
||||
ComputeBuffer nodeBuffer;
|
||||
|
||||
public LinearTree linearTree;
|
||||
|
||||
|
||||
//--------------- RayCasts ------------------------------------------------------
|
||||
int kernel;
|
||||
|
||||
ComputeBuffer datasBuffer;
|
||||
ComputeBuffer hitCounterBuffer = null;
|
||||
ComputeBuffer rayBuffer = null;
|
||||
ComputeBuffer hitBuffer;
|
||||
|
||||
int raysPerBatch;
|
||||
|
||||
@ -27,12 +27,33 @@ public class VoxelRaycastGpuManager
|
||||
int groupsX;
|
||||
|
||||
int maxRaycastPerIteration;
|
||||
|
||||
|
||||
//--------------- Clustering ------------------------------------------------------
|
||||
|
||||
ComputeShader clusteringShader;
|
||||
|
||||
int gridSize;
|
||||
int threadCount = 64;
|
||||
int groupCountHits;
|
||||
int groupCountGrid;
|
||||
|
||||
ComputeBuffer cellClusteringSums;
|
||||
ComputeBuffer cellClusteringCounts;
|
||||
ComputeBuffer clustered;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
public VoxelRaycastGpuManager(ComputeShader computeShader, ComputeShader clusteringShader, OctreeNode octreeRoot)
|
||||
{
|
||||
raycastShader = computeShader;
|
||||
this.clusteringShader = clusteringShader;
|
||||
root = octreeRoot;
|
||||
}
|
||||
|
||||
public VoxelRaycastGPU.BatchData[] Raycast(in VoxelRaycastGPU.BatchData[] batchData, int datasLenght)
|
||||
{
|
||||
ComputeBuffer hitBuffer = new ComputeBuffer(5000, batchDataClassSize, ComputeBufferType.Append);
|
||||
ComputeBuffer datasBuffer = new ComputeBuffer(datasLenght, batchDataClassSize, ComputeBufferType.Default);
|
||||
ComputeBuffer countBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Raw);
|
||||
|
||||
int iteration = 0;
|
||||
@ -41,17 +62,20 @@ public class VoxelRaycastGpuManager
|
||||
|
||||
datasBuffer.SetData(batchData, 0, 0, currentCount);
|
||||
|
||||
while (iteration < 4 && currentCount > 0)
|
||||
while (iteration < 5 && currentCount > 0)
|
||||
{
|
||||
previousCount = currentCount;
|
||||
|
||||
raycastShader.SetBuffer(kernel, "batchDatas", datasBuffer);
|
||||
hitBuffer.SetCounterValue(0);
|
||||
|
||||
raycastShader.SetBuffer(kernel, "batchDatas", datasBuffer );
|
||||
raycastShader.SetBuffer(kernel, "hits", hitBuffer);
|
||||
|
||||
int threadsY = 8;
|
||||
|
||||
int groupsY = Mathf.CeilToInt((float)currentCount / threadsY);
|
||||
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
raycastShader.Dispatch(kernel, groupsX, groupsY, 1);
|
||||
|
||||
ComputeBuffer.CopyCount(hitBuffer, countBuffer, 0);
|
||||
@ -59,22 +83,35 @@ public class VoxelRaycastGpuManager
|
||||
countBuffer.GetData(countArr);
|
||||
currentCount = countArr[0];
|
||||
|
||||
/*VoxelRaycastGPU.BatchData[] hits = new VoxelRaycastGPU.BatchData[currentCount];
|
||||
hitBuffer.GetData(hits, 0, 0, currentCount);
|
||||
|
||||
for (int i = 0; i < currentCount; i++)
|
||||
{
|
||||
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
||||
sphere.transform.position = hits[i].origin;
|
||||
sphere.transform.localScale = Vector3.one * 0.5f;
|
||||
}*/
|
||||
sw.Stop();
|
||||
UnityEngine.Debug.Log($"Dispatch done in {sw.Elapsed.TotalMilliseconds}ms for {previousCount*raysPerBatch} casts retrieving {currentCount} hits");
|
||||
|
||||
if (currentCount > 0)
|
||||
{
|
||||
(datasBuffer, hitBuffer) = (hitBuffer, datasBuffer);
|
||||
if (currentCount * raysPerBatch > maxRaycastPerIteration && iteration < 5)
|
||||
{
|
||||
sw = Stopwatch.StartNew();
|
||||
currentCount = Clustering(currentCount);
|
||||
sw.Stop();
|
||||
|
||||
hitBuffer.Release();
|
||||
hitBuffer = new ComputeBuffer(5000, batchDataClassSize, ComputeBufferType.Append);
|
||||
UnityEngine.Debug.Log($"Clustering done in {sw.Elapsed.TotalMilliseconds}ms for {currentCount} casts");
|
||||
|
||||
VoxelRaycastGPU.BatchData[] hits = new VoxelRaycastGPU.BatchData[currentCount];
|
||||
datasBuffer.GetData(hits, 0, 0, currentCount);
|
||||
|
||||
for (int i = 0; i < currentCount; i++)
|
||||
{
|
||||
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
||||
sphere.transform.position = hits[i].origin;
|
||||
sphere.transform.localScale = Vector3.one * 0.5f;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
datasBuffer = hitBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
iteration++;
|
||||
@ -86,19 +123,24 @@ public class VoxelRaycastGpuManager
|
||||
else
|
||||
hitBuffer.GetData(result, 0, 0, previousCount);
|
||||
|
||||
hitBuffer.Release();
|
||||
datasBuffer.Release();
|
||||
|
||||
countBuffer.Release();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Init( int nbRaysPerBatch, in VoxelRaycastGPU.Ray[] rays )
|
||||
public void Init(int nbRaysPerBatch, in VoxelRaycastGPU.Ray[] rays)
|
||||
{
|
||||
maxRaycastPerIteration = 1000000;
|
||||
raysPerBatch = nbRaysPerBatch;
|
||||
|
||||
// Flatten octree
|
||||
linearTree = OctreeGpuHelpers.FlattenOctree(root);
|
||||
int nodeStride = Marshal.SizeOf(typeof(LinearNode)); // should be 64
|
||||
|
||||
hitBuffer = new ComputeBuffer(maxRaycastPerIteration * raysPerBatch, batchDataClassSize, ComputeBufferType.Append);
|
||||
datasBuffer = new ComputeBuffer(maxRaycastPerIteration, batchDataClassSize, ComputeBufferType.Default);
|
||||
|
||||
rayBuffer = new ComputeBuffer(rays.Length, Marshal.SizeOf(typeof(VoxelRaycastGPU.Ray)), ComputeBufferType.Default);
|
||||
rayBuffer.SetData(rays, 0, 0, rays.Length);
|
||||
|
||||
@ -110,7 +152,7 @@ public class VoxelRaycastGpuManager
|
||||
uint[] counterInit = { 0 };
|
||||
counterInit[0] = 0;
|
||||
hitCounterBuffer.SetData(counterInit);
|
||||
|
||||
|
||||
kernel = raycastShader.FindKernel("CSMain");
|
||||
|
||||
raycastShader.SetBuffer(kernel, "nodes", nodeBuffer);
|
||||
@ -124,11 +166,54 @@ public class VoxelRaycastGpuManager
|
||||
raycastShader.SetFloat("rootHalfSize", root.bounds.size.x / 2f);
|
||||
raycastShader.SetFloats("rootCenter", new float[3] { root.bounds.center.x, root.bounds.center.y, root.bounds.center.z });
|
||||
|
||||
raysPerBatch = nbRaysPerBatch;
|
||||
|
||||
groupsX = Mathf.CeilToInt((float)raysPerBatch / 8);
|
||||
|
||||
maxRaycastPerIteration = 5000 / raysPerBatch;
|
||||
gridSize = maxRaycastPerIteration / raysPerBatch;
|
||||
groupCountGrid = Mathf.CeilToInt((float)gridSize / threadCount);
|
||||
|
||||
cellClusteringSums = new ComputeBuffer(gridSize, sizeof(float) * 4);
|
||||
cellClusteringCounts = new ComputeBuffer(gridSize, sizeof(uint));
|
||||
clustered = new ComputeBuffer(gridSize, Marshal.SizeOf(typeof(VoxelRaycastGPU.BatchData)), ComputeBufferType.Append);
|
||||
}
|
||||
|
||||
public int Clustering( int inputCount )
|
||||
{
|
||||
groupCountHits = Mathf.CeilToInt((float)inputCount / threadCount);
|
||||
|
||||
clustered.SetCounterValue(0);
|
||||
float[] zero4 = new float[gridSize * 4];
|
||||
uint[] zeroU = new uint[gridSize];
|
||||
cellClusteringSums.SetData(zero4);
|
||||
cellClusteringCounts.SetData(zeroU);
|
||||
|
||||
// Shader
|
||||
int kernelAcc = clusteringShader.FindKernel("AccumulateHits");
|
||||
int kernelMean = clusteringShader.FindKernel("ComputeMeans");
|
||||
|
||||
clusteringShader.SetInt("inputCount", inputCount);
|
||||
clusteringShader.SetFloat("cellSize", 1.0f); // taille des cellules
|
||||
clusteringShader.SetVector("gridOrigin", Vector3.zero);
|
||||
|
||||
clusteringShader.SetBuffer(kernelAcc, "inputHits", hitBuffer);
|
||||
clusteringShader.SetBuffer(kernelAcc, "cellSums", cellClusteringSums);
|
||||
clusteringShader.SetBuffer(kernelAcc, "cellCounts", cellClusteringCounts);
|
||||
clusteringShader.Dispatch(kernelAcc, groupCountHits, 1, 1);
|
||||
|
||||
clusteringShader.SetBuffer(kernelMean, "cellSums", cellClusteringSums);
|
||||
clusteringShader.SetBuffer(kernelMean, "cellCounts", cellClusteringCounts);
|
||||
clusteringShader.SetBuffer(kernelMean, "clusteredHits", clustered);
|
||||
clusteringShader.Dispatch(kernelMean, groupCountGrid, 1, 1);
|
||||
|
||||
// Lecture du résultat
|
||||
ComputeBuffer countBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Raw);
|
||||
ComputeBuffer.CopyCount(clustered, countBuffer, 0);
|
||||
int[] countArr = new int[1];
|
||||
countBuffer.GetData(countArr);
|
||||
int clusterCount = countArr[0];
|
||||
|
||||
datasBuffer = clustered;
|
||||
|
||||
return clusterCount;
|
||||
}
|
||||
|
||||
~VoxelRaycastGpuManager()
|
||||
@ -138,5 +223,9 @@ public class VoxelRaycastGpuManager
|
||||
|
||||
if (rayBuffer != null)
|
||||
rayBuffer.Release();
|
||||
|
||||
hitBuffer.Release();
|
||||
datasBuffer.Release();
|
||||
}
|
||||
|
||||
}
|
||||
@ -15,6 +15,7 @@ public class VoxelTreeManager : MonoBehaviour
|
||||
public int maxDepth = 6; // Tree subdivision limit
|
||||
public float boundsSize = 300f; // World size covered by the voxel tree
|
||||
public ComputeShader computeShader;
|
||||
public ComputeShader clusteringShader;
|
||||
private OctreeNode root;
|
||||
private VoxelTreeRaycaster raycaster = new VoxelTreeRaycaster();
|
||||
public VoxelRaycastGpuManager gpuRayCaster;
|
||||
@ -29,7 +30,7 @@ public class VoxelTreeManager : MonoBehaviour
|
||||
var dbg = FindObjectOfType<VoxelTreeDebugger>();
|
||||
if (dbg) dbg.root = root;
|
||||
|
||||
gpuRayCaster = new VoxelRaycastGpuManager(computeShader, root);
|
||||
gpuRayCaster = new VoxelRaycastGpuManager(computeShader, clusteringShader, root);
|
||||
}
|
||||
|
||||
// This function replaces pos => pos.magnitude < 100f
|
||||
|
||||
Reference in New Issue
Block a user