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

@ -1,81 +1,91 @@
// VoxelBatchCluster.compute // SpatialGridCluster.compute
#pragma kernel AccumulateHits #pragma kernel Accumulate
#pragma kernel ComputeMeans #pragma kernel Reduce
// ---- Structures ----
struct BatchData struct BatchData
{ {
float3 position; float3 origin;
float maxDistance; float maxDistance;
}; };
// ---- Constantes ---- StructuredBuffer<BatchData> batchDatas;
#define GRID_SIZE 8192 // nombre total de cellules max RWStructuredBuffer<uint> cellCount;
#define GRID_PRIME1 73856093 // pour hash RWStructuredBuffer<uint> cellDistanceSum;
#define GRID_PRIME2 19349663 AppendStructuredBuffer<BatchData> clusteredBatches;
#define GRID_PRIME3 83492791
#define SCALE 1000.0
// ---- Buffers ---- float3 gridMin;
StructuredBuffer<BatchData> inputHits; float3 gridMax;
int3 gridResolution;
float3 cellSize;
int startIndex;
RWStructuredBuffer<int4> cellSums; // xyz = somme positions, w = somme maxDistance #define DIST_SCALE 100.0
RWStructuredBuffer<uint> cellCounts; // nombre d'éléments par cellule #define THREADS 64
AppendStructuredBuffer<BatchData> clusteredHits;
// ---- Params ---- // ----------------------
float cellSize; // taille d'une cellule (distance seuil) // === KERNEL 1 : ACCUMULATION OPTIMISÉE ===
uint inputCount; // nombre d'éléments d'entrée // ----------------------
float3 gridOrigin; // origine du monde pour le hash groupshared uint localCellCount[THREADS];
groupshared uint localCellSum[THREADS];
// ---- Utilitaires ---- [numthreads(THREADS, 1, 1)]
uint HashCell(int3 cell) void Accumulate(uint3 id : SV_DispatchThreadID, uint3 groupId : SV_GroupID, uint3 localId : SV_GroupThreadID)
{ {
uint h = (uint)((cell.x * GRID_PRIME1) ^ (cell.y * GRID_PRIME2) ^ (cell.z * GRID_PRIME3)); uint index = id.x + startIndex;
return h % GRID_SIZE; if (index >= batchDatas.Length) return;
BatchData b = batchDatas[index];
// Position relative dans la grille
float3 rel = (b.origin - gridMin) / (gridMax - gridMin);
int3 cell = clamp(int3(rel * gridResolution), 0, gridResolution - 1);
// Index 1D de la cellule
uint cellIndex = cell.x + cell.y * gridResolution.x + cell.z * gridResolution.x * gridResolution.y;
// Initialiser le groupe partagé pour ce thread
localCellCount[localId.x] = 0;
localCellSum[localId.x] = 0;
GroupMemoryBarrierWithGroupSync();
// Accumulation locale
localCellCount[localId.x] += 1;
localCellSum[localId.x] += (uint)(b.maxDistance * DIST_SCALE + 0.5);
GroupMemoryBarrierWithGroupSync();
// Écriture atomique unique par thread vers le buffer global
InterlockedAdd(cellCount[cellIndex], localCellCount[localId.x]);
InterlockedAdd(cellDistanceSum[cellIndex], localCellSum[localId.x]);
} }
// ---- Kernel 1 : Accumulation ---- // ----------------------
// Constante déchelle // === KERNEL 2 : REDUCTION ===
// ----------------------
[numthreads(64,1,1)] [numthreads(THREADS, 1, 1)]
void AccumulateHits(uint3 id : SV_DispatchThreadID) void Reduce(uint3 id : SV_DispatchThreadID)
{ {
uint i = id.x; uint index = id.x;
if (i >= inputCount) return; uint totalCells = gridResolution.x * gridResolution.y * gridResolution.z;
BatchData b = inputHits[i]; if (index >= totalCells) return;
int3 cell = int3(floor((b.position - gridOrigin) / cellSize)); uint count = cellCount[index];
uint hash = HashCell(cell);
// Conversion float -> int
int3 posInt = int3(b.position * SCALE);
int maxDistInt = (int)(b.maxDistance * SCALE);
// Ajout atomique
InterlockedAdd(cellSums[hash].x, posInt.x);
InterlockedAdd(cellSums[hash].y, posInt.y);
InterlockedAdd(cellSums[hash].z, posInt.z);
InterlockedAdd(cellSums[hash].w, maxDistInt);
InterlockedAdd(cellCounts[hash], 1);
}
// ---- Kernel 2 : Calcul des moyennes ----
[numthreads(64,1,1)]
void ComputeMeans(uint3 id : SV_DispatchThreadID)
{
uint i = id.x;
if (i >= GRID_SIZE) return;
uint count = cellCounts[i];
if (count == 0) return; if (count == 0) return;
int4 sum = cellSums[i]; uint sumScaled = cellDistanceSum[index];
float avgDistance = (float(sumScaled) / float(count)) / DIST_SCALE;
BatchData outB; uint3 coord;
outB.position = (float3(sum.xyz) / SCALE) / count; coord.x = index % gridResolution.x;
outB.maxDistance = (float(sum.w) / SCALE) / count; coord.y = (index / gridResolution.x) % gridResolution.y;
coord.z = index / (gridResolution.x * gridResolution.y);
clusteredHits.Append(outB); float3 center = gridMin + (float3(coord) + 0.5) * cellSize;
BatchData b;
b.origin = center;
b.maxDistance = avgDistance;
clusteredBatches.Append(b);
} }

