Skip to content

Commit ef14edf

Browse files
Add a primitive reveral mode to IIndexingCallback::SContext
Make hash recompute disable-able in smooth normal calculation fix some bugs like bad ListIndexingCallbacks and missing return values
1 parent e2aa2bb commit ef14edf

5 files changed

Lines changed: 85 additions & 60 deletions

File tree

include/nbl/asset/IGeometryCollection.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ class NBL_API2 IGeometryCollection : public virtual core::IReferenceCounted
3434
if (jointRedirectView.getElementCount()<geometry->getJointCount())
3535
return false;
3636
}
37-
else
38-
return true;
37+
return true;
3938
}
4039

4140
inline bool hasTransform() const {return !core::isnan(transform[0][0]);}

include/nbl/asset/IPolygonGeometry.h

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "nbl/asset/IAccelerationStructure.h"
1111

1212
#include <span>
13+
#include <ranges>
1314

1415
namespace nbl::asset
1516
{
@@ -39,41 +40,53 @@ class IPolygonGeometryBase : public virtual core::IReferenceCounted
3940
template<typename OutT> requires (sizeof(OutT)<8 && hlsl::concepts::UnsignedIntegralScalar<OutT>)
4041
struct SContext final
4142
{
42-
// `indexOfIndex` is somewhat of a baseIndex
43-
template<typename Range>
44-
inline void streamOut(const uint32_t indexOfIndex, const Range& permutation)
45-
{
46-
auto& typedOut = reinterpret_cast<OutT*&>(out);
47-
if (indexBuffer)
48-
switch (indexSize)
43+
private:
44+
// `indexOfIndex` is somewhat of a baseIndex
45+
template<typename Range>
46+
inline void impl_streamOut(const uint32_t indexOfIndex, const Range permutation)
4947
{
50-
case 1:
51-
for (const auto relIx : permutation)
52-
*(typedOut++) = reinterpret_cast<const uint8_t*>(indexBuffer)[indexOfIndex+relIx];
53-
break;
54-
case 2:
55-
for (const auto relIx : permutation)
56-
*(typedOut++) = reinterpret_cast<const uint16_t*>(indexBuffer)[indexOfIndex+relIx];
57-
break;
58-
case 4:
59-
for (const auto relIx : permutation)
60-
*(typedOut++) = reinterpret_cast<const uint32_t*>(indexBuffer)[indexOfIndex+relIx];
61-
break;
62-
default:
63-
assert(false);
64-
break;
48+
auto& typedOut = reinterpret_cast<OutT*&>(out);
49+
if (indexBuffer)
50+
switch (indexSize)
51+
{
52+
case 1:
53+
for (const auto relIx : permutation)
54+
*(typedOut++) = reinterpret_cast<const uint8_t*>(indexBuffer)[indexOfIndex+relIx];
55+
break;
56+
case 2:
57+
for (const auto relIx : permutation)
58+
*(typedOut++) = reinterpret_cast<const uint16_t*>(indexBuffer)[indexOfIndex+relIx];
59+
break;
60+
case 4:
61+
for (const auto relIx : permutation)
62+
*(typedOut++) = reinterpret_cast<const uint32_t*>(indexBuffer)[indexOfIndex+relIx];
63+
break;
64+
default:
65+
assert(false);
66+
break;
67+
}
68+
else
69+
for (const auto relIx : permutation)
70+
*(typedOut++) = indexOfIndex+relIx;
6571
}
66-
else
67-
for (const auto relIx : permutation)
68-
*(typedOut++) = indexOfIndex+relIx;
69-
}
70-
71-
// always the base pointer, doesn't get advanced
72-
const void* const indexBuffer;
73-
const uint64_t indexSize : 3;
74-
const uint64_t beginPrimitive : 30;
75-
const uint64_t endPrimitive : 31;
76-
void* out;
72+
73+
public:
74+
template<std::ranges::view V> requires std::ranges::bidirectional_range<V>
75+
inline void streamOut(const uint32_t indexOfIndex, const V& permutation)
76+
{
77+
if (reversePrims)
78+
impl_streamOut(indexOfIndex,permutation|std::views::reverse);
79+
else
80+
impl_streamOut(indexOfIndex,permutation);
81+
}
82+
83+
// always the base pointer, doesn't get advanced
84+
const void* const indexBuffer;
85+
const uint64_t indexSize : 3;
86+
const uint64_t beginPrimitive : 30;
87+
const uint64_t endPrimitive : 30;
88+
const uint64_t reversePrims : 1 = false;
89+
void* out;
7790
};
7891
// could have been a static if not virtual
7992
virtual void operator()(SContext<uint8_t>& ctx) const = 0;

src/nbl/asset/ICPUPolygonGeometry.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ class CListIndexingCB final : public IPolygonGeometryBase::IIndexingCallback
1212
template<typename OutT>
1313
static void operator_impl(SContext<OutT>& ctx)
1414
{
15-
auto indexOfIndex = ctx.beginPrimitive*3;
16-
for (const auto end=ctx.endPrimitive*3; indexOfIndex!=end; indexOfIndex+=3)
15+
auto indexOfIndex = ctx.beginPrimitive*Order;
16+
for (const auto end=ctx.endPrimitive*Order; indexOfIndex!=end; indexOfIndex+=Order)
1717
ctx.streamOut(indexOfIndex,std::ranges::iota_view{0,int(Order)});
1818
}
1919

@@ -70,7 +70,7 @@ class CTriangleStripIndexingCB final : public IPolygonGeometryBase::IIndexingCal
7070
indexOfIndex = ctx.beginPrimitive+2;
7171
const int32_t perm[] = {-1,-2,0};
7272
for (const auto end=ctx.endPrimitive+2; indexOfIndex!=end; indexOfIndex++)
73-
ctx.streamOut(indexOfIndex,perm);
73+
ctx.streamOut<std::span<const int32_t>>(indexOfIndex,perm);
7474
}
7575

