Skip to content

Commit e91aba1

Browse files
author
kevyuu
committed
Refactor CVertexHashGrid
1 parent e72e0ef commit e91aba1

File tree

3 files changed

+32
-34
lines changed

3 files changed

+32
-34
lines changed

include/nbl/asset/utils/CVertexHashGrid.h

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
1623
template <HashGridVertexData VertexData>
1724
class 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
8589
private:
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

include/nbl/asset/utils/CVertexWelder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class CVertexWelder {
3737
const auto asIndex = vertexIndexToAsIndex[index];
3838
const auto& vertexData = as.vertices()[asIndex];
3939
auto& remappedVertexIndex = remappedVertexIndexes[index];
40-
as.iterateBroadphaseCandidates(vertexData, [&, polygon, index](const typename AccelStructureT::vertex_data_t& neighbor) {
40+
as.forEachBroadphaseNeighborCandidates(vertexData, [&, polygon, index](const typename AccelStructureT::vertex_data_t& neighbor) {
4141
const auto neighborRemappedIndex = remappedVertexIndexes[neighbor.index];
4242
if (shouldWeldFn(polygon, index, neighbor.index) && neighborRemappedIndex != INVALID_INDEX) {
4343
remappedVertexIndex = neighborRemappedIndex;

src/nbl/asset/utils/CSmoothNormalGenerator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData(const as
6262
vertices.add({ i + 2, 0, faceNormal * angleWages.z, v3});
6363
}
6464

65-
vertices.validate();
65+
vertices.bake();
6666

6767
return vertices;
6868
}
@@ -96,7 +96,7 @@ core::smart_refctd_ptr<ICPUPolygonGeometry> CSmoothNormalGenerator::processConne
9696
{
9797
auto normal = processedVertex.weightedNormal;
9898

99-
vertexHashMap.iterateBroadphaseCandidates(processedVertex, [&](const VertexHashMap::vertex_data_t& candidate)
99+
vertexHashMap.forEachBroadphaseNeighborCandidates(processedVertex, [&](const VertexHashMap::vertex_data_t& candidate)
100100
{
101101
if (compareVertexPosition(processedVertex.position, candidate.position, epsilon) &&
102102
vxcmp(processedVertex, candidate, polygon))

0 commit comments

Comments
 (0)