View File

@ -69,6 +69,8 @@ float3 rootCenter;
float rootHalfSize; float rootHalfSize;
int rootIndex; int rootIndex;
int startIndexY;
float3 ClosestPointOnAABB(float3 hitPos, float3 boxCenter, float halfSize) float3 ClosestPointOnAABB(float3 hitPos, float3 boxCenter, float halfSize)
{ {
float3 minB = boxCenter - halfSize; float3 minB = boxCenter - halfSize;
@ -139,7 +141,7 @@ inline bool IntersectAABB_fast(
void CSMain(uint3 id : SV_DispatchThreadID) void CSMain(uint3 id : SV_DispatchThreadID)
{ {
uint rayIndex = id.x; uint rayIndex = id.x;
uint batchIndex = id.y; uint batchIndex = id.y + startIndexY;
if (rayIndex >= rays.Length || batchIndex >= batchDatas.Length) return; if (rayIndex >= rays.Length || batchIndex >= batchDatas.Length) return;
RayData r = rays[rayIndex]; RayData r = rays[rayIndex];

View File

@ -244,228 +244,6 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: Assembly-CSharp::AudioObject m_EditorClassIdentifier: Assembly-CSharp::AudioObject
audioMaterialSettings: {fileID: 11400000, guid: 58ebbfa597f7b56499162cc5660da3ba, type: 2} audioMaterialSettings: {fileID: 11400000, guid: 58ebbfa597f7b56499162cc5660da3ba, type: 2}
--- !u!1 &428183757
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 428183761}
- component: {fileID: 428183760}
- component: {fileID: 428183759}
- component: {fileID: 428183758}
m_Layer: 0
m_Name: Cube (2)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!65 &428183758
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 428183757}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!23 &428183759
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 428183757}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!33 &428183760
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 428183757}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!4 &428183761
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 428183757}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 19.35913, y: 9.19515, z: 43.9}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &450236051
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 450236055}
- component: {fileID: 450236054}
- component: {fileID: 450236053}
- component: {fileID: 450236052}
m_Layer: 0
m_Name: Cube (5)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!65 &450236052
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 450236051}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!23 &450236053
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 450236051}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!33 &450236054
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 450236051}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!4 &450236055
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 450236051}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 20.352, y: 9.19515, z: 44.904}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &464574962 --- !u!1 &464574962
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -560,117 +338,6 @@ MonoBehaviour:
emptyColor: {r: 0, g: 0.5, b: 1, a: 0.2} emptyColor: {r: 0, g: 0.5, b: 1, a: 0.2}
solidColor: {r: 1, g: 0, b: 0, a: 0.5} solidColor: {r: 1, g: 0, b: 0, a: 0.5}
mixedColor: {r: 1, g: 1, b: 0, a: 0.4} mixedColor: {r: 1, g: 1, b: 0, a: 0.4}
--- !u!1 &612412859
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 612412863}
- component: {fileID: 612412862}
- component: {fileID: 612412861}
- component: {fileID: 612412860}
m_Layer: 0
m_Name: Cube (6)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!65 &612412860
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 612412859}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!23 &612412861
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 612412859}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!33 &612412862
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 612412859}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!4 &612412863
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 612412859}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 18.363, y: 9.19515, z: 41.884}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &705507993 --- !u!1 &705507993
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -768,7 +435,7 @@ Transform:
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!1 &864920249 --- !u!1 &711765669
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -776,104 +443,24 @@ GameObject:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
serializedVersion: 6 serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 864920253} - component: {fileID: 711765670}
- component: {fileID: 864920252}
- component: {fileID: 864920251}
- component: {fileID: 864920250}
m_Layer: 0 m_Layer: 0
m_Name: Cube (3) m_Name: GameObject
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
m_StaticEditorFlags: 0 m_StaticEditorFlags: 0
m_IsActive: 1 m_IsActive: 1
--- !u!65 &864920250 --- !u!4 &711765670
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 864920249}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!23 &864920251
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 864920249}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!33 &864920252
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 864920249}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!4 &864920253
Transform: Transform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 864920249} m_GameObject: {fileID: 711765669}
serializedVersion: 2 serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 18.363, y: 9.19515, z: 42.918} m_LocalPosition: {x: 50, y: 50, z: 50}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
@ -1349,117 +936,6 @@ Transform:
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: -53.013, z: 0} m_LocalEulerAnglesHint: {x: 0, y: -53.013, z: 0}
--- !u!1 &2077705879
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2077705883}
- component: {fileID: 2077705882}
- component: {fileID: 2077705881}
- component: {fileID: 2077705880}
m_Layer: 0
m_Name: Cube (4)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!65 &2077705880
BoxCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2077705879}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Size: {x: 1, y: 1, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!23 &2077705881
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2077705879}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!33 &2077705882
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2077705879}
m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!4 &2077705883
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2077705879}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 21.35913, y: 9.19515, z: 45.902}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1660057539 &9223372036854775807 --- !u!1660057539 &9223372036854775807
SceneRoots: SceneRoots:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -1470,9 +946,5 @@ SceneRoots:
- {fileID: 1376698039} - {fileID: 1376698039}
- {fileID: 1629958729} - {fileID: 1629958729}
- {fileID: 464574964} - {fileID: 464574964}
- {fileID: 428183761}
- {fileID: 864920253}
- {fileID: 612412863}
- {fileID: 2077705883}
- {fileID: 450236055}
- {fileID: 1273284507} - {fileID: 1273284507}
- {fileID: 711765670}

View File

@ -29,18 +29,18 @@ public class Player : MonoBehaviour
void Cast( ref VoxelRaycastGPU.BatchData[] batchData, int batchCount, int iIteration ) 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(); Stopwatch sw = Stopwatch.StartNew();
totalCastDone += batchCount * rayCount; totalCastDone += batchCount * rayCount;
VoxelRaycastGPU.BatchData[] hits = voxelManager.CastGpuRay(in batchData, batchCount); VoxelRaycastGPU.BatchData[] hits = voxelManager.CastGpuRay(in batchData, batchCount);
/*for( int i = 0; i < hits.Length; i++ ) /**
for( int i = 0; i < hits.Length; i++ )
{ {
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = hits[i].origin; sphere.transform.position = hits[i].origin;
sphere.transform.localScale = Vector3.one * 0.5f; sphere.transform.localScale = Vector3.one * 0.5f;
}*/ }
*/
sw.Stop(); sw.Stop();
} }

View File

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