@@ -13,6 +13,13 @@ concept HashGridVertexData = requires(T obj, T const cobj, uint32_t hash) {
1313 { cobj.getPosition () } -> std::same_as<hlsl::float32_t3>;
1414};
1515
16+ template <typename Fn, typename T>
17+ concept HashGridIteratorFn = HashGridVertexData<T> && requires (Fn && fn, T const cobj)
18+ {
19+ // return whether hash grid should continue the iteration
20+ { std::invoke (std::forward<Fn>(fn), cobj) } -> std::same_as<bool >;
21+ };
22+
1623template <HashGridVertexData VertexData>
1724class CVertexHashGrid
1825{
@@ -26,43 +33,40 @@ class CVertexHashGrid
2633 collection_t ::const_iterator end;
2734 };
2835
29- CVertexHashGrid (size_t _vertexCount , uint32_t _hashTableMaxSize , float _cellSize ) :
30- m_sorter (createSorter(_vertexCount) ),
31- m_hashTableMaxSize (_hashTableMaxSize ),
32- m_cellSize (_cellSize )
36+ CVertexHashGrid (size_t cellSize , uint32_t hashTableMaxSizeLog2 , float vertexCountReserve ) :
37+ m_cellSize (cellSize ),
38+ m_hashTableMaxSize (1llu << hashTableMaxSizeLog2 ),
39+ m_sorter (createSorter(vertexCountReserve) )
3340 {
34- assert ((core::isPoT (m_hashTableMaxSize)));
35-
36- m_vertices.reserve (_vertexCount);
41+ m_vertices.reserve (vertexCountReserve);
3742 }
3843
3944 // inserts vertex into hash table
4045 void add (VertexData&& vertex)
4146 {
4247 vertex.setHash (hash (vertex));
43- m_vertices.push_back (vertex);
48+ m_vertices.push_back (std::move ( vertex) );
4449 }
4550
46- void validate ()
51+ void bake ()
4752 {
48- const auto oldSize = m_vertices.size ();
49- m_vertices.resize (oldSize*2u );
50- auto finalSortedOutput = std::visit ( [&](auto & sorter) { return sorter (m_vertices.data (), m_vertices.data () + oldSize, oldSize, KeyAccessor ()); },m_sorter );
53+ auto scratchBuffer = collection_t (m_vertices.size ());
54+
55+ auto finalSortedOutput = std::visit ( [&](auto & sorter)
56+ {
57+ return sorter (m_vertices.data (), scratchBuffer.data (), m_vertices.size (), KeyAccessor ());
58+ }, m_sorter );
5159
5260 if (finalSortedOutput != m_vertices.data ())
53- m_vertices.erase (m_vertices.begin (), m_vertices.begin () + oldSize);
54- else
55- m_vertices.resize (oldSize);
61+ m_vertices = std::move (scratchBuffer);
5662 }
5763
5864 const collection_t & vertices () const { return m_vertices; }
5965
60- collection_t & vertices (){ return m_vertices; }
61-
6266 inline uint32_t getVertexCount () const { return m_vertices.size (); }
6367
64- template <typename Fn>
65- void iterateBroadphaseCandidates (const VertexData& vertex, Fn fn) const
68+ template <HashGridIteratorFn<VertexData> Fn>
69+ void forEachBroadphaseNeighborCandidates (const VertexData& vertex, Fn&& fn) const
6670 {
6771 std::array<uint32_t , 8 > neighboringCells;
6872 const auto cellCount = getNeighboringCellHashes (neighboringCells.data (), vertex);
@@ -76,7 +80,7 @@ class CVertexHashGrid
7680 {
7781 const vertex_data_t & neighborVertex = *bounds.begin ;
7882 if (&vertex != &neighborVertex)
79- if (!fn ( neighborVertex)) break ;
83+ if (!std::invoke (std::forward<Fn>(fn), neighborVertex)) break ;
8084 }
8185 }
8286
@@ -85,7 +89,7 @@ class CVertexHashGrid
8589private:
8690 struct KeyAccessor
8791 {
88- _NBL_STATIC_INLINE_CONSTEXPR size_t key_bit_count = 32ull ;
92+ constexpr static size_t key_bit_count = 32ull ;
8993
9094 template <auto bit_offset, auto radix_mask>
9195 inline decltype (radix_mask) operator()(const VertexData& item) const
@@ -98,8 +102,6 @@ class CVertexHashGrid
98102 static constexpr uint32_t primeNumber2 = 19349663 ;
99103 static constexpr uint32_t primeNumber3 = 83492791 ;
100104
101- static constexpr uint32_t invalidHash = 0xFFFFFFFF ;
102-
103105 using sorter_t = std::variant<
104106 core::RadixLsbSorter<KeyAccessor::key_bit_count, uint16_t >,
105107 core::RadixLsbSorter<KeyAccessor::key_bit_count, uint32_t >,
@@ -122,10 +124,8 @@ class CVertexHashGrid
122124 uint32_t hash (const VertexData& vertex) const
123125 {
124126 const hlsl::float32_t3 position = floor (vertex.getPosition () / m_cellSize);
125-
126- return ((static_cast <uint32_t >(position.x ) * primeNumber1) ^
127- (static_cast <uint32_t >(position.y ) * primeNumber2) ^
128- (static_cast <uint32_t >(position.z ) * primeNumber3))& (m_hashTableMaxSize - 1 );
127+ const auto position_uint32 = hlsl::uint32_t3 (position.x , position.y , position.z );
128+ return hash (position_uint32);
129129 }
130130
131131 uint32_t hash (const hlsl::uint32_t3& position) const
@@ -137,6 +137,7 @@ class CVertexHashGrid
137137
138138 uint8_t getNeighboringCellHashes (uint32_t * outNeighbors, const VertexData& vertex) const
139139 {
140+ // both 0.x and -0.x would be converted to 0 if we directly casting the position to unsigned integer. Causing the 0 to be crowded then the rest of the cells. So we use floor here to spread the vertex more uniformly.
140141 hlsl::float32_t3 cellfloatcoord = floor (vertex.getPosition () / m_cellSize - hlsl::float32_t3 (0.5 ));
141142 hlsl::uint32_t3 baseCoord = hlsl::uint32_t3 (static_cast <uint32_t >(cellfloatcoord.x ), static_cast <uint32_t >(cellfloatcoord.y ), static_cast <uint32_t >(cellfloatcoord.z ));
142143
@@ -167,12 +168,9 @@ class CVertexHashGrid
167168
168169 BucketBounds getBucketBoundsByHash (uint32_t hash) const
169170 {
170- if (hash == invalidHash)
171- return { m_vertices.end (), m_vertices.end () };
172-
173171 const auto skipListBound = std::visit ([&](auto & sorter)
174172 {
175- auto hashBound = sorter.getHashBound (hash);
173+ auto hashBound = sorter.getMostSignificantRadixBound (hash);
176174 return std::pair<collection_t ::const_iterator, collection_t ::const_iterator>(m_vertices.begin () + hashBound.first , m_vertices.begin () + hashBound.second );
177175 }, m_sorter);
178176
0 commit comments