Removing clustering. Replaced by separation of axes

This commit is contained in:
2025-10-21 22:50:36 +02:00
parent 16ffd2cb57
commit 7031d8ad5e
5 changed files with 209 additions and 676 deletions

View File

@ -29,18 +29,18 @@ public class Player : MonoBehaviour
void Cast( ref VoxelRaycastGPU.BatchData[] batchData, int batchCount, int iIteration )
{
ComputeBuffer hitBuffer = new ComputeBuffer(rayCount * batchCount, Marshal.SizeOf(typeof(VoxelRaycastGPU.Hit)), ComputeBufferType.Append);
Stopwatch sw = Stopwatch.StartNew();
totalCastDone += batchCount * rayCount;
VoxelRaycastGPU.BatchData[] hits = voxelManager.CastGpuRay(in batchData, batchCount);
/*for( int i = 0; i < hits.Length; i++ )
{
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = hits[i].origin;
sphere.transform.localScale = Vector3.one * 0.5f;
}*/
/**
for( int i = 0; i < hits.Length; i++ )
{
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = hits[i].origin;
sphere.transform.localScale = Vector3.one * 0.5f;
}
*/
sw.Stop();
}

View File

@ -15,10 +15,11 @@ public class VoxelRaycastGpuManager
//--------------- RayCasts ------------------------------------------------------
int kernel;
ComputeBuffer datasBuffer;
ComputeBuffer datasBuffer = null;
ComputeBuffer hitCounterBuffer = null;
ComputeBuffer rayBuffer = null;
ComputeBuffer hitBuffer;
ComputeBuffer hitBuffer = null;
ComputeBuffer countBuffer = null;
int raysPerBatch;
@ -27,12 +28,16 @@ public class VoxelRaycastGpuManager
int groupsX;
int maxRaycastPerIteration;
int threadsY = 8;
int maxGroupsY = 65535;
//--------------- Clustering ------------------------------------------------------
ComputeShader clusteringShader;
int accumulationKernel;
int reductionKernel;
int gridSize;
int threadCount = 64;
int groupCountHits;
@ -54,8 +59,6 @@ public class VoxelRaycastGpuManager
public VoxelRaycastGPU.BatchData[] Raycast(in VoxelRaycastGPU.BatchData[] batchData, int datasLenght)
{
ComputeBuffer countBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Raw);
int iteration = 0;
int currentCount = datasLenght;
int previousCount = datasLenght;
@ -71,60 +74,73 @@ public class VoxelRaycastGpuManager
raycastShader.SetBuffer(kernel, "batchDatas", datasBuffer );
raycastShader.SetBuffer(kernel, "hits", hitBuffer);
int threadsY = 8;
/**
Stopwatch sw = Stopwatch.StartNew();
*/
for (int y = 0; y < currentCount; y += threadsY * maxGroupsY)
{
int remaining = currentCount - y;
int dispatchGroupsY = Mathf.CeilToInt(Mathf.Min(remaining / (float)threadsY, maxGroupsY));
raycastShader.SetInt("startIndexY", y);
raycastShader.Dispatch(kernel, groupsX, dispatchGroupsY, 1);
}
int groupsY = Mathf.CeilToInt((float)currentCount / threadsY);
Stopwatch sw = Stopwatch.StartNew();
raycastShader.Dispatch(kernel, groupsX, groupsY, 1);
ComputeBuffer.CopyCount(hitBuffer, countBuffer, 0);
int[] countArr = new int[1];
countBuffer.GetData(countArr);
currentCount = countArr[0];
sw.Stop();
UnityEngine.Debug.Log($"Dispatch done in {sw.Elapsed.TotalMilliseconds}ms for {previousCount*raysPerBatch} casts retrieving {currentCount} hits");
if (currentCount > 0)
{
if (currentCount * raysPerBatch > maxRaycastPerIteration && iteration < 5)
{
sw = Stopwatch.StartNew();
currentCount = Clustering(currentCount);
sw.Stop();
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++)
hitBuffer.GetData(hits, 0, 0, currentCount);
for( int i = 0; i < hits.Length; i++ )
{
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = hits[i].origin;
sphere.transform.localScale = Vector3.one * 0.5f;
}
}
else
{
*/
datasBuffer = hitBuffer;
}
}
/**
sw.Stop();
UnityEngine.Debug.Log($"Dispatch done in {sw.Elapsed.TotalMilliseconds}ms for {previousCount*raysPerBatch} casts retrieving {currentCount} hits");
*/
iteration++;
if (currentCount > 0 && iteration < 5)
{
datasBuffer = hitBuffer;
/**
if (currentCount * raysPerBatch > maxRaycastPerIteration && iteration < 5)
{
sw = Stopwatch.StartNew();
currentCount = Clustering( maxRaycastPerIteration / raysPerBatch);
sw.Stop();
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;
}
}
*/
}
}
VoxelRaycastGPU.BatchData[] result = new VoxelRaycastGPU.BatchData[previousCount];
if (currentCount == 0)
datasBuffer.GetData(result, 0, 0, previousCount);
else
hitBuffer.GetData(result, 0, 0, previousCount);
countBuffer.Release();
hitBuffer.GetData(result, 0, 0, previousCount);
return result;
}
@ -133,6 +149,8 @@ public class VoxelRaycastGpuManager
{
maxRaycastPerIteration = 1000000;
raysPerBatch = nbRaysPerBatch;
countBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Raw);
// Flatten octree
linearTree = OctreeGpuHelpers.FlattenOctree(root);
@ -152,7 +170,6 @@ public class VoxelRaycastGpuManager
uint[] counterInit = { 0 };
counterInit[0] = 0;
hitCounterBuffer.SetData(counterInit);
kernel = raycastShader.FindKernel("CSMain");
raycastShader.SetBuffer(kernel, "nodes", nodeBuffer);
@ -174,46 +191,72 @@ public class VoxelRaycastGpuManager
cellClusteringSums = new ComputeBuffer(gridSize, sizeof(float) * 4);
cellClusteringCounts = new ComputeBuffer(gridSize, sizeof(uint));
clustered = new ComputeBuffer(gridSize, Marshal.SizeOf(typeof(VoxelRaycastGPU.BatchData)), ComputeBufferType.Append);
accumulationKernel = clusteringShader.FindKernel("Accumulate");
reductionKernel = clusteringShader.FindKernel("Reduce");
}
public int Clustering( int inputCount )
public int Clustering( int targetGroupCount )
{
groupCountHits = Mathf.CeilToInt((float)inputCount / threadCount);
int count = datasBuffer.count;
clustered.SetCounterValue(0);
float[] zero4 = new float[gridSize * 4];
uint[] zeroU = new uint[gridSize];
cellClusteringSums.SetData(zero4);
cellClusteringCounts.SetData(zeroU);
// 1⃣ Définir la résolution de la grille
int cellsPerAxis = Mathf.CeilToInt(Mathf.Pow(targetGroupCount, 1f / 3f));
Vector3 gridMin = new Vector3(-50, -50, -50);
Vector3 gridMax = new Vector3(50, 50, 50);
Vector3 cellSize = (gridMax - gridMin) / cellsPerAxis;
// Shader
int kernelAcc = clusteringShader.FindKernel("AccumulateHits");
int kernelMean = clusteringShader.FindKernel("ComputeMeans");
int totalCells = cellsPerAxis * cellsPerAxis * cellsPerAxis;
clusteringShader.SetInt("inputCount", inputCount);
clusteringShader.SetFloat("cellSize", 1.0f); // taille des cellules
clusteringShader.SetVector("gridOrigin", Vector3.zero);
// 2⃣ Créer les buffers
ComputeBuffer cellCount = new ComputeBuffer(totalCells, sizeof(uint));
ComputeBuffer cellDistanceSum = new ComputeBuffer(totalCells, sizeof(float));
ComputeBuffer resultBuffer = new ComputeBuffer(totalCells, sizeof(float) * 4, ComputeBufferType.Append);
resultBuffer.SetCounterValue(0);
clusteringShader.SetBuffer(kernelAcc, "inputHits", hitBuffer);
clusteringShader.SetBuffer(kernelAcc, "cellSums", cellClusteringSums);
clusteringShader.SetBuffer(kernelAcc, "cellCounts", cellClusteringCounts);
clusteringShader.Dispatch(kernelAcc, groupCountHits, 1, 1);
clusteringShader.SetBuffer(accumulationKernel, "batchDatas", datasBuffer);
clusteringShader.SetBuffer(accumulationKernel, "cellCount", cellCount);
clusteringShader.SetBuffer(accumulationKernel, "cellDistanceSum", cellDistanceSum);
clusteringShader.SetBuffer(kernelMean, "cellSums", cellClusteringSums);
clusteringShader.SetBuffer(kernelMean, "cellCounts", cellClusteringCounts);
clusteringShader.SetBuffer(kernelMean, "clusteredHits", clustered);
clusteringShader.Dispatch(kernelMean, groupCountGrid, 1, 1);
clusteringShader.SetVector("gridMin", gridMin);
clusteringShader.SetVector("gridMax", gridMax);
clusteringShader.SetInts("gridResolution", cellsPerAxis, cellsPerAxis, cellsPerAxis);
clusteringShader.SetVector("cellSize", cellSize);
// 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];
int threadsPerGroup = 64;
int maxThreadGroups = 65535;
datasBuffer = clustered;
for (int i = 0; i < count; i += threadsPerGroup * maxThreadGroups)
{
int remaining = count - i;
int groups = Mathf.CeilToInt(Mathf.Min(remaining / (float)threadsPerGroup, maxThreadGroups));
clusteringShader.SetInt("startIndex", i);
clusteringShader.Dispatch(accumulationKernel, groups, 1, 1);
}
return clusterCount;
// 4⃣ Dispatch reduce
clusteringShader.SetBuffer(reductionKernel, "cellCount", cellCount);
clusteringShader.SetBuffer(reductionKernel, "cellDistanceSum", cellDistanceSum);
clusteringShader.SetBuffer(reductionKernel, "clusteredBatches", resultBuffer);
int reduceGroups = Mathf.CeilToInt(totalCells / 64);
clusteringShader.Dispatch(reductionKernel, reduceGroups, 1, 1);
// 5⃣ Lire le résultat
ComputeBuffer.CopyCount(resultBuffer, countBuffer, 0);
int[] countArray = new int[1];
countBuffer.GetData(countArray);
int outputCount = countArray[0];
VoxelRaycastGPU.BatchData[] finalBatches = new VoxelRaycastGPU.BatchData[outputCount];
resultBuffer.GetData(finalBatches, 0, 0, outputCount);
// 🔚 Cleanup
cellCount.Release();
cellDistanceSum.Release();
resultBuffer.Release();
return outputCount;
}
~VoxelRaycastGpuManager()
@ -224,8 +267,14 @@ public class VoxelRaycastGpuManager
if (rayBuffer != null)
rayBuffer.Release();
hitBuffer.Release();
datasBuffer.Release();
if (hitBuffer != null)
hitBuffer.Release();
if (datasBuffer != null)
datasBuffer.Release();
if( countBuffer != null )
countBuffer.Release();
}
}