Skip to content

Commit 5acb40d

Browse files
author
kevyuu
committed
Fix normal comparison to use dot instead of value by value comparison
1 parent 28f73f5 commit 5acb40d

File tree

3 files changed

+252
-9
lines changed

3 files changed

+252
-9
lines changed
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
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+
template <typename T>
10+
concept HashGridVertexData = requires(T obj, T const cobj, uint32_t hash) {
11+
{ cobj.getHash() } -> std::same_as<uint32_t>;
12+
{ obj.setHash(hash) } -> std::same_as<void>;
13+
{ cobj.getPosition() } -> std::same_as<hlsl::float32_t3>;
14+
};
15+
16+
template <HashGridVertexData VertexData>
17+
class CVertexHashGrid
18+
{
19+
public:
20+
21+
using vertex_data_t = VertexData;
22+
using collection_t = core::vector<VertexData>;
23+
struct BucketBounds
24+
{
25+
collection_t::const_iterator begin;
26+
collection_t::const_iterator end;
27+
};
28+
29+
CVertexHashGrid(size_t _vertexCount, uint32_t _hashTableMaxSize, float _cellSize) :
30+
m_sorter(createSorter(_vertexCount)),
31+
m_hashTableMaxSize(_hashTableMaxSize),
32+
m_cellSize(_cellSize)
33+
{
34+
assert((core::isPoT(m_hashTableMaxSize)));
35+
36+
m_vertices.reserve(_vertexCount);
37+
}
38+
39+
//inserts vertex into hash table
40+
void add(VertexData&& vertex)
41+
{
42+
vertex.setHash(hash(vertex));
43+
m_vertices.push_back(vertex);
44+
}
45+
46+
void validate()
47+
{
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 );
51+
52+
if (finalSortedOutput != m_vertices.data())
53+
m_vertices.erase(m_vertices.begin(), m_vertices.begin() + oldSize);
54+
else
55+
m_vertices.resize(oldSize);
56+
}
57+
58+
const collection_t& vertices() const { return m_vertices; }
59+
60+
collection_t& vertices(){ return m_vertices; }
61+
62+
inline uint32_t getVertexCount() const { return m_vertices.size(); }
63+
64+
template <typename Fn>
65+
void iterateBroadphaseCandidates(const VertexData& vertex, Fn fn) const
66+
{
67+
std::array<uint32_t, 8> neighboringCells;
68+
const auto cellCount = getNeighboringCellHashes(neighboringCells.data(), vertex);
69+
70+
//iterate among all neighboring cells
71+
for (uint8_t i = 0; i < cellCount; i++)
72+
{
73+
const auto& neighborCell = neighboringCells[i];
74+
BucketBounds bounds = getBucketBoundsByHash(neighborCell);
75+
for (; bounds.begin != bounds.end; bounds.begin++)
76+
{
77+
const vertex_data_t& neighborVertex = *bounds.begin;
78+
if (&vertex != &neighborVertex)
79+
if (!fn(neighborVertex)) break;
80+
}
81+
}
82+
83+
};
84+
85+
private:
86+
struct KeyAccessor
87+
{
88+
_NBL_STATIC_INLINE_CONSTEXPR size_t key_bit_count = 32ull;
89+
90+
template<auto bit_offset, auto radix_mask>
91+
inline decltype(radix_mask) operator()(const VertexData& item) const
92+
{
93+
return static_cast<decltype(radix_mask)>(item.getHash() >> static_cast<uint32_t>(bit_offset)) & radix_mask;
94+
}
95+
};
96+
97+
static constexpr uint32_t primeNumber1 = 73856093;
98+
static constexpr uint32_t primeNumber2 = 19349663;
99+
static constexpr uint32_t primeNumber3 = 83492791;
100+
101+
static constexpr uint32_t invalidHash = 0xFFFFFFFF;
102+
103+
using sorter_t = std::variant<
104+
core::LSBSorter<KeyAccessor::key_bit_count, uint16_t>,
105+
core::LSBSorter<KeyAccessor::key_bit_count, uint32_t>,
106+
core::LSBSorter<KeyAccessor::key_bit_count, size_t>>;
107+
sorter_t m_sorter;
108+
109+
static sorter_t createSorter(size_t vertexCount)
110+
{
111+
if (vertexCount < (0x1ull << 16ull))
112+
return core::LSBSorter<KeyAccessor::key_bit_count, uint16_t>();
113+
if (vertexCount < (0x1ull << 32ull))
114+
return core::LSBSorter<KeyAccessor::key_bit_count, uint32_t>();
115+
return core::LSBSorter<KeyAccessor::key_bit_count, size_t>();
116+
}
117+
118+
collection_t m_vertices;
119+
const uint32_t m_hashTableMaxSize;
120+
const float m_cellSize;
121+
122+
uint32_t hash(const VertexData& vertex) const
123+
{
124+
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);
129+
}
130+
131+
uint32_t hash(const hlsl::uint32_t3& position) const
132+
{
133+
return ((position.x * primeNumber1) ^
134+
(position.y * primeNumber2) ^
135+
(position.z * primeNumber3))& (m_hashTableMaxSize - 1);
136+
}
137+
138+
uint8_t getNeighboringCellHashes(uint32_t* outNeighbors, const VertexData& vertex) const
139+
{
140+
hlsl::float32_t3 cellfloatcoord = floor(vertex.getPosition() / m_cellSize - hlsl::float32_t3(0.5));
141+
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));
142+
143+
uint8_t neighborCount = 0;
144+
145+
outNeighbors[neighborCount] = hash(baseCoord);
146+
neighborCount++;
147+
148+
auto addUniqueNeighbor = [&neighborCount, outNeighbors](uint32_t hashval)
149+
{
150+
if (std::find(outNeighbors, outNeighbors + neighborCount, hashval) == outNeighbors + neighborCount)
151+
{
152+
outNeighbors[neighborCount] = hashval;
153+
neighborCount++;
154+
}
155+
};
156+
157+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(0, 0, 1)));
158+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(0, 1, 0)));
159+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(1, 0, 0)));
160+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(1, 1, 0)));
161+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(1, 0, 1)));
162+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(0, 1, 1)));
163+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(1, 1, 1)));
164+
165+
return neighborCount;
166+
}
167+
168+
BucketBounds getBucketBoundsByHash(uint32_t hash) const
169+
{
170+
if (hash == invalidHash)
171+
return { m_vertices.end(), m_vertices.end() };
172+
173+
const auto skipListBound = std::visit([&](auto& sorter)
174+
{
175+
auto hashBound = sorter.getHashBound(hash);
176+
return std::pair<collection_t::const_iterator, collection_t::const_iterator>(m_vertices.begin() + hashBound.first, m_vertices.begin() + hashBound.second);
177+
}, m_sorter);
178+
179+
auto begin = std::lower_bound(
180+
skipListBound.first,
181+
skipListBound.second,
182+
hash,
183+
[](const VertexData& vertex, uint32_t hash)
184+
{
185+
return vertex.hash < hash;
186+
});
187+
188+
auto end = std::upper_bound(
189+
skipListBound.first,
190+
skipListBound.second,
191+
hash,
192+
[](uint32_t hash, const VertexData& vertex)
193+
{
194+
return hash < vertex.hash;
195+
});
196+
197+
const auto beginIx = begin - m_vertices.begin();
198+
const auto endIx = end - m_vertices.begin();
199+
//bucket missing
200+
if (begin == end)
201+
return { m_vertices.end(), m_vertices.end() };
202+
203+
//bucket missing
204+
if (begin->hash != hash)
205+
return { m_vertices.end(), m_vertices.end() };
206+
207+
return { begin, end };
208+
}
209+
};
210+
211+
}
212+
#endif

