Skip to content

Commit ff2558b

Browse files
committed
Merge branch 'master' of github.com:Devsh-Graphics-Programming/Nabla into ies
2 parents 2eadc3b + 9b4f730 commit ff2558b

40 files changed

+2531
-3106
lines changed

include/nbl/asset/utils/CPolygonGeometryManipulator.h

Lines changed: 56 additions & 63 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/CSmoothNormalGenerator.h"
1213

1314
namespace nbl::asset
1415
{
@@ -17,17 +18,6 @@ namespace nbl::asset
1718
class NBL_API2 CPolygonGeometryManipulator
1819
{
1920
public:
20-
//vertex data needed for CSmoothNormalGenerator
21-
struct SSNGVertexData
22-
{
23-
uint32_t index; //offset of the vertex into index buffer
24-
uint32_t hash; //
25-
float wage; //angle wage of the vertex
26-
hlsl::float32_t3 position; //position of the vertex in 3D space
27-
hlsl::float32_t3 parentTriangleFaceNormal; //
28-
};
29-
30-
using VxCmpFunction = std::function<bool(const SSNGVertexData&, const SSNGVertexData&, const ICPUPolygonGeometry*)>;
3121

3222
static inline void recomputeContentHashes(ICPUPolygonGeometry* geo)
3323
{
@@ -243,11 +233,14 @@ class NBL_API2 CPolygonGeometryManipulator
243233

244234
static core::smart_refctd_ptr<ICPUPolygonGeometry> createUnweldedList(const ICPUPolygonGeometry* inGeo);
245235

236+
using SSNGVertexData = CSmoothNormalGenerator::VertexData;
237+
using SSNGVxCmpFunction = CSmoothNormalGenerator::VxCmpFunction;
238+
246239
static core::smart_refctd_ptr<ICPUPolygonGeometry> createSmoothVertexNormal(const ICPUPolygonGeometry* inbuffer, bool enableWelding = false, float epsilon = 1.525e-5f,
247-
VxCmpFunction vxcmp = [](const CPolygonGeometryManipulator::SSNGVertexData& v0, const CPolygonGeometryManipulator::SSNGVertexData& v1, const ICPUPolygonGeometry* buffer)
240+
SSNGVxCmpFunction vxcmp = [](const SSNGVertexData& v0, const SSNGVertexData& v1, const ICPUPolygonGeometry* buffer)
248241
{
249-
static constexpr float cosOf45Deg = 0.70710678118f;
250-
return dot(v0.parentTriangleFaceNormal,v1.parentTriangleFaceNormal) > cosOf45Deg;
242+
constexpr float cosOf45Deg = 0.70710678118f;
243+
return dot(normalize(v0.weightedNormal),normalize(v1.weightedNormal)) > cosOf45Deg;
251244
});
252245

253246
#if 0 // TODO: REDO
@@ -277,14 +270,14 @@ class NBL_API2 CPolygonGeometryManipulator
277270
};
278271
typedef std::function<bool(const IMeshManipulator::SSNGVertexData&, const IMeshManipulator::SSNGVertexData&, ICPUMeshBuffer*)> VxCmpFunction;
279272

280-
//! Compares two attributes of floating point types in accordance with passed error metric.
281-
/**
282-
@param _a First attribute.
283-
@param _b Second attribute.
284-
@param _cpa Component count.
285-
@param _errMetric Error metric info.
286-
*/
287-
static inline bool compareFloatingPointAttribute(const core::vectorSIMDf& _a, const core::vectorSIMDf& _b, size_t _cpa, const SErrorMetric& _errMetric)
273+
//! Compares two attributes of floating point types in accordance with passed error metric.
274+
/**
275+
@param _a First attribute.
276+
@param _b Second attribute.
277+
@param _cpa Component count.
278+
@param _errMetric Error metric info.
279+
*/
280+
static inline bool compareFloatingPointAttribute(const core::vectorSIMDf& _a, const core::vectorSIMDf& _b, size_t _cpa, const SErrorMetric& _errMetric)
288281
{
289282
using ErrorF_t = core::vectorSIMDf(*)(core::vectorSIMDf, core::vectorSIMDf);
290283

@@ -365,41 +358,41 @@ class NBL_API2 CPolygonGeometryManipulator
365358
}
366359

367360

368-
//! Swaps the index buffer for a new index buffer with invalid triangles removed.
369-
/**
370-
Invalid triangle is such consisting of two or more same indices.
371-
@param _input Input index buffer.
372-
@param _idxType Type of indices in the index buffer.
373-
@returns New index buffer or nullptr if input indices were of unknown type or _input was nullptr.
374-
*/
375-
static void filterInvalidTriangles(ICPUMeshBuffer* _input);
376-
377-
//! Creates index buffer from input converting it to indices for line list primitives. Input is assumed to be indices for line strip.
378-
/**
379-
@param _input Input index buffer's data.
380-
@param _idxCount Index count.
381-
@param _inIndexType Type of input index buffer data (32bit or 16bit).
382-
@param _outIndexType Type of output index buffer data (32bit or 16bit).
383-
*/
384-
static core::smart_refctd_ptr<ICPUBuffer> idxBufferFromLineStripsToLines(const void* _input, uint32_t& _idxCount, E_INDEX_TYPE _inIndexType, E_INDEX_TYPE _outIndexType);
385-
386-
//! Creates index buffer from input converting it to indices for triangle list primitives. Input is assumed to be indices for triangle strip.
387-
/**
388-
@param _input Input index buffer's data.
389-
@param _idxCount Index count.
390-
@param _inIndexType Type of input index buffer data (32bit or 16bit).
391-
@param _outIndexType Type of output index buffer data (32bit or 16bit).
392-
*/
393-
static core::smart_refctd_ptr<ICPUBuffer> idxBufferFromTriangleStripsToTriangles(const void* _input, uint32_t& _idxCount, E_INDEX_TYPE _inIndexType, E_INDEX_TYPE _outIndexType);
394-
395-
//! Creates index buffer from input converting it to indices for triangle list primitives. Input is assumed to be indices for triangle fan.
396-
/**
397-
@param _input Input index buffer's data.
398-
@param _idxCount Index count.
399-
@param _inIndexType Type of input index buffer data (32bit or 16bit).
400-
@param _outIndexType Type of output index buffer data (32bit or 16bit).
401-
*/
402-
static core::smart_refctd_ptr<ICPUBuffer> idxBufferFromTrianglesFanToTriangles(const void* _input, uint32_t& _idxCount, E_INDEX_TYPE _inIndexType, E_INDEX_TYPE _outIndexType);
361+
//! Swaps the index buffer for a new index buffer with invalid triangles removed.
362+
/**
363+
Invalid triangle is such consisting of two or more same indices.
364+
@param _input Input index buffer.
365+
@param _idxType Type of indices in the index buffer.
366+
@returns New index buffer or nullptr if input indices were of unknown type or _input was nullptr.
367+
*/
368+
static void filterInvalidTriangles(ICPUMeshBuffer* _input);
369+
370+
//! Creates index buffer from input converting it to indices for line list primitives. Input is assumed to be indices for line strip.
371+
/**
372+
@param _input Input index buffer's data.
373+
@param _idxCount Index count.
374+
@param _inIndexType Type of input index buffer data (32bit or 16bit).
375+
@param _outIndexType Type of output index buffer data (32bit or 16bit).
376+
*/
377+
static core::smart_refctd_ptr<ICPUBuffer> idxBufferFromLineStripsToLines(const void* _input, uint32_t& _idxCount, E_INDEX_TYPE _inIndexType, E_INDEX_TYPE _outIndexType);
378+
379+
//! Creates index buffer from input converting it to indices for triangle list primitives. Input is assumed to be indices for triangle strip.
380+
/**
381+
@param _input Input index buffer's data.
382+
@param _idxCount Index count.
383+
@param _inIndexType Type of input index buffer data (32bit or 16bit).
384+
@param _outIndexType Type of output index buffer data (32bit or 16bit).
385+
*/
386+
static core::smart_refctd_ptr<ICPUBuffer> idxBufferFromTriangleStripsToTriangles(const void* _input, uint32_t& _idxCount, E_INDEX_TYPE _inIndexType, E_INDEX_TYPE _outIndexType);
387+
388+
//! Creates index buffer from input converting it to indices for triangle list primitives. Input is assumed to be indices for triangle fan.
389+
/**
390+
@param _input Input index buffer's data.
391+
@param _idxCount Index count.
392+
@param _inIndexType Type of input index buffer data (32bit or 16bit).
393+
@param _outIndexType Type of output index buffer data (32bit or 16bit).
394+
*/
395+
static core::smart_refctd_ptr<ICPUBuffer> idxBufferFromTrianglesFanToTriangles(const void* _input, uint32_t& _idxCount, E_INDEX_TYPE _inIndexType, E_INDEX_TYPE _outIndexType);
403396

404397
//!
405398
static inline std::array<uint32_t,3u> getTriangleIndices(const ICPUMeshBuffer* mb, uint32_t triangleIx)
@@ -635,7 +628,7 @@ class NBL_API2 CPolygonGeometryManipulator
635628

636629
//! Creates a copy of a mesh with vertices welded
637630
/** \param mesh Input mesh
638-
\param errMetrics Array of size EVAI_COUNT. Describes error metric for each vertex attribute (used if attribute is of floating point or normalized type).
631+
\param errMetrics Array of size EVAI_COUNT. Describes error metric for each vertex attribute (used if attribute is of floating point or normalized type).
639632
\param tolerance The threshold for vertex comparisons.
640633
\return Mesh without redundant vertices. */
641634
static core::smart_refctd_ptr<ICPUMeshBuffer> createMeshBufferWelded(ICPUMeshBuffer *inbuffer, const SErrorMetric* errMetrics, const bool& optimIndexType = true, const bool& makeNewMesh = false);
@@ -653,12 +646,12 @@ class NBL_API2 CPolygonGeometryManipulator
653646
*/
654647
static void requantizeMeshBuffer(ICPUMeshBuffer* _meshbuffer, const SErrorMetric* _errMetric);
655648

656-
//! Creates a 32bit index buffer for a mesh with primitive types changed to list types
657-
/**#
649+
//! Creates a 32bit index buffer for a mesh with primitive types changed to list types
650+
/**#
658651
@param _newPrimitiveType
659-
@param _begin non-const iterator to beginning of meshbuffer range
660-
@param _end non-const iterator to ending of meshbuffer range
661-
*/
652+
@param _begin non-const iterator to beginning of meshbuffer range
653+
@param _end non-const iterator to ending of meshbuffer range
654+
*/
662655
template<typename Iterator>
663656
static inline void homogenizePrimitiveTypeAndIndices(Iterator _begin, Iterator _end, const E_PRIMITIVE_TOPOLOGY _newPrimitiveType, const E_INDEX_TYPE outIndexType = EIT_32BIT)
664657
{
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
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 <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+
23+
// TODO: implement a class template that take position type(either float32_t3 or float64_t3 as template argument
24+
template <HashGridVertexData VertexData>
25+
class CVertexHashGrid
26+
{
27+
public:
28+
29+
using vertex_data_t = VertexData;
30+
using collection_t = core::vector<VertexData>;
31+
struct BucketBounds
32+
{
33+
collection_t::const_iterator begin;
34+
collection_t::const_iterator end;
35+
};
36+
37+
inline CVertexHashGrid(float cellSize, uint32_t hashTableMaxSizeLog2, size_t vertexCountReserve = 8192) :
38+
m_cellSize(cellSize),
39+
m_hashTableMaxSize(1llu << hashTableMaxSizeLog2),
40+
m_sorter(createSorter(vertexCountReserve))
41+
{
42+
m_vertices.reserve(vertexCountReserve);
43+
}
44+
45+
//inserts vertex into hash table
46+
inline void add(VertexData&& vertex)
47+
{
48+
vertex.setHash(hash(vertex));
49+
m_vertices.push_back(std::move(vertex));
50+
}
51+
52+
inline void bake()
53+
{
54+
auto scratchBuffer = collection_t(m_vertices.size());
55+
56+
auto finalSortedOutput = std::visit( [&](auto& sorter)
57+
{
58+
return sorter(m_vertices.data(), scratchBuffer.data(), m_vertices.size(), KeyAccessor());
59+
}, m_sorter );
60+
61+
if (finalSortedOutput != m_vertices.data())
62+
m_vertices = std::move(scratchBuffer);
63+
}
64+
65+
inline const collection_t& vertices() const { return m_vertices; }
66+
67+
inline uint32_t getVertexCount() const { return m_vertices.size(); }
68+
69+
template <HashGridIteratorFn<VertexData> Fn>
70+
inline void forEachBroadphaseNeighborCandidates(const hlsl::float32_t3& position, Fn&& fn) const
71+
{
72+
std::array<uint32_t, 8> neighboringCells;
73+
const auto cellCount = getNeighboringCellHashes(neighboringCells.data(), position);
74+
75+
//iterate among all neighboring cells
76+
for (uint8_t i = 0; i < cellCount; i++)
77+
{
78+
const auto& neighborCell = neighboringCells[i];
79+
BucketBounds bounds = getBucketBoundsByHash(neighborCell);
80+
for (; bounds.begin != bounds.end; bounds.begin++)
81+
{
82+
const vertex_data_t& neighborVertex = *bounds.begin;
83+
if (!std::invoke(std::forward<Fn>(fn), neighborVertex)) break;
84+
}
85+
}
86+
}
87+
88+
private:
89+
struct KeyAccessor
90+
{
91+
constexpr static inline size_t key_bit_count = 32ull;
92+
93+
template<auto bit_offset, auto radix_mask>
94+
inline decltype(radix_mask) operator()(const VertexData& item) const
95+
{
96+
return static_cast<decltype(radix_mask)>(item.getHash() >> static_cast<uint32_t>(bit_offset)) & radix_mask;
97+
}
98+
};
99+
100+
static constexpr inline uint32_t primeNumber1 = 73856093;
101+
static constexpr inline uint32_t primeNumber2 = 19349663;
102+
static constexpr inline uint32_t primeNumber3 = 83492791;
103+
104+
using sorter_t = std::variant<
105+
core::RadixLsbSorter<KeyAccessor::key_bit_count, uint16_t>,
106+
core::RadixLsbSorter<KeyAccessor::key_bit_count, uint32_t>,
107+
core::RadixLsbSorter<KeyAccessor::key_bit_count, size_t>>;
108+
sorter_t m_sorter;
109+
110+
inline static sorter_t createSorter(size_t vertexCount)
111+
{
112+
if (vertexCount < (0x1ull << 16ull))
113+
return core::RadixLsbSorter<KeyAccessor::key_bit_count, uint16_t>();
114+
if (vertexCount < (0x1ull << 32ull))
115+
return core::RadixLsbSorter<KeyAccessor::key_bit_count, uint32_t>();
116+
return core::RadixLsbSorter<KeyAccessor::key_bit_count, size_t>();
117+
}
118+
119+
collection_t m_vertices;
120+
const uint32_t m_hashTableMaxSize;
121+
const float m_cellSize;
122+
123+
inline uint32_t hash(const VertexData& vertex) const
124+
{
125+
const hlsl::float32_t3 position = floor(vertex.getPosition() / m_cellSize);
126+
const auto position_uint32 = hlsl::uint32_t3(position.x, position.y, position.z);
127+
return hash(position_uint32);
128+
}
129+
130+
inline uint32_t hash(const hlsl::uint32_t3& position) const
131+
{
132+
return ((position.x * primeNumber1) ^
133+
(position.y * primeNumber2) ^
134+
(position.z * primeNumber3))& (m_hashTableMaxSize - 1);
135+
}
136+
137+
inline uint8_t getNeighboringCellHashes(uint32_t* outNeighbors, hlsl::float32_t3 position) const
138+
{
139+
// We substract the coordinate by 0.5 since the cellSize is expected to be twice the epsilon. This is to snap the vertex into the cell that contain the most bottom left cell that could collide with of our vertex.
140+
// ------- -------
141+
// | | y| | | |
142+
// | |x | | |y |
143+
// ------- -> -------
144+
// | | | | x| |
145+
// | | | | | |
146+
// ------- -------
147+
// |2e|e|
148+
// In the example,x is snapped into a different cell which is the most bottom left cell that could collide with x. Since we have move it into its bottom left candidate, there is no need to check to the bottom and to the left of the snapped coordinate. We only need to check the upper and to the right of the snapped cell, which include the original cell. Note that we do not need to check the upper and to the right of the original cell. The cell size is 2 * epsilon and x is located on the lower and lefter side of the cell.
149+
// Contrary to x, y is still snapped into its original cell. It means the most bottom left cell that collide with y is its own cell.
150+
// The above scheme is to reduce the number of cell candidates that we need to check for collision, from 9 cell to 4 cell in 2d, or from 27 cells to 8 cells in 3d.
151+
// 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.
152+
hlsl::float32_t3 cellfloatcoord = floor(position / m_cellSize - hlsl::float32_t3(0.5));
153+
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));
154+
155+
uint8_t neighborCount = 0;
156+
157+
outNeighbors[neighborCount] = hash(baseCoord);
158+
neighborCount++;
159+
160+
auto addUniqueNeighbor = [&neighborCount, outNeighbors](uint32_t hashval)
161+
{
162+
if (std::find(outNeighbors, outNeighbors + neighborCount, hashval) == outNeighbors + neighborCount)
163+
{
164+
outNeighbors[neighborCount] = hashval;
165+
neighborCount++;
166+
}
167+
};
168+
169+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(0, 0, 1)));
170+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(0, 1, 0)));
171+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(1, 0, 0)));
172+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(1, 1, 0)));
173+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(1, 0, 1)));
174+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(0, 1, 1)));
175+
addUniqueNeighbor(hash(baseCoord + hlsl::uint32_t3(1, 1, 1)));
176+
177+
return neighborCount;
178+
}
179+
180+
inline BucketBounds getBucketBoundsByHash(uint32_t hash) const
181+
{
182+
const auto skipListBound = std::visit([&](auto& sorter)
183+
{
184+
auto hashBound = sorter.getMostSignificantRadixBound(hash);
185+
return std::pair<collection_t::const_iterator, collection_t::const_iterator>(m_vertices.begin() + hashBound.first, m_vertices.begin() + hashBound.second);
186+
}, m_sorter);
187+
188+
auto begin = std::lower_bound(
189+
skipListBound.first,
190+
skipListBound.second,
191+
hash,
192+
[](const VertexData& vertex, uint32_t hash)
193+
{
194+
return vertex.getHash() < hash;
195+
});
196+
197+
auto end = std::upper_bound(
198+
skipListBound.first,
199+
skipListBound.second,
200+
hash,
201+
[](uint32_t hash, const VertexData& vertex)
202+
{
203+
return hash < vertex.getHash();
204+
});
205+
206+
const auto beginIx = begin - m_vertices.begin();
207+
const auto endIx = end - m_vertices.begin();
208+
//bucket missing
209+
if (begin == end)
210+
return { m_vertices.end(), m_vertices.end() };
211+
212+
//bucket missing
213+
if (begin->hash != hash)
214+
return { m_vertices.end(), m_vertices.end() };
215+
216+
return { begin, end };
217+
}
218+
};
219+
220+
}
221+
#endif

0 commit comments

Comments
 (0)