2023-12-23 18:26:54 +01:00
|
|
|
#include "Meshlet.h"
|
|
|
|
|
#include "Containers/List.h"
|
2024-06-09 12:20:04 +02:00
|
|
|
#include "Containers/Map.h"
|
2023-12-23 18:26:54 +01:00
|
|
|
#include "Containers/Set.h"
|
2024-04-24 23:25:34 +02:00
|
|
|
#include <iostream>
|
2023-12-23 18:26:54 +01:00
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
|
2023-12-23 18:26:54 +01:00
|
|
|
using namespace Seele;
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
struct AdjacencyInfo {
|
2024-04-08 11:38:55 +02:00
|
|
|
Array<uint32> trianglesPerVertex;
|
|
|
|
|
Array<uint32> indexBufferOffset;
|
|
|
|
|
Array<uint32> triangleData;
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void buildAdjacency(const uint32 numVerts, const Array<uint32>& indices, AdjacencyInfo& info) {
|
2024-04-08 11:38:55 +02:00
|
|
|
info.trianglesPerVertex.resize(numVerts, 0);
|
2024-06-09 12:20:04 +02:00
|
|
|
for (size_t i = 0; i < indices.size(); ++i) {
|
2024-04-08 11:38:55 +02:00
|
|
|
info.trianglesPerVertex[indices[i]]++;
|
|
|
|
|
}
|
|
|
|
|
uint32 triangleOffset = 0;
|
|
|
|
|
info.indexBufferOffset.resize(numVerts, 0);
|
2024-06-09 12:20:04 +02:00
|
|
|
for (size_t j = 0; j < numVerts; ++j) {
|
2024-04-08 11:38:55 +02:00
|
|
|
info.indexBufferOffset[j] = triangleOffset;
|
|
|
|
|
triangleOffset += info.trianglesPerVertex[j];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32 numTriangles = indices.size() / 3;
|
|
|
|
|
info.triangleData.resize(triangleOffset);
|
|
|
|
|
Array<uint32> offsets = info.indexBufferOffset;
|
2024-06-09 12:20:04 +02:00
|
|
|
for (uint32 k = 0; k < numTriangles; ++k) {
|
2024-04-08 11:38:55 +02:00
|
|
|
int a = indices[k * 3];
|
|
|
|
|
int b = indices[k * 3 + 1];
|
|
|
|
|
int c = indices[k * 3 + 2];
|
|
|
|
|
|
|
|
|
|
info.triangleData[offsets[a]++] = k;
|
|
|
|
|
info.triangleData[offsets[b]++] = k;
|
|
|
|
|
info.triangleData[offsets[c]++] = k;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
int32 skipDeadEnd(const Array<uint32>& liveTriCount, List<uint32>& deadEndStack, uint32& cursor) {
|
|
|
|
|
while (!deadEndStack.empty()) {
|
2024-04-08 11:38:55 +02:00
|
|
|
uint32 vertIdx = deadEndStack.front();
|
|
|
|
|
deadEndStack.popFront();
|
2024-06-09 12:20:04 +02:00
|
|
|
if (liveTriCount[vertIdx] > 0) {
|
2024-04-08 11:38:55 +02:00
|
|
|
return vertIdx;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
while (cursor < liveTriCount.size()) {
|
|
|
|
|
if (liveTriCount[cursor] > 0) {
|
2024-04-08 11:38:55 +02:00
|
|
|
return cursor;
|
|
|
|
|
}
|
|
|
|
|
++cursor;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
int32 getNextVertex(const uint32 cacheSize, const Array<uint32>& oneRing, const Array<uint32>& cacheTimeStamps, const uint32 timeStamp,
|
|
|
|
|
const Array<uint32>& liveTriCount, List<uint32>& deadEndStack, uint32& cursor) {
|
2024-04-08 11:38:55 +02:00
|
|
|
uint32 bestCandidate = std::numeric_limits<uint32>::max();
|
|
|
|
|
int highestPriority = -1;
|
2024-06-09 12:20:04 +02:00
|
|
|
for (const uint32& vertIdx : oneRing) {
|
|
|
|
|
if (liveTriCount[vertIdx] > 0) {
|
2024-04-08 11:38:55 +02:00
|
|
|
int priority = 0;
|
2024-06-09 12:20:04 +02:00
|
|
|
if (timeStamp - cacheTimeStamps[vertIdx] + 2 * liveTriCount[vertIdx] <= cacheSize) {
|
2024-04-08 11:38:55 +02:00
|
|
|
priority = timeStamp - cacheTimeStamps[vertIdx];
|
|
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
if (priority > highestPriority) {
|
2024-04-08 11:38:55 +02:00
|
|
|
highestPriority = priority;
|
|
|
|
|
bestCandidate = vertIdx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
if (bestCandidate == std::numeric_limits<uint32>::max()) {
|
2024-04-08 11:38:55 +02:00
|
|
|
bestCandidate = skipDeadEnd(liveTriCount, deadEndStack, cursor);
|
|
|
|
|
}
|
|
|
|
|
return bestCandidate;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void tipsifyIndexBuffer(const Array<uint32>& indices, const uint32 numVerts, const uint32 cacheSize, Array<uint32>& outIndices) {
|
2024-04-08 11:38:55 +02:00
|
|
|
AdjacencyInfo adjacencyStruct;
|
|
|
|
|
buildAdjacency(numVerts, indices, adjacencyStruct);
|
|
|
|
|
|
|
|
|
|
Array<uint32> liveTriCount = adjacencyStruct.trianglesPerVertex;
|
|
|
|
|
|
|
|
|
|
Array<uint32> cacheTimeStamps(numVerts);
|
|
|
|
|
|
|
|
|
|
List<uint32> deadEndStack;
|
|
|
|
|
|
|
|
|
|
Array<bool> emittedTriangles(indices.size() / 3);
|
|
|
|
|
|
2024-04-09 16:41:12 +02:00
|
|
|
int32 curVert = 0;
|
2024-04-08 11:38:55 +02:00
|
|
|
uint32 timeStamp = cacheSize + 1;
|
|
|
|
|
uint32 cursor = 1;
|
2024-06-09 12:20:04 +02:00
|
|
|
while (curVert != -1) {
|
2024-04-08 11:38:55 +02:00
|
|
|
Array<uint32> oneRing;
|
|
|
|
|
const uint32* startTriPointer = &adjacencyStruct.triangleData[0] + adjacencyStruct.indexBufferOffset[curVert];
|
|
|
|
|
const uint32* endTriPointer = startTriPointer + adjacencyStruct.trianglesPerVertex[curVert];
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
for (const uint32* it = startTriPointer; it != endTriPointer; ++it) {
|
2024-04-08 11:38:55 +02:00
|
|
|
uint32 triangle = *it;
|
|
|
|
|
|
|
|
|
|
if (emittedTriangles[triangle])
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
uint32 a = indices[triangle * 3 + 0];
|
|
|
|
|
uint32 b = indices[triangle * 3 + 1];
|
|
|
|
|
uint32 c = indices[triangle * 3 + 2];
|
|
|
|
|
|
|
|
|
|
outIndices.add(a);
|
|
|
|
|
outIndices.add(b);
|
|
|
|
|
outIndices.add(c);
|
|
|
|
|
|
|
|
|
|
deadEndStack.add(a);
|
|
|
|
|
deadEndStack.add(b);
|
|
|
|
|
deadEndStack.add(c);
|
|
|
|
|
|
|
|
|
|
oneRing.add(a);
|
|
|
|
|
oneRing.add(b);
|
|
|
|
|
oneRing.add(c);
|
|
|
|
|
|
|
|
|
|
liveTriCount[a]--;
|
|
|
|
|
liveTriCount[b]--;
|
|
|
|
|
liveTriCount[c]--;
|
|
|
|
|
|
|
|
|
|
if (timeStamp - cacheTimeStamps[a] > cacheSize) {
|
|
|
|
|
cacheTimeStamps[a] = timeStamp;
|
|
|
|
|
}
|
|
|
|
|
if (timeStamp - cacheTimeStamps[b] > cacheSize) {
|
|
|
|
|
cacheTimeStamps[b] = timeStamp;
|
|
|
|
|
}
|
|
|
|
|
if (timeStamp - cacheTimeStamps[c] > cacheSize) {
|
|
|
|
|
cacheTimeStamps[c] = timeStamp;
|
|
|
|
|
}
|
|
|
|
|
emittedTriangles[triangle] = true;
|
|
|
|
|
}
|
|
|
|
|
curVert = getNextVertex(cacheSize, oneRing, cacheTimeStamps, timeStamp, liveTriCount, deadEndStack, cursor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
struct Triangle {
|
2024-04-05 10:41:59 +02:00
|
|
|
StaticArray<uint32, 3> indices;
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
int findIndex(Meshlet& current, uint32 index) {
|
|
|
|
|
for (uint32 i = 0; i < current.numVertices; ++i) {
|
|
|
|
|
if (current.uniqueVertices[i] == index) {
|
2024-04-05 10:41:59 +02:00
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
if (current.numVertices == Gfx::numVerticesPerMeshlet) {
|
2024-04-05 10:41:59 +02:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
current.uniqueVertices[current.numVertices] = index;
|
|
|
|
|
|
|
|
|
|
return current.numVertices++;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
void completeMeshlet(Array<Meshlet>& meshlets, Meshlet& current) {
|
2024-04-05 10:41:59 +02:00
|
|
|
meshlets.add(current);
|
|
|
|
|
current = {
|
2024-04-06 08:29:15 +02:00
|
|
|
.boundingBox = AABB(),
|
2024-04-05 10:41:59 +02:00
|
|
|
.numVertices = 0,
|
|
|
|
|
.numPrimitives = 0,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 22:47:51 +02:00
|
|
|
bool addTriangle(const Array<Vector4>& positions, Meshlet& current, Triangle& tri) {
|
2024-04-05 10:41:59 +02:00
|
|
|
int f1 = findIndex(current, tri.indices[0]);
|
|
|
|
|
int f2 = findIndex(current, tri.indices[1]);
|
|
|
|
|
int f3 = findIndex(current, tri.indices[2]);
|
|
|
|
|
|
2024-06-09 12:20:04 +02:00
|
|
|
if (f1 == -1 || f2 == -1 || f3 == -1 || current.numPrimitives == Gfx::numPrimitivesPerMeshlet) {
|
2024-04-07 22:55:17 +02:00
|
|
|
return false;
|
2024-04-05 10:41:59 +02:00
|
|
|
}
|
2024-04-07 22:55:17 +02:00
|
|
|
current.boundingBox.adjust(positions[tri.indices[0]]);
|
|
|
|
|
current.boundingBox.adjust(positions[tri.indices[1]]);
|
|
|
|
|
current.boundingBox.adjust(positions[tri.indices[2]]);
|
2024-04-05 10:41:59 +02:00
|
|
|
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++;
|
2024-04-07 22:55:17 +02:00
|
|
|
return true;
|
2024-04-05 10:41:59 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-13 22:47:51 +02:00
|
|
|
void Meshlet::build(const Array<Vector4>& positions, const Array<uint32>& indices, Array<Meshlet>& meshlets) {
|
2023-12-23 18:26:54 +01:00
|
|
|
Meshlet current = {
|
|
|
|
|
.numVertices = 0,
|
|
|
|
|
.numPrimitives = 0,
|
|
|
|
|
};
|
2024-06-09 12:20:04 +02:00
|
|
|
// Array<uint32> optimizedIndices = indices;
|
|
|
|
|
// tipsifyIndexBuffer(indices, positions.size(), 25, optimizedIndices);
|
2024-04-24 23:25:34 +02:00
|
|
|
Array<Triangle> triangles(indices.size() / 3);
|
2024-06-09 12:20:04 +02:00
|
|
|
for (size_t i = 0; i < triangles.size(); ++i) {
|
2024-04-07 22:55:17 +02:00
|
|
|
triangles[i] = Triangle{
|
2024-06-09 12:20:04 +02:00
|
|
|
.indices =
|
|
|
|
|
{
|
|
|
|
|
indices[i * 3 + 0],
|
|
|
|
|
indices[i * 3 + 1],
|
|
|
|
|
indices[i * 3 + 2],
|
|
|
|
|
},
|
2024-04-07 22:55:17 +02:00
|
|
|
};
|
|
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
while (!triangles.empty()) {
|
|
|
|
|
if (!addTriangle(positions, current, triangles.back())) {
|
2024-04-08 11:38:55 +02:00
|
|
|
completeMeshlet(meshlets, current);
|
|
|
|
|
addTriangle(positions, current, triangles.back());
|
|
|
|
|
}
|
|
|
|
|
triangles.pop();
|
2024-04-07 16:33:32 +02:00
|
|
|
}
|
2024-06-09 12:20:04 +02:00
|
|
|
if (current.numVertices > 0) {
|
2024-04-07 16:33:32 +02:00
|
|
|
completeMeshlet(meshlets, current);
|
2023-12-23 18:26:54 +01:00
|
|
|
}
|
|
|
|
|
}
|