include/nbl/asset/utils/CVertexWelder.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ class CVertexWelder {
5151
}
5252
}
5353

54-
// TODO(kevinyu): Handle when indexBuffer is not exist
55-
5654
const auto& indexView = outPolygon->getIndexView();
5755
if (indexView)
5856
{

src/nbl/asset/utils/CPolygonGeometryManipulator.cpp

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ core::smart_refctd_ptr<ICPUPolygonGeometry> CPolygonGeometryManipulator::createU
135135

136136
namespace
137137
{
138-
static bool isAttributeEqual(const ICPUPolygonGeometry::SDataView& view, uint64_t index1, uint64_t index2, float epsilon)
138+
bool isAttributeValEqual(const ICPUPolygonGeometry::SDataView& view, uint64_t index1, uint64_t index2, float epsilon)
139139
{
140140
if (!view) return true;
141141
const auto channelCount = getFormatChannelCount(view.composed.format);
@@ -175,7 +175,40 @@ namespace
175175
}
176176
}
177177
return true;
178-
}
178+
}
179+
180+
bool isAttributeDirEqual(const ICPUPolygonGeometry::SDataView& view, uint64_t index1, uint64_t index2, float epsilon)
181+
{
182+
if (!view) return true;
183+
const auto channelCount = getFormatChannelCount(view.composed.format);
184+
switch (view.composed.rangeFormat)
185+
{
186+
case IGeometryBase::EAABBFormat::U64:
187+
case IGeometryBase::EAABBFormat::U32:
188+
{
189+
hlsl::uint64_t4 val1, val2;
190+
view.decodeElement<hlsl::uint64_t4>(index1, val1);
191+
view.decodeElement<hlsl::uint64_t4>(index2, val2);
192+
return (1.0 - hlsl::dot(val1, val2)) < epsilon;
193+
}
194+
case IGeometryBase::EAABBFormat::S64:
195+
case IGeometryBase::EAABBFormat::S32:
196+
{
197+
hlsl::int64_t4 val1, val2;
198+
view.decodeElement<hlsl::int64_t4>(index1, val1);
199+
view.decodeElement<hlsl::int64_t4>(index2, val2);
200+
return (1.0 - hlsl::dot(val1, val2)) < epsilon;
201+
}
202+
default:
203+
{
204+
hlsl::float64_t4 val1, val2;
205+
view.decodeElement<hlsl::float64_t4>(index1, val1);
206+
view.decodeElement<hlsl::float64_t4>(index2, val2);
207+
return (1.0 - hlsl::dot(val1, val2)) < epsilon;
208+
}
209+
}
210+
return true;
211+
}
179212
}
180213

