Fixing tree and adding unit tests

This commit is contained in:
Dynamitos
2023-12-23 18:26:54 +01:00
parent c8f99bb64d
commit 95dcfda1cd
11 changed files with 272 additions and 98 deletions
+3
View File
@@ -15,6 +15,8 @@ target_sources(Engine
Initializer.cpp
Mesh.h
Mesh.cpp
Meshlet.h
Meshlet.cpp
Pipeline.h
Pipeline.cpp
RenderTarget.h
@@ -43,6 +45,7 @@ target_sources(Engine
Graphics.h
Initializer.h
Mesh.h
Meshlet.h
Pipeline.h
RenderTarget.h
Resources.h
+203
View File
@@ -0,0 +1,203 @@
#include "Meshlet.h"
#include "Containers/Map.h"
#include "Containers/List.h"
#include "Containers/Set.h"
using namespace Seele;
// Tipsy algorithm by Sanders 2007
struct Triangle
{
bool emitted = false;
StaticArray<uint32, 3> indices;
};
Map<uint32, List<Triangle>> buildAdjacency(const Array<uint32>& indices)
{
Map<uint32, List<Triangle>> result;
for (uint32 i = 0; i < indices.size(); i += 3)
{
result[indices[i + 0]].add(Triangle{
.emitted = false,
.indices = {
indices[i + 0],
indices[i + 1],
indices[i + 2],
}
});
result[indices[i + 1]].add(Triangle{
.emitted = false,
.indices = {
indices[i + 0],
indices[i + 1],
indices[i + 2],
}
});
result[indices[i + 2]].add(Triangle{
.emitted = false,
.indices = {
indices[i + 0],
indices[i + 1],
indices[i + 2],
}
});
}
return result;
}
Map<uint32, uint32> getTriangleCounts(Map<uint32, List<Triangle>>& adjacency)
{
Map<uint32, uint32> result;
for (const auto& [index, list] : adjacency)
{
result[index] = list.size();
}
return result;
}
int32 skipDeadEnd(Map<uint32, uint32>& L, Array<uint32>& D, const Array<uint32>& indices, uint32& i, uint32 vertexCount)
{
while (!D.empty())
{
uint32 d = D.back();
D.pop();
if (L[d] > 0)
{
return d;
}
}
while (i < vertexCount)
{
i++;
if (L[i] > 0)
{
return i;
}
}
return -1;
}
uint32 getNextVertex(const Array<uint32>& indices, uint32& i, uint32 cacheSize, Set<uint32> N, const Array<uint32>& C, uint32 s, Map<uint32, uint32>& L, Array<uint32>& D, uint32 vertexCount)
{
int32 n = -1;
int32 p = -1;
int32 m = 0;
for (uint32 v : N)
{
if (L[v] > 0)
{
p = 0;
if (s - C[v] + 2 * L[v] <= cacheSize)
{
p = s - C[v];
}
if (p > m)
{
m = p;
n = v;
}
}
}
if (n == -1)
{
n = skipDeadEnd(L, D, indices, i, vertexCount);
}
return n;
}
Array<uint32> tipsify(const Array<Vector>& positions, const Array<uint32>& indices, uint32 cacheSize)
{
auto A = buildAdjacency(indices);
auto L = getTriangleCounts(A);
auto C = Array<uint32>(positions.size(), 0);
auto D = Array<uint32>();
Array<uint32> output;
int32 f = 0;
uint32 s = cacheSize + 1, i = 1;
while (f >= 0)
{
auto N = Set<uint32>();
for (Triangle t : A[f])
{
if (!t.emitted)
{
for (uint32 v : t.indices)
{
output.add(v);
D.add(v);
N.insert(v);
L[v] = L[v] - 1;
if (s - C[v] > cacheSize)
{
C[v] = s;
s = s + 1;
}
}
t.emitted = true;
}
}
f = getNextVertex(indices, i, cacheSize, std::move(N), C, s, L, D, positions.size());
}
return output;
}
void Meshlet::build(const Array<Vector>& positions, const Array<uint32>& indices, Array<Meshlet>& meshlets)
{
Meshlet current = {
.numVertices = 0,
.numPrimitives = 0,
};
auto findIndex = [&current](uint32 index) -> int {
for (uint32 i = 0; i < current.numVertices; ++i)
{
if (current.uniqueVertices[i] == index)
{
return i;
}
}
if (current.numVertices == Gfx::numVerticesPerMeshlet)
{
return -1;
}
current.uniqueVertices[current.numVertices] = index;
return current.numVertices++;
};
auto completeMeshlet = [&positions, &meshlets, &current]() {
for (uint32 i = 0; i < current.numVertices; ++i)
{
current.boundingBox.adjust(positions[current.uniqueVertices[i]]);
}
meshlets.add(current);
current = {
.numVertices = 0,
.numPrimitives = 0,
};
};
for (size_t faceIndex = 0; faceIndex < indices.size() / 3; ++faceIndex)
{
int f1 = findIndex(indices[faceIndex * 3 + 0]);
int f2 = findIndex(indices[faceIndex * 3 + 1]);
int f3 = findIndex(indices[faceIndex * 3 + 2]);
if (f1 == -1 || f2 == -1 || f1 == -1)
{
completeMeshlet();
f1 = findIndex(indices[faceIndex * 3 + 0]);
f2 = findIndex(indices[faceIndex * 3 + 1]);
f3 = findIndex(indices[faceIndex * 3 + 2]);
}
current.primitiveLayout[current.numPrimitives * 3 + 0] = uint8(f1);
current.primitiveLayout[current.numPrimitives * 3 + 1] = uint8(f2);
current.primitiveLayout[current.numPrimitives * 3 + 2] = uint8(f3);
current.numPrimitives++;
if (current.numPrimitives == Gfx::numPrimitivesPerMeshlet)
{
completeMeshlet();
}
}
if (current.numVertices > 0)
{
completeMeshlet();
}
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "Math/AABB.h"
#include "Graphics/Enums.h"
namespace Seele
{
struct Meshlet
{
AABB boundingBox;
uint32 uniqueVertices[Gfx::numVerticesPerMeshlet]; // unique vertiex indices in the vertex data
uint8 primitiveLayout[Gfx::numPrimitivesPerMeshlet * 3]; // indices into the uniqueVertices array, only uint8 needed
uint32 numVertices;
uint32 numPrimitives;
static void build(const Array<Vector>& positions, const Array<uint32>& indices, Array<Meshlet>& meshlets);
};
} // namespace Seele
+1 -70
View File
@@ -117,6 +117,7 @@ void VertexData::loadMesh(MeshId id, Array<uint32> loadedIndices, Array<Meshlet>
.primitiveCount = m.numPrimitives,
.vertexOffset = vertexOffset,
.primitiveOffset = primitiveOffset,
.color = Vector((float)rand() / RAND_MAX,(float)rand() / RAND_MAX,(float)rand() / RAND_MAX),
});
}
meshData[id].add(MeshData{
@@ -245,73 +246,3 @@ VertexData::VertexData()
, dirty(false)
{
}
void Meshlet::build(const Array<uint32>& indices, Array<Meshlet>& meshlets)
{
Map<uint32, Set<uint32>> connectivity;
for (uint32 i = 0; i < indices.size(); i+=3)
{
connectivity[indices[i]].insert(indices[i + 1]);
connectivity[indices[i]].insert(indices[i + 2]);
}
Meshlet current = {
.numVertices = 0,
.numPrimitives = 0,
};
auto findIndex = [&current](uint32 index) -> int {
for (uint32 i = 0; i < current.numVertices; ++i)
{
if (current.uniqueVertices[i] == index)
{
return i;
}
}
if (current.numVertices == Gfx::numVerticesPerMeshlet)
{
return -1;
}
current.uniqueVertices[current.numVertices] = index;
return current.numVertices++;
};
auto completeMeshlet = [&meshlets, &current]() {
meshlets.add(current);
current = {
.numVertices = 0,
.numPrimitives = 0,
};
};
for (size_t faceIndex = 0; faceIndex < indices.size() / 3; ++faceIndex)
{
int f1 = findIndex(indices[faceIndex * 3 + 0]);
int f2 = findIndex(indices[faceIndex * 3 + 1]);
int f3 = findIndex(indices[faceIndex * 3 + 2]);
if (f1 == -1 || f2 == -1 || f1 == -1)
{
completeMeshlet();
f1 = findIndex(indices[faceIndex * 3 + 0]);
f2 = findIndex(indices[faceIndex * 3 + 1]);
f3 = findIndex(indices[faceIndex * 3 + 2]);
}
current.primitiveLayout[current.numPrimitives * 3 + 0] = uint8(f1);
current.primitiveLayout[current.numPrimitives * 3 + 1] = uint8(f2);
current.primitiveLayout[current.numPrimitives * 3 + 2] = uint8(f3);
current.numPrimitives++;
if (current.numPrimitives == Gfx::numPrimitivesPerMeshlet)
{
completeMeshlet();
}
}
if (current.numVertices > 0)
{
completeMeshlet();
}
}
void Meshlet::calcBoundingBox(const Array<Vector>& positions)
{
for (uint32 i = 0; i < numVertices; ++i)
{
boundingBox.adjust(positions[uniqueVertices[i]]);
}
}
+3 -11
View File
@@ -6,7 +6,7 @@
#include "Graphics/Command.h"
#include "Graphics/Descriptor.h"
#include "Graphics/Buffer.h"
#include "Math/AABB.h"
#include "Meshlet.h"
namespace Seele
{
@@ -23,16 +23,6 @@ struct MeshId
return id == other.id;
}
};
struct Meshlet
{
AABB boundingBox;
uint32 uniqueVertices[Gfx::numVerticesPerMeshlet]; // unique vertiex indices in the vertex data
uint8 primitiveLayout[Gfx::numPrimitivesPerMeshlet * 3]; // indices into the uniqueVertices array, only uint8 needed
uint32 numVertices;
uint32 numPrimitives;
static void build(const Array<uint32>& indices, Array<Meshlet>& meshlets);
void calcBoundingBox(const Array<Vector>& positions);
};
class VertexData
{
public:
@@ -99,6 +89,8 @@ protected:
uint32_t primitiveCount;
uint32_t vertexOffset;
uint32_t primitiveOffset;
Vector color;
float pad;
};
std::mutex materialDataLock;
Map<std::string, MaterialData> materialData;