Skip to content

Commit ce99287

Browse files
author
kevyuu
committed
Move VertexHashMap into its own file
1 parent 0dd02e8 commit ce99287

File tree

7 files changed

+252
-200
lines changed

7 files changed

+252
-200
lines changed

include/nbl/asset/utils/CPolygonGeometryManipulator.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "nbl/asset/ICPUPolygonGeometry.h"
1111
#include "nbl/asset/utils/CGeometryManipulator.h"
12+
#include "nbl/asset/utils/CVertexHashMap.h"
1213

1314
namespace nbl::asset
1415
{
@@ -17,14 +18,8 @@ namespace nbl::asset
1718
class NBL_API2 CPolygonGeometryManipulator
1819
{
1920
public:
20-
//vertex data needed for CSmoothNormalGenerator
21-
struct SSNGVertexData
22-
{
23-
uint64_t index; //offset of the vertex into index buffer
24-
uint32_t hash; //
25-
hlsl::float32_t3 weightedNormal;
26-
hlsl::float32_t3 position; //position of the vertex in 3D space
27-
};
21+
22+
using SSNGVertexData = CVertexHashMap::VertexData;
2823

2924
using VxCmpFunction = std::function<bool(const SSNGVertexData&, const SSNGVertexData&, const ICPUPolygonGeometry*)>;
3025

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#ifndef _NBL_ASSET_C_VERTEX_HASH_MAP_H_INCLUDED_
2+
#define _NBL_ASSET_C_VERTEX_HASH_MAP_H_INCLUDED_
3+
4+
#include "nbl/core/declarations.h"
5+
6+
namespace nbl::asset
7+
{
8+
9+
class CVertexHashMap
10+
{
11+
public:
12+
13+
struct VertexData
14+
{
15+
uint64_t index; //offset of the vertex into index buffer
16+
uint32_t hash; //
17+
hlsl::float32_t3 weightedNormal;
18+
hlsl::float32_t3 position; //position of the vertex in 3D space
19+
};
20+
21+
using collection_t = core::vector<VertexData>;
22+
struct BucketBounds
23+
{
24+
collection_t::iterator begin;
25+
collection_t::iterator end;
26+
};
27+
28+
29+
CVertexHashMap(size_t _vertexCount, uint32_t _hashTableMaxSize, float _cellSize);
30+
31+
//inserts vertex into hash table
32+
void add(VertexData&& vertex);
33+
34+
//sorts hashtable and sets iterators at beginnings of bucktes
35+
void validate();
36+
37+
inline uint32_t getVertexCount() const { return m_vertices.size(); }
38+
39+
uint8_t getNeighboringCellHashes(uint32_t* outNeighbours, const VertexData& vertex);
40+
41+
BucketBounds getBucketBoundsByHash(uint32_t hash);
42+
43+
const collection_t& vertices() const { return m_vertices; }
44+
45+
private:
46+
struct KeyAccessor
47+
{
48+
_NBL_STATIC_INLINE_CONSTEXPR size_t key_bit_count = 32ull;
49+
50+
template<auto bit_offset, auto radix_mask>
51+
inline decltype(radix_mask) operator()(const VertexData& item) const
52+
{
53+
return static_cast<decltype(radix_mask)>(item.hash >> static_cast<uint32_t>(bit_offset)) & radix_mask;
54+
}
55+
};
56+
57+
static constexpr uint32_t invalidHash = 0xFFFFFFFF;
58+
static constexpr uint32_t primeNumber1 = 73856093;
59+
static constexpr uint32_t primeNumber2 = 19349663;
60+
static constexpr uint32_t primeNumber3 = 83492791;
61+
62+
using sorter_t = std::variant<
63+
core::LSBSorter<KeyAccessor::key_bit_count, uint16_t>,
64+
core::LSBSorter<KeyAccessor::key_bit_count, uint32_t>,
65+
core::LSBSorter<KeyAccessor::key_bit_count, size_t>>;
66+
sorter_t m_sorter;
67+
68+
static sorter_t createSorter(size_t vertexCount)
69+
{
70+
if (vertexCount < (0x1ull << 16ull))
71+
return core::LSBSorter<KeyAccessor::key_bit_count, uint16_t>();
72+
if (vertexCount < (0x1ull << 32ull))
73+
return core::LSBSorter<KeyAccessor::key_bit_count, uint32_t>();
74+
return core::LSBSorter<KeyAccessor::key_bit_count, size_t>();
75+
}
76+
77+
collection_t m_vertices;
78+
const uint32_t m_hashTableMaxSize;
79+
const float m_cellSize;
80+
81+
uint32_t hash(const VertexData& vertex) const;
82+
uint32_t hash(const hlsl::uint32_t3& position) const;
83+
84+
};
85+
86+
}
87+
#endif
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O.
2+
// This file is part of the "Nabla Engine".
3+
// For conditions of distribution and use, see copyright notice in nabla.h
4+
#ifndef _NBL_ASSET_C_POLYGON_VERTEX_WELDER_H_INCLUDED_
5+
#define _NBL_ASSET_C_POLYGON_VERTEX_WELDER_H_INCLUDED_
6+
7+
#include "nbl/asset/utils/CPolygonGeometryManipulator.h"
8+
9+
namespace nbl::asset {
10+
11+
class CVertexWelder {
12+
13+
template <typename AccelStructureT>
14+
static core::smart_refctd_ptr<ICPUPolygonGeometry> weldVertices(const ICPUPolygonGeometry* polygon, const AccelStructureT& vertices, float epsilon);
15+
};
16+
17+
}
18+
19+
#endif

src/nbl/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ set(NBL_ASSET_SOURCES
184184
asset/utils/CPolygonGeometryManipulator.cpp
185185
asset/utils/COverdrawPolygonGeometryOptimizer.cpp
186186
asset/utils/CSmoothNormalGenerator.cpp
187+
asset/utils/CVertexHashMap.cpp
187188

188189
# Mesh loaders
189190
asset/interchange/COBJMeshFileLoader.cpp

src/nbl/asset/utils/CSmoothNormalGenerator.cpp

Lines changed: 0 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -84,79 +84,6 @@ core::smart_refctd_ptr<ICPUPolygonGeometry> CSmoothNormalGenerator::calculateNor
8484
return smoothPolygon;
8585
}
8686

87-
CSmoothNormalGenerator::VertexHashMap::VertexHashMap(size_t _vertexCount, uint32_t _hashTableMaxSize, float _cellSize) :
88-
m_sorter(createSorter(_vertexCount)),
89-
m_hashTableMaxSize(_hashTableMaxSize),
90-
m_cellSize(_cellSize)
91-
{
92-
assert((core::isPoT(m_hashTableMaxSize)));
93-
94-
m_vertices.reserve(_vertexCount);
95-
}
96-
97-
uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const CPolygonGeometryManipulator::SSNGVertexData & vertex) const
98-
{
99-
const hlsl::float32_t3 position = vertex.position / m_cellSize;
100-
101-
return ((static_cast<uint32_t>(position.x) * primeNumber1) ^
102-
(static_cast<uint32_t>(position.y) * primeNumber2) ^
103-
(static_cast<uint32_t>(position.z) * primeNumber3))& (m_hashTableMaxSize - 1);
104-
}
105-
106-
uint32_t CSmoothNormalGenerator::VertexHashMap::hash(const hlsl::uint32_t3& position) const
107-
{
108-
return ((position.x * primeNumber1) ^
109-
(position.y * primeNumber2) ^
110-
(position.z * primeNumber3))& (m_hashTableMaxSize - 1);
111-
}
112-
113-
void CSmoothNormalGenerator::VertexHashMap::add(CPolygonGeometryManipulator::SSNGVertexData && vertex)
114-
{
115-
vertex.hash = hash(vertex);
116-
m_vertices.push_back(vertex);
117-
}
118-
119-
CSmoothNormalGenerator::VertexHashMap::BucketBounds CSmoothNormalGenerator::VertexHashMap::getBucketBoundsByHash(uint32_t hash)
120-
{
121-
if (hash == invalidHash)
122-
return { m_vertices.end(), m_vertices.end() };
123-
124-
const auto skipListBound = std::visit([&](auto& sorter)
125-
{
126-
auto hashBound = sorter.getHashBound(hash);
127-
return std::pair<collection_t::iterator, collection_t::iterator>(m_vertices.begin() + hashBound.first, m_vertices.begin() + hashBound.second);
128-
}, m_sorter);
129-
130-
auto begin = std::lower_bound(skipListBound.first, skipListBound.second, hash);
131-
auto end = std::upper_bound(skipListBound.first, skipListBound.second, hash);
132-
133-
//bucket missing
134-
if (begin == m_vertices.end())
135-
return { m_vertices.end(), m_vertices.end() };
136-
137-
//bucket missing
138-
if (begin->hash != hash)
139-
return { m_vertices.end(), m_vertices.end() };
140-
141-
return { begin, end };
142-
}
143-
144-
void CSmoothNormalGenerator::VertexHashMap::validate()
145-
{
146-
const auto oldSize = m_vertices.size();
147-
m_vertices.resize(oldSize*2u);
148-
// TODO: maybe use counting sort (or big radix) and use the histogram directly for the m_buckets
149-
auto finalSortedOutput = std::visit( [&](auto& sorter) { return sorter(m_vertices.data(), m_vertices.data() + oldSize, oldSize, KeyAccessor()); },m_sorter );
150-
// TODO: optimize out the erase
151-
if (finalSortedOutput != m_vertices.data())
152-
m_vertices.erase(m_vertices.begin(), m_vertices.begin() + oldSize);
153-
else
154-
m_vertices.resize(oldSize);
155-
156-
// TODO: are `m_buckets` even begin USED!?
157-
uint16_t prevHash = m_vertices[0].hash;
158-
core::vector<CPolygonGeometryManipulator::SSNGVertexData>::iterator prevBegin = m_vertices.begin();
159-
}
16087

16188
CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData(const asset::ICPUPolygonGeometry* polygon, float epsilon)
16289
{
@@ -243,56 +170,6 @@ core::smart_refctd_ptr<ICPUPolygonGeometry> CSmoothNormalGenerator::processConne
243170
return outPolygon;
244171
}
245172

246-
uint8_t CSmoothNormalGenerator::VertexHashMap::getNeighboringCellHashes(uint32_t* outNeighbours, const CPolygonGeometryManipulator::SSNGVertexData& vertex)
247-
{
248-
hlsl::float32_t3 cellFloatCoord = floor(vertex.position / m_cellSize - hlsl::float32_t3(0.5f));
249-
hlsl::uint32_t3 neighbor = hlsl::uint32_t3(static_cast<uint32_t>(cellFloatCoord.x), static_cast<uint32_t>(cellFloatCoord.y), static_cast<uint32_t>(cellFloatCoord.z));
250-
251-
uint8_t neighbourCount = 0;
252-
253-
//left bottom near
254-
outNeighbours[neighbourCount] = hash(neighbor);
255-
neighbourCount++;
256-
257-
auto addUniqueNeighbour = [&neighbourCount, outNeighbours](uint32_t hashVal)
258-
{
259-
if (std::find(outNeighbours, outNeighbours + neighbourCount, hashVal) != outNeighbours + neighbourCount)
260-
{
261-
outNeighbours[neighbourCount] = hashVal;
262-
neighbourCount++;
263-
}
264-
};
265-
266-
//right bottom near
267-
neighbor = neighbor + hlsl::uint32_t3(1, 0, 0);
268-
addUniqueNeighbour(hash(neighbor));
269-
270-
//right bottom far
271-
neighbor = neighbor + hlsl::uint32_t3(0, 0, 1);
272-
addUniqueNeighbour(hash(neighbor));
273-
274-
//left bottom far
275-
neighbor = neighbor - hlsl::uint32_t3(1, 0, 0);
276-
addUniqueNeighbour(hash(neighbor));
277-
278-
//left top far
279-
neighbor = neighbor + hlsl::uint32_t3(0, 1, 0);
280-
addUniqueNeighbour(hash(neighbor));
281-
282-
//right top far
283-
neighbor = neighbor + hlsl::uint32_t3(1, 0, 0);
284-
addUniqueNeighbour(hash(neighbor));
285-
286-
//righ top near
287-
neighbor = neighbor - hlsl::uint32_t3(0, 0, 1);
288-
addUniqueNeighbour(hash(neighbor));
289-
290-
//left top near
291-
neighbor = neighbor - hlsl::uint32_t3(1, 0, 0);
292-
addUniqueNeighbour(hash(neighbor));
293-
294-
return neighbourCount;
295-
}
296173

297174
core::smart_refctd_ptr<ICPUPolygonGeometry> CSmoothNormalGenerator::weldVertices(const ICPUPolygonGeometry* polygon, VertexHashMap& vertices, float epsilon)
298175
{

src/nbl/asset/utils/CSmoothNormalGenerator.h

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -19,76 +19,8 @@ class CSmoothNormalGenerator
1919
static core::smart_refctd_ptr<ICPUPolygonGeometry> calculateNormals(const ICPUPolygonGeometry* polygon, bool enableWelding, float epsilon, CPolygonGeometryManipulator::VxCmpFunction function);
2020

2121
private:
22-
class VertexHashMap
23-
{
24-
public:
25-
using collection_t = core::vector<CPolygonGeometryManipulator::SSNGVertexData>;
26-
struct BucketBounds
27-
{
28-
collection_t::iterator begin;
29-
collection_t::iterator end;
30-
};
22+
using VertexHashMap = CVertexHashMap;
3123

32-
33-
public:
34-
VertexHashMap(size_t _vertexCount, uint32_t _hashTableMaxSize, float _cellSize);
35-
36-
//inserts vertex into hash table
37-
void add(CPolygonGeometryManipulator::SSNGVertexData&& vertex);
38-
39-
//sorts hashtable and sets iterators at beginnings of bucktes
40-
void validate();
41-
42-
inline uint32_t getVertexCount() const { return m_vertices.size(); }
43-
44-
uint8_t getNeighboringCellHashes(uint32_t* outNeighbours, const CPolygonGeometryManipulator::SSNGVertexData& vertex);
45-
46-
BucketBounds getBucketBoundsByHash(uint32_t hash);
47-
48-
const collection_t& vertices() const { return m_vertices; }
49-
50-
private:
51-
struct KeyAccessor
52-
{
53-
_NBL_STATIC_INLINE_CONSTEXPR size_t key_bit_count = 32ull;
54-
55-
template<auto bit_offset, auto radix_mask>
56-
inline decltype(radix_mask) operator()(const CPolygonGeometryManipulator::SSNGVertexData& item) const
57-
{
58-
return static_cast<decltype(radix_mask)>(item.hash>>static_cast<uint32_t>(bit_offset))&radix_mask;
59-
}
60-
};
61-
62-
static constexpr uint32_t invalidHash = 0xFFFFFFFF;
63-
static constexpr uint32_t primeNumber1 = 73856093;
64-
static constexpr uint32_t primeNumber2 = 19349663;
65-
static constexpr uint32_t primeNumber3 = 83492791;
66-
67-
using sorter_t = std::variant<
68-
core::LSBSorter<KeyAccessor::key_bit_count, uint16_t>,
69-
core::LSBSorter<KeyAccessor::key_bit_count, uint32_t>,
70-
core::LSBSorter<KeyAccessor::key_bit_count, size_t>>;
71-
sorter_t m_sorter;
72-
73-
static sorter_t createSorter(size_t vertexCount)
74-
{
75-
if (vertexCount < (0x1ull << 16ull))
76-
return core::LSBSorter<KeyAccessor::key_bit_count,uint16_t>();
77-
if (vertexCount< (0x1ull << 32ull))
78-
return core::LSBSorter<KeyAccessor::key_bit_count,uint32_t>();
79-
return core::LSBSorter<KeyAccessor::key_bit_count,size_t>();
80-
}
81-
82-
collection_t m_vertices;
83-
const uint32_t m_hashTableMaxSize;
84-
const float m_cellSize;
85-
86-
uint32_t hash(const CPolygonGeometryManipulator::SSNGVertexData& vertex) const;
87-
uint32_t hash(const hlsl::uint32_t3& position) const;
88-
89-
};
90-
91-
private:
9224
static VertexHashMap setupData(const ICPUPolygonGeometry* polygon, float epsilon);
9325
static core::smart_refctd_ptr<ICPUPolygonGeometry> processConnectedVertices(const ICPUPolygonGeometry* polygon, VertexHashMap& vertices, float epsilon, CPolygonGeometryManipulator::VxCmpFunction vxcmp);
9426
static core::smart_refctd_ptr<ICPUPolygonGeometry> weldVertices(const ICPUPolygonGeometry* polygon, VertexHashMap& vertices, float epsilon);

0 commit comments

Comments
 (0)