diff --git a/res/shaders/BasePass.slang b/res/shaders/BasePass.slang index a6f4f3a..1616e55 100644 --- a/res/shaders/BasePass.slang +++ b/res/shaders/BasePass.slang @@ -29,5 +29,5 @@ float4 fragmentMain(in FragmentParameter params) : SV_Target { result += pLightEnv.pointLights[i].illuminate(lightingParams, brdf); } - return float4(result, 1.0f); + return float4(params.vertexColor, 1.0f); } diff --git a/res/shaders/MeshletBasePass.slang b/res/shaders/MeshletBasePass.slang index 825d6b5..c9163be 100644 --- a/res/shaders/MeshletBasePass.slang +++ b/res/shaders/MeshletBasePass.slang @@ -120,6 +120,7 @@ void meshMain( { uint vertexIndex = pScene.vertexIndices[m.vertexOffset + v]; VertexAttributes attr = pVertexData.getAttributes(md.indicesOffset + vertexIndex); + attr.vertexColor = m.color; vertices[v] = attr.getParameter(inst.transformMatrix); } } diff --git a/res/shaders/lib/Scene.slang b/res/shaders/lib/Scene.slang index 847c428..6a8dc5a 100644 --- a/res/shaders/lib/Scene.slang +++ b/res/shaders/lib/Scene.slang @@ -7,6 +7,8 @@ struct MeshletDescription uint32_t primitiveCount; uint32_t vertexOffset; uint32_t primitiveOffset; + float3 color; + float pad; }; struct MeshData diff --git a/src/Editor/Asset/MeshLoader.cpp b/src/Editor/Asset/MeshLoader.cpp index 5bc1a11..92dad4b 100644 --- a/src/Editor/Asset/MeshLoader.cpp +++ b/src/Editor/Asset/MeshLoader.cpp @@ -268,11 +268,7 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array meshlets; meshlets.reserve(indices.size() / (3ull * Gfx::numPrimitivesPerMeshlet)); - Meshlet::build(indices, meshlets); - for (auto& meshlet : meshlets) - { - meshlet.calcBoundingBox(positions); - } + Meshlet::build(positions, indices, meshlets); vertexData->loadMesh(id, indices, meshlets); collider.physicsMesh.addCollider(positions, indices, Matrix4(1.0f)); diff --git a/src/Engine/Containers/Tree.h b/src/Engine/Containers/Tree.h index 53221d7..2a760c0 100644 --- a/src/Engine/Containers/Tree.h +++ b/src/Engine/Containers/Tree.h @@ -185,7 +185,10 @@ public: , _size() , comp(other.comp) { - std::copy(other.begin(), other.end(), begin()); + for (const auto& elem : other) + { + insert(elem); + } } constexpr Tree(Tree&& other) noexcept : alloc(std::move(other.alloc)) @@ -204,11 +207,14 @@ public: if (this != &other) { clear(); - alloc = other.alloc; - comp = other.comp; - root = nullptr; - _size = 0; - std::copy(other.begin(), other.end(), begin()); + if constexpr (std::allocator_traits::propagate_on_container_copy_assignment::value) + { + alloc = other.alloc; + } + for (const auto& elem : other) + { + insert(elem); + } markIteratorsDirty(); } return *this; @@ -405,7 +411,7 @@ private: Node* newNode = alloc.allocate(1); std::allocator_traits::construct(alloc, newNode, nullptr, nullptr, std::forward(data)); - if (comp(keyFun(r->data), keyFun(newNode->data))) + if (comp(keyFun(newNode->data), keyFun(r->data))) { newNode->rightChild = r; newNode->leftChild = r->leftChild; @@ -456,12 +462,12 @@ private: { return r; } - if (comp(keyFun(r->data), key)) + if (comp(key, keyFun(r->data))) { if (r->leftChild == nullptr) return r; - if (comp(keyFun(r->leftChild->data), key)) + if (comp(key, keyFun(r->leftChild->data))) { r->leftChild->leftChild = _splay(r->leftChild->leftChild, key); @@ -483,7 +489,7 @@ private: if (r->rightChild == nullptr) return r; - if (comp(keyFun(r->rightChild->data), key)) + if (comp(key, keyFun(r->rightChild->data))) { r->rightChild->leftChild = _splay(r->rightChild->leftChild, key); diff --git a/src/Engine/Graphics/CMakeLists.txt b/src/Engine/Graphics/CMakeLists.txt index e06ffbe..82355a1 100644 --- a/src/Engine/Graphics/CMakeLists.txt +++ b/src/Engine/Graphics/CMakeLists.txt @@ -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 diff --git a/src/Engine/Graphics/Meshlet.cpp b/src/Engine/Graphics/Meshlet.cpp new file mode 100644 index 0000000..6ff5420 --- /dev/null +++ b/src/Engine/Graphics/Meshlet.cpp @@ -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 indices; +}; + +Map> buildAdjacency(const Array& indices) +{ + Map> 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 getTriangleCounts(Map>& adjacency) +{ + Map result; + for (const auto& [index, list] : adjacency) + { + result[index] = list.size(); + } + return result; +} + +int32 skipDeadEnd(Map& L, Array& D, const Array& 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& indices, uint32& i, uint32 cacheSize, Set N, const Array& C, uint32 s, Map& L, Array& 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 tipsify(const Array& positions, const Array& indices, uint32 cacheSize) +{ + auto A = buildAdjacency(indices); + auto L = getTriangleCounts(A); + auto C = Array(positions.size(), 0); + auto D = Array(); + Array output; + int32 f = 0; + uint32 s = cacheSize + 1, i = 1; + while (f >= 0) + { + auto N = Set(); + 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& positions, const Array& indices, Array& meshlets) +{ + Meshlet current = { + .numVertices = 0, + .numPrimitives = 0, + }; + auto findIndex = [¤t](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, ¤t]() { + 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(); + } +} diff --git a/src/Engine/Graphics/Meshlet.h b/src/Engine/Graphics/Meshlet.h new file mode 100644 index 0000000..88afea2 --- /dev/null +++ b/src/Engine/Graphics/Meshlet.h @@ -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& positions, const Array& indices, Array& meshlets); +}; +} // namespace Seele \ No newline at end of file diff --git a/src/Engine/Graphics/VertexData.cpp b/src/Engine/Graphics/VertexData.cpp index 977f2fa..69deac8 100644 --- a/src/Engine/Graphics/VertexData.cpp +++ b/src/Engine/Graphics/VertexData.cpp @@ -117,6 +117,7 @@ void VertexData::loadMesh(MeshId id, Array loadedIndices, Array .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& indices, Array& meshlets) -{ - Map> 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 = [¤t](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, ¤t]() { - 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& positions) -{ - for (uint32 i = 0; i < numVertices; ++i) - { - boundingBox.adjust(positions[uniqueVertices[i]]); - } -} \ No newline at end of file diff --git a/src/Engine/Graphics/VertexData.h b/src/Engine/Graphics/VertexData.h index 10578fa..ecaff88 100644 --- a/src/Engine/Graphics/VertexData.h +++ b/src/Engine/Graphics/VertexData.h @@ -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& indices, Array& meshlets); - void calcBoundingBox(const Array& 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 materialData; diff --git a/tests/Engine/Containers/Map.cpp b/tests/Engine/Containers/Map.cpp index ab070fc..1a8fdd9 100644 --- a/tests/Engine/Containers/Map.cpp +++ b/tests/Engine/Containers/Map.cpp @@ -82,10 +82,34 @@ TEST(CachedMap, custom_key) TEST(CachedMap, string_key) { - std::map map; + Map map; map["Test"] = 2; map["Test2"] = 3; ASSERT_EQ(map["Test"], 2); ASSERT_EQ(map["Test2"], 3); } +TEST(CachedMap, copy) +{ + Map map; + map[54] = 14; + map[5123] = 51; + map[262] = 14; + map[9620] = 91283; + map[141] = 415; + Map map2 = map; + Map map3; + map3 = map; + Map::iterator i1 = map.begin(); + Map::iterator i2 = map2.begin(); + Map::iterator i3 = map3.begin(); + while(i1 != map.end()) + { + ASSERT_EQ(i1->key, i2->key); + ASSERT_EQ(i1->value, i2->value); + ASSERT_EQ(i1->key, i3->key); + ASSERT_EQ(i1->value, i3->value); + i1++; i2++; i3++; + } +} +