181214

@@ -196,17 +229,17 @@ core::smart_refctd_ptr<ICPUPolygonGeometry> CPolygonGeometryManipulator::createS
196229

197230
auto canJoinVertices = [epsilon](const ICPUPolygonGeometry* polygon, uint32_t index1, uint32_t index2)-> bool
198231
{
199-
if (!isAttributeEqual(polygon->getPositionView(), index1, index2, epsilon))
232+
if (!isAttributeValEqual(polygon->getPositionView(), index1, index2, epsilon))
200233
return false;
201-
if (!isAttributeEqual(polygon->getNormalView(), index1, index2, epsilon))
234+
if (!isAttributeDirEqual(polygon->getNormalView(), index1, index2, epsilon))
202235
return false;
203236
for (const auto& jointWeightView : polygon->getJointWeightViews())
204237
{
205-
if (!isAttributeEqual(jointWeightView.indices, index1, index2, epsilon)) return false;
206-
if (!isAttributeEqual(jointWeightView.weights, index1, index2, epsilon)) return false;
238+
if (!isAttributeValEqual(jointWeightView.indices, index1, index2, epsilon)) return false;
239+
if (!isAttributeValEqual(jointWeightView.weights, index1, index2, epsilon)) return false;
207240
}
208241
for (const auto& auxAttributeView : polygon->getAuxAttributeViews())
209-
if (!isAttributeEqual(auxAttributeView, index1, index2, epsilon)) return false;
242+
if (!isAttributeValEqual(auxAttributeView, index1, index2, epsilon)) return false;
210243

211244
return true;
212245
};

0 commit comments

Comments
 (0)