From 7031d8ad5ef9d797e2b4485e6260d4255edab7aa Mon Sep 17 00:00:00 2001 From: blomios Date: Tue, 21 Oct 2025 22:50:36 +0200 Subject: [PATCH] Removing clustering. Replaced by separation of axes --- .../Assets/Shader/VoxelBatchCluster.compute | 130 +++-- Assets/Assets/Shader/VoxelRaycast.compute | 4 +- Assets/Scenes/SampleScene.unity | 542 +----------------- Assets/Scripts/Debug/Player.cs | 16 +- .../VoxelOctree/GPU/VoxelRaycastGpuManager.cs | 193 ++++--- 5 files changed, 209 insertions(+), 676 deletions(-) diff --git a/Assets/Assets/Shader/VoxelBatchCluster.compute b/Assets/Assets/Shader/VoxelBatchCluster.compute index fa7e021..0617ecf 100644 --- a/Assets/Assets/Shader/VoxelBatchCluster.compute +++ b/Assets/Assets/Shader/VoxelBatchCluster.compute @@ -1,81 +1,91 @@ -// VoxelBatchCluster.compute -#pragma kernel AccumulateHits -#pragma kernel ComputeMeans +// SpatialGridCluster.compute +#pragma kernel Accumulate +#pragma kernel Reduce -// ---- Structures ---- struct BatchData { - float3 position; + float3 origin; float maxDistance; }; -// ---- Constantes ---- -#define GRID_SIZE 8192 // nombre total de cellules max -#define GRID_PRIME1 73856093 // pour hash -#define GRID_PRIME2 19349663 -#define GRID_PRIME3 83492791 -#define SCALE 1000.0 +StructuredBuffer batchDatas; +RWStructuredBuffer cellCount; +RWStructuredBuffer cellDistanceSum; +AppendStructuredBuffer clusteredBatches; -// ---- Buffers ---- -StructuredBuffer inputHits; +float3 gridMin; +float3 gridMax; +int3 gridResolution; +float3 cellSize; +int startIndex; -RWStructuredBuffer cellSums; // xyz = somme positions, w = somme maxDistance -RWStructuredBuffer cellCounts; // nombre d'éléments par cellule -AppendStructuredBuffer clusteredHits; +#define DIST_SCALE 100.0 +#define THREADS 64 -// ---- Params ---- -float cellSize; // taille d'une cellule (distance seuil) -uint inputCount; // nombre d'éléments d'entrée -float3 gridOrigin; // origine du monde pour le hash +// ---------------------- +// === KERNEL 1 : ACCUMULATION OPTIMISÉE === +// ---------------------- +groupshared uint localCellCount[THREADS]; +groupshared uint localCellSum[THREADS]; -// ---- Utilitaires ---- -uint HashCell(int3 cell) +[numthreads(THREADS, 1, 1)] +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)); - return h % GRID_SIZE; + uint index = id.x + startIndex; + 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 - -[numthreads(64,1,1)] -void AccumulateHits(uint3 id : SV_DispatchThreadID) +// ---------------------- +// === KERNEL 2 : REDUCTION === +// ---------------------- +[numthreads(THREADS, 1, 1)] +void Reduce(uint3 id : SV_DispatchThreadID) { - uint i = id.x; - if (i >= inputCount) return; + uint index = id.x; + 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 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]; + uint count = cellCount[index]; if (count == 0) return; - int4 sum = cellSums[i]; + uint sumScaled = cellDistanceSum[index]; + float avgDistance = (float(sumScaled) / float(count)) / DIST_SCALE; - BatchData outB; - outB.position = (float3(sum.xyz) / SCALE) / count; - outB.maxDistance = (float(sum.w) / SCALE) / count; + uint3 coord; + coord.x = index % gridResolution.x; + 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); } \ No newline at end of file diff --git a/Assets/Assets/Shader/VoxelRaycast.compute b/Assets/Assets/Shader/VoxelRaycast.compute index 0eaacc6..bd62448 100644 --- a/Assets/Assets/Shader/VoxelRaycast.compute +++ b/Assets/Assets/Shader/VoxelRaycast.compute @@ -69,6 +69,8 @@ float3 rootCenter; float rootHalfSize; int rootIndex; +int startIndexY; + float3 ClosestPointOnAABB(float3 hitPos, float3 boxCenter, float halfSize) { float3 minB = boxCenter - halfSize; @@ -139,7 +141,7 @@ inline bool IntersectAABB_fast( void CSMain(uint3 id : SV_DispatchThreadID) { uint rayIndex = id.x; - uint batchIndex = id.y; + uint batchIndex = id.y + startIndexY; if (rayIndex >= rays.Length || batchIndex >= batchDatas.Length) return; RayData r = rays[rayIndex]; diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity index 890dfa9..47d4770 100644 --- a/Assets/Scenes/SampleScene.unity +++ b/Assets/Scenes/SampleScene.unity @@ -244,228 +244,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Assembly-CSharp::AudioObject 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 GameObject: m_ObjectHideFlags: 0 @@ -560,117 +338,6 @@ MonoBehaviour: emptyColor: {r: 0, g: 0.5, b: 1, a: 0.2} solidColor: {r: 1, g: 0, b: 0, a: 0.5} 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 GameObject: m_ObjectHideFlags: 0 @@ -768,7 +435,7 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!1 &864920249 +--- !u!1 &711765669 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -776,104 +443,24 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 864920253} - - component: {fileID: 864920252} - - component: {fileID: 864920251} - - component: {fileID: 864920250} + - component: {fileID: 711765670} m_Layer: 0 - m_Name: Cube (3) + m_Name: GameObject m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!65 &864920250 -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 +--- !u!4 &711765670 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 864920249} + m_GameObject: {fileID: 711765669} serializedVersion: 2 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_ConstrainProportionsScale: 0 m_Children: [] @@ -1349,117 +936,6 @@ Transform: m_Children: [] m_Father: {fileID: 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 SceneRoots: m_ObjectHideFlags: 0 @@ -1470,9 +946,5 @@ SceneRoots: - {fileID: 1376698039} - {fileID: 1629958729} - {fileID: 464574964} - - {fileID: 428183761} - - {fileID: 864920253} - - {fileID: 612412863} - - {fileID: 2077705883} - - {fileID: 450236055} - {fileID: 1273284507} + - {fileID: 711765670} diff --git a/Assets/Scripts/Debug/Player.cs b/Assets/Scripts/Debug/Player.cs index c68a56d..81adc96 100644 --- a/Assets/Scripts/Debug/Player.cs +++ b/Assets/Scripts/Debug/Player.cs @@ -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(); } diff --git a/Assets/Scripts/VoxelOctree/GPU/VoxelRaycastGpuManager.cs b/Assets/Scripts/VoxelOctree/GPU/VoxelRaycastGpuManager.cs index 33383a5..3f6863b 100644 --- a/Assets/Scripts/VoxelOctree/GPU/VoxelRaycastGpuManager.cs +++ b/Assets/Scripts/VoxelOctree/GPU/VoxelRaycastGpuManager.cs @@ -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(); } } \ No newline at end of file