7676
public:
@@ -106,7 +106,7 @@ class CTriangleFanIndexingCB final : public IPolygonGeometryBase::IIndexingCallb
106106
{
107107
// first index is always global 0
108108
perm[0] = -indexOfIndex;
109-
ctx.streamOut(indexOfIndex,perm);
109+
ctx.streamOut<std::span<const int32_t>>(indexOfIndex,perm);
110110
}
111111
}
112112

src/nbl/asset/utils/CSmoothNormalGenerator.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,18 @@ static bool compareVertexPosition(const hlsl::float32_t3& a, const hlsl::float32
2929
return (difference.x <= epsilon && difference.y <= epsilon && difference.z <= epsilon);
3030
}
3131

32-
CSmoothNormalGenerator::Result CSmoothNormalGenerator::calculateNormals(const asset::ICPUPolygonGeometry* polygon, float epsilon, VxCmpFunction vxcmp)
32+
CSmoothNormalGenerator::Result CSmoothNormalGenerator::calculateNormals(const asset::ICPUPolygonGeometry* polygon, float epsilon, VxCmpFunction vxcmp, const bool recomputeHash)
3333
{
3434
assert(polygon->getIndexingCallback()->degree() == 3);
35+
3536
static constexpr auto MinEpsilon = 0.00001f;
3637
const auto patchedEpsilon = epsilon < MinEpsilon ? MinEpsilon : epsilon;
3738
VertexHashMap vertexHashMap = setupData(polygon, patchedEpsilon);
39+
3840
const auto smoothPolygon = processConnectedVertices(polygon, vertexHashMap, patchedEpsilon,vxcmp);
41+
if (recomputeHash)
42+
CPolygonGeometryManipulator::recomputeContentHashes(smoothPolygon.get());
43+
3944
return { vertexHashMap, smoothPolygon };
4045
}
4146

@@ -51,33 +56,42 @@ CSmoothNormalGenerator::VertexHashMap CSmoothNormalGenerator::setupData(const as
5156
{
5257
//calculate face normal of parent triangle
5358
hlsl::float32_t3 v0, v1, v2;
59+
// TODO: could iterate over an index buffer properly
5460
polygon->getPositionView().decodeElement<hlsl::float32_t3>(i, v0);
5561
polygon->getPositionView().decodeElement<hlsl::float32_t3>(i + 1, v1);
5662
polygon->getPositionView().decodeElement<hlsl::float32_t3>(i + 2, v2);
5763

58-
const auto faceNormal = normalize(cross(v1 - v0, v2 - v0));
64+
auto faceNormal = cross(v1 - v0, v2 - v0);
65+
// if any triangle edge is 0 length, the cross product will be 0 length too
66+
const float normLen2 = dot(faceNormal,faceNormal);
67+
// need to filter invalid triangles while we're at it
68+
if (normLen2<hlsl::numeric_limits<float>::min)
69+
continue;
70+
faceNormal *= hlsl::rsqrt(normLen2);
5971

6072
//set data for m_vertices
61-
const auto angleWages = hlsl::shapes::util::anglesFromTriangleEdges(v2 - v1, v0 - v2, v1 - v2);
73+
const auto angleWeights = hlsl::shapes::util::anglesFromTriangleEdges(v2 - v1, v0 - v2, v1 - v2);
6274

63-
vertices.add({ i, 0, faceNormal * angleWages.x, v0});
64-
vertices.add({ i + 1, 0, faceNormal * angleWages.y,v1});
65-
vertices.add({ i + 2, 0, faceNormal * angleWages.z, v2});
75+
vertices.add({ i, 0, faceNormal * angleWeights.x, v0});
76+
vertices.add({ i + 1, 0, faceNormal * angleWeights.y,v1});
77+
vertices.add({ i + 2, 0, faceNormal * angleWeights.z, v2});
6678
}
6779

6880
vertices.bake();
6981

7082
return vertices;
7183
}
7284

73-
core::smart_refctd_ptr<ICPUPolygonGeometry> CSmoothNormalGenerator::processConnectedVertices(const asset::ICPUPolygonGeometry* polygon, VertexHashMap& vertexHashMap, float epsilon, VxCmpFunction vxcmp)
85+
core::smart_refctd_ptr<ICPUPolygonGeometry> CSmoothNormalGenerator::processConnectedVertices(const asset::ICPUPolygonGeometry* polygon, VertexHashMap& vertexHashMap, const float epsilon, VxCmpFunction vxcmp)
7486
{
87+
// TODO: its semi doable to defer unwelding/rewelding until later an just work on a duplicated normal buffer only
7588
auto outPolygon = core::move_and_static_cast<ICPUPolygonGeometry>(polygon->clone(0u));
7689
static constexpr auto NormalFormat = EF_R32G32B32_SFLOAT;
7790
const auto normalFormatBytesize = asset::getTexelOrBlockBytesize(NormalFormat);
7891
auto normalBuf = ICPUBuffer::create({ normalFormatBytesize * outPolygon->getPositionView().getElementCount()});
7992
auto normalView = polygon->getNormalView();
8093

94+
// TODO: compute actual range
8195
hlsl::shapes::AABB<4,hlsl::float32_t> aabb;
8296
aabb.maxVx = hlsl::float32_t4(1, 1, 1, 0.f);
8397
aabb.minVx = -aabb.maxVx;
@@ -118,8 +132,6 @@ core::smart_refctd_ptr<ICPUPolygonGeometry> CSmoothNormalGenerator::processConne
118132
memcpy(normalPtr + (normalStride * processedVertex.index), &normal, sizeof(normal));
119133
}
120134

121-
CPolygonGeometryManipulator::recomputeContentHashes(outPolygon.get());
122-
123135
return outPolygon;
124136
}
125137

src/nbl/asset/utils/CSmoothNormalGenerator.h

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,20 @@ namespace nbl::asset
1111
{
1212

1313
// TODO: implement a class template that take position type(either float32_t3 or float64_t3 as template argument
14-
class CSmoothNormalGenerator
14+
class CSmoothNormalGenerator final
1515
{
1616
public:
1717
CSmoothNormalGenerator() = delete;
1818
~CSmoothNormalGenerator() = delete;
1919

20-
struct VertexData
21-
{
22-
uint32_t index; //offset of the vertex into index buffer
20+
struct VertexData
21+
{
22+
//offset of the vertex into index buffer
23+
uint32_t index;
2324
uint32_t hash;
24-
hlsl::float32_t3 weightedNormal;
25-
hlsl::float32_t3 position; //position of the vertex in 3D space
25+
hlsl::float32_t3 weightedNormal;
26+
//position of the vertex in 3D space
27+
hlsl::float32_t3 position;
2628

2729
hlsl::float32_t3 getPosition() const
2830
{
@@ -39,21 +41,20 @@ class CSmoothNormalGenerator
3941
return hash;
4042
};
4143

42-
};
44+
};
4345

4446
using VxCmpFunction = std::function<bool(const VertexData&, const VertexData&, const ICPUPolygonGeometry*)>;
4547

4648
using VertexHashMap = CVertexHashGrid<VertexData>;
4749

48-
struct Result
49-
{
50+
struct Result
51+
{
5052
VertexHashMap vertexHashGrid;
5153
core::smart_refctd_ptr<ICPUPolygonGeometry> geom;
52-
};
53-
static Result calculateNormals(const ICPUPolygonGeometry* polygon, float epsilon, VxCmpFunction function);
54+
};
55+
static Result calculateNormals(const ICPUPolygonGeometry* polygon, float epsilon, VxCmpFunction function, const bool recomputeHash=true);
5456

5557
private:
56-
5758
static VertexHashMap setupData(const ICPUPolygonGeometry* polygon, float epsilon);
5859
static core::smart_refctd_ptr<ICPUPolygonGeometry> processConnectedVertices(const ICPUPolygonGeometry* polygon, VertexHashMap& vertices, float epsilon, VxCmpFunction vxcmp);
5960
};

0 commit comments

Comments
 (0)