From fc277c4d9a7380e45b1d6326dffb13e21b4a3583 Mon Sep 17 00:00:00 2001 From: Dynamitos Date: Mon, 8 Apr 2024 11:38:55 +0200 Subject: [PATCH] Implement Tipsify --- src/Engine/Graphics/Meshlet.cpp | 213 ++++++++++++++++++++++------- src/Engine/Graphics/VertexData.cpp | 74 +++++----- 2 files changed, 200 insertions(+), 87 deletions(-) diff --git a/src/Engine/Graphics/Meshlet.cpp b/src/Engine/Graphics/Meshlet.cpp index 23fc4b4..b30aea3 100644 --- a/src/Engine/Graphics/Meshlet.cpp +++ b/src/Engine/Graphics/Meshlet.cpp @@ -5,12 +5,159 @@ using namespace Seele; +struct AdjacencyInfo +{ + Array trianglesPerVertex; + Array indexBufferOffset; + Array triangleData; +}; + +void buildAdjacency(const uint32 numVerts, const Array& indices, AdjacencyInfo& info) +{ + info.trianglesPerVertex.resize(numVerts, 0); + for (int i = 0; i < indices.size(); ++i) + { + info.trianglesPerVertex[indices[i]]++; + } + uint32 triangleOffset = 0; + info.indexBufferOffset.resize(numVerts, 0); + for (int j = 0; j < numVerts; ++j) + { + info.indexBufferOffset[j] = triangleOffset; + triangleOffset += info.trianglesPerVertex[j]; + } + + uint32 numTriangles = indices.size() / 3; + info.triangleData.resize(triangleOffset); + Array offsets = info.indexBufferOffset; + for (uint32 k = 0; k < numTriangles; ++k) + { + 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; + } +} + +uint32 skipDeadEnd(const Array& liveTriCount, List& deadEndStack, uint32& cursor) +{ + while (!deadEndStack.empty()) + { + uint32 vertIdx = deadEndStack.front(); + deadEndStack.popFront(); + if (liveTriCount[vertIdx] > 0) + { + return vertIdx; + } + } + while (cursor < liveTriCount.size()) + { + if (liveTriCount[cursor] > 0) + { + return cursor; + } + ++cursor; + } + return -1; +} + +uint32 getNextVertex(const int cacheSize, const Array& oneRing, const Array& cacheTimeStamps, const uint32 timeStamp, const Array& liveTriCount, List& deadEndStack, uint32& cursor) +{ + uint32 bestCandidate = std::numeric_limits::max(); + int highestPriority = -1; + for (const uint32& vertIdx : oneRing) + { + if (liveTriCount[vertIdx] > 0) + { + int priority = 0; + if (timeStamp - cacheTimeStamps[vertIdx] + 2 * liveTriCount[vertIdx] <= cacheSize) + { + priority = timeStamp - cacheTimeStamps[vertIdx]; + } + if (priority > highestPriority) + { + highestPriority = priority; + bestCandidate = vertIdx; + } + } + } + if(bestCandidate == std::numeric_limits::max()) + { + bestCandidate = skipDeadEnd(liveTriCount, deadEndStack, cursor); + } + return bestCandidate; +} + +void tipsifyIndexBuffer(const Array& indices, const uint32 numVerts, const int cacheSize, Array& outIndices) +{ + AdjacencyInfo adjacencyStruct; + buildAdjacency(numVerts, indices, adjacencyStruct); + + Array liveTriCount = adjacencyStruct.trianglesPerVertex; + + Array cacheTimeStamps(numVerts); + + List deadEndStack; + + Array emittedTriangles(indices.size() / 3); + + uint32 curVert = 0; + uint32 timeStamp = cacheSize + 1; + uint32 cursor = 1; + while (curVert != -1) + { + Array oneRing; + const uint32* startTriPointer = &adjacencyStruct.triangleData[0] + adjacencyStruct.indexBufferOffset[curVert]; + const uint32* endTriPointer = startTriPointer + adjacencyStruct.trianglesPerVertex[curVert]; + + for (const uint32* it = startTriPointer; it != endTriPointer; ++it) + { + 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); + } +} + struct Triangle { StaticArray indices; - Array twoAdjacent; - Array oneAdjacent; - int32 meshletId = -1; }; int findIndex(Meshlet ¤t, uint32 index) @@ -41,7 +188,7 @@ void completeMeshlet(Array &meshlets, Meshlet ¤t) }; } -bool addTriangle(const Array& positions, Array &meshlets, Meshlet ¤t, Triangle tri) +bool addTriangle(const Array& positions, Meshlet ¤t, Triangle& tri) { int f1 = findIndex(current, tri.indices[0]); int f2 = findIndex(current, tri.indices[1]); @@ -67,61 +214,27 @@ void Meshlet::build(const Array &positions, const Array &indices .numVertices = 0, .numPrimitives = 0, }; - Array triangles(indices.size() / 3); + Array optimizedIndices; + tipsifyIndexBuffer(indices, positions.size(), 25, optimizedIndices); + Array triangles(optimizedIndices.size() / 3); for (size_t i = 0; i < triangles.size(); ++i) { triangles[i] = Triangle{ .indices = { - indices[i * 3 + 0], - indices[i * 3 + 1], - indices[i * 3 + 2], + optimizedIndices[i * 3 + 0], + optimizedIndices[i * 3 + 1], + optimizedIndices[i * 3 + 2], }, }; } - for (size_t i = 0; i < triangles.size(); i++) - { - for (size_t j = 0; j < triangles.size(); j++) - { - if (i == j) - continue; - - uint32 adjacency = 0; - if (triangles[i].indices[0] == triangles[j].indices[0] - || triangles[i].indices[0] == triangles[j].indices[1] - || triangles[i].indices[0] == triangles[j].indices[2]) - { - adjacency++; - } - if (triangles[i].indices[1] == triangles[j].indices[0] - || triangles[i].indices[1] == triangles[j].indices[1] - || triangles[i].indices[1] == triangles[j].indices[2]) - { - adjacency++; - } - if (triangles[i].indices[1] == triangles[j].indices[0] - || triangles[i].indices[1] == triangles[j].indices[1] - || triangles[i].indices[1] == triangles[j].indices[2]) - { - adjacency++; - } - if(adjacency == 2) - { - triangles[i].twoAdjacent.add(j); - triangles[j].twoAdjacent.add(i); - } - if(adjacency == 1) - { - triangles[i].oneAdjacent.add(j); - triangles[j].oneAdjacent.add(i); - } - } - } - addTriangle(positions, meshlets, current, triangles.back()); - triangles.pop(); while(!triangles.empty()) { - AABB boundingBox; - + if (!addTriangle(positions, current, triangles.back())) + { + completeMeshlet(meshlets, current); + addTriangle(positions, current, triangles.back()); + } + triangles.pop(); } if (current.numVertices > 0) { diff --git a/src/Engine/Graphics/VertexData.cpp b/src/Engine/Graphics/VertexData.cpp index bf0df23..9bd433b 100644 --- a/src/Engine/Graphics/VertexData.cpp +++ b/src/Engine/Graphics/VertexData.cpp @@ -44,43 +44,43 @@ void VertexData::updateMesh(PMesh mesh, Component::Transform& transform) }, .data = data, }); - for (size_t i = 0; i < data.numMeshlets; ++i) - { - auto bounding = meshlets[data.meshletOffset + i].bounding; - StaticArray corners; - corners[0] = transform.toMatrix() * Vector4(bounding.min.x, bounding.min.y, bounding.min.z, 1); - corners[1] = transform.toMatrix() * Vector4(bounding.min.x, bounding.min.y, bounding.max.z, 1); - corners[2] = transform.toMatrix() * Vector4(bounding.min.x, bounding.max.y, bounding.min.z, 1); - corners[3] = transform.toMatrix() * Vector4(bounding.min.x, bounding.max.y, bounding.max.z, 1); - corners[4] = transform.toMatrix() * Vector4(bounding.max.x, bounding.min.y, bounding.min.z, 1); - corners[5] = transform.toMatrix() * Vector4(bounding.max.x, bounding.min.y, bounding.max.z, 1); - corners[6] = transform.toMatrix() * Vector4(bounding.max.x, bounding.max.y, bounding.min.z, 1); - corners[7] = transform.toMatrix() * Vector4(bounding.max.x, bounding.max.y, bounding.max.z, 1); - addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); - addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); - } + //for (size_t i = 0; i < data.numMeshlets; ++i) + //{ + // auto bounding = meshlets[data.meshletOffset + i].bounding; + // StaticArray corners; + // corners[0] = transform.toMatrix() * Vector4(bounding.min.x, bounding.min.y, bounding.min.z, 1); + // corners[1] = transform.toMatrix() * Vector4(bounding.min.x, bounding.min.y, bounding.max.z, 1); + // corners[2] = transform.toMatrix() * Vector4(bounding.min.x, bounding.max.y, bounding.min.z, 1); + // corners[3] = transform.toMatrix() * Vector4(bounding.min.x, bounding.max.y, bounding.max.z, 1); + // corners[4] = transform.toMatrix() * Vector4(bounding.max.x, bounding.min.y, bounding.min.z, 1); + // corners[5] = transform.toMatrix() * Vector4(bounding.max.x, bounding.min.y, bounding.max.z, 1); + // corners[6] = transform.toMatrix() * Vector4(bounding.max.x, bounding.max.y, bounding.min.z, 1); + // corners[7] = transform.toMatrix() * Vector4(bounding.max.x, bounding.max.y, bounding.max.z, 1); + // addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[0], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[1], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[2], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[3], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[4], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[6], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[5], .color = meshlets[data.meshletOffset + i].color }); + // addDebugVertex(DebugVertex{ .position = corners[7], .color = meshlets[data.meshletOffset + i].color }); + //} } matInstanceData.materialInstance = referencedInstance; referencedInstance->updateDescriptor();