From f873d6db265ced85347ab41c8e417f10bda6d54e Mon Sep 17 00:00:00 2001 From: Dynamitos Date: Mon, 12 May 2025 22:48:01 +0200 Subject: [PATCH] Starting to integrate mesh optimizer --- CMakeLists.txt | 4 + res/shaders/EnvironmentMapping.slang | 67 ++-- res/shaders/Skybox.slang | 115 +++--- res/shaders/ToneMapping.slang | 2 +- res/shaders/lib/Scene.slang | 2 + res/shaders/lib/StaticMeshVertexData.slang | 4 +- src/Editor/Asset/EnvironmentLoader.cpp | 4 +- src/Editor/Asset/MeshLoader.cpp | 16 +- src/Engine/Actor/DirectionalLightActor.cpp | 2 +- src/Engine/Actor/PointLightActor.cpp | 2 +- src/Engine/Graphics/Enums.h | 1 + src/Engine/Graphics/Meshlet.cpp | 34 +- src/Engine/Graphics/Meshlet.h | 1 + src/Engine/Graphics/RenderPass/BasePass.cpp | 2 +- src/Engine/Graphics/StaticMeshVertexData.cpp | 31 +- src/Engine/Graphics/StaticMeshVertexData.h | 6 - src/Engine/Graphics/VertexData.cpp | 401 ++++++++++++++----- src/Engine/Graphics/VertexData.h | 33 +- src/Engine/Graphics/Vulkan/RayTracing.cpp | 2 +- src/Engine/System/MeshUpdater.cpp | 1 - vcpkg.json | 4 +- 21 files changed, 446 insertions(+), 288 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d1b42d4..45784c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,8 @@ find_package(Ktx CONFIG REQUIRED) find_package(nlohmann_json CONFIG REQUIRED) find_package(fmt CONFIG REQUIRED) find_package(lunasvg CONFIG REQUIRED) +find_package(metis CONFIG REQUIRED) +find_package(meshoptimizer CONFIG REQUIRED) find_package(VulkanMemoryAllocator CONFIG REQUIRED) if(UNIX) @@ -73,6 +75,8 @@ target_link_libraries(Engine PUBLIC crcpp) target_link_libraries(Engine PUBLIC fmt::fmt) target_link_libraries(Engine PUBLIC lunasvg::lunasvg) target_link_libraries(Engine PUBLIC GPUOpen::VulkanMemoryAllocator) +target_link_libraries(Engine PUBLIC metis) +target_link_libraries(Engine PUBLIC meshoptimizer::meshoptimizer) if(WIN32) target_link_libraries(Engine PUBLIC ${VCPKG_BASE_FOLDER}/lib/slang.lib) elseif(APPLE) diff --git a/res/shaders/EnvironmentMapping.slang b/res/shaders/EnvironmentMapping.slang index f49a441..05015e6 100644 --- a/res/shaders/EnvironmentMapping.slang +++ b/res/shaders/EnvironmentMapping.slang @@ -1,57 +1,58 @@ const static float3 vertices[] = { // Right + float3( 1, -1, 1), float3( 1, 1, 1), - float3( 1, -1, 1), - float3( 1, 1, -1), - - float3( 1, 1, -1), - float3( 1, -1, 1), float3( 1, -1, -1), + float3( 1, -1, -1), + float3( 1, 1, 1), + float3( 1, 1, -1), + // Left + float3(-1, -1, -1), float3(-1, 1, -1), - float3(-1, -1, -1), - float3(-1, 1, 1), - - float3(-1, 1, 1), - float3(-1, -1, -1), float3(-1, -1, 1), + float3(-1, -1, 1), + float3(-1, 1, -1), + float3(-1, 1, 1), + // Bottom - float3(-1, -1, 1), - float3(-1, -1, -1), - float3( 1, -1, 1), + float3(-1, 1, 1), + float3(-1, 1, -1), + float3( 1, 1, 1), - float3( 1, -1, 1), - float3(-1, -1, -1), - float3( 1, -1, -1), + float3( 1, 1, 1), + float3(-1, 1, -1), + float3( 1, 1, -1), // Top - float3(-1, 1, -1), - float3(-1, 1, 1), - float3( 1, 1, -1), - - float3( 1, 1, -1), - float3(-1, 1, 1), - float3( 1, 1, 1), - - // Back - float3(-1, 1, 1), + float3(-1, -1, -1), float3(-1, -1, 1), - float3( 1, 1, 1), + float3( 1, -1, -1), - float3( 1, 1, 1), + float3( 1, -1, -1), float3(-1, -1, 1), float3( 1, -1, 1), // Front - float3( 1, 1, -1), float3( 1, -1, -1), + float3( 1, 1, -1), + float3(-1, -1, -1), + + float3(-1, -1, -1), + float3( 1, 1, -1), float3(-1, 1, -1), - float3(-1, 1, -1), - float3( 1, -1, -1), - float3(-1, -1, -1), + // Back + float3(-1, -1, 1), + float3(-1, 1, 1), + float3( 1, -1, 1), + + float3( 1, -1, 1), + float3(-1, 1, 1), + float3( 1, 1, 1), + }; struct ViewParams @@ -80,7 +81,7 @@ VertexOutput vertMain(uint vertexIndex : SV_VertexID, uint viewIndex : SV_ViewID const static float2 invAtan = float2(0.1591, 0.3183); float2 sampleSphericalMap(float3 v) { - float2 uv = float2(atan2(v.z, v.x), asin(v.y)); + float2 uv = float2(atan2(-v.z, v.x), asin(v.y)); uv *= invAtan; uv += 0.5; return uv; diff --git a/res/shaders/Skybox.slang b/res/shaders/Skybox.slang index ff07380..a7be67a 100644 --- a/res/shaders/Skybox.slang +++ b/res/shaders/Skybox.slang @@ -1,5 +1,62 @@ import Common; +const static float3 vertices[] = { + // Right + float3(512, -512, 512), + float3(512, 512, 512), + float3(512, -512, -512), + + float3(512, -512, -512), + float3(512, 512, 512), + float3(512, 512, -512), + + // Left + float3(-512, -512, -512), + float3(-512, 512, -512), + float3(-512, -512, 512), + + float3(-512, -512, 512), + float3(-512, 512, -512), + float3(-512, 512, 512), + + // Bottom + float3(-512, 512, 512), + float3(-512, 512, -512), + float3(512, 512, 512), + + float3(512, 512, 512), + float3(-512, 512, -512), + float3(512, 512, -512), + + // Top + float3(-512, -512, -512), + float3(-512, -512, 512), + float3(512, -512, -512), + + float3(512, -512, -512), + float3(-512, -512, 512), + float3(512, -512, 512), + + // Front + float3(512, -512, -512), + float3(512, 512, -512), + float3(-512, -512, -512), + + float3(-512, -512, -512), + float3(512, 512, -512), + float3(-512, 512, -512), + + // Back + float3(-512, -512, 512), + float3(-512, 512, 512), + float3(512, -512, 512), + + float3(512, -512, 512), + float3(-512, 512, 512), + float3(512, 512, 512), +}; + + struct VertexShaderOutput { float4 clipPos : SV_Position; @@ -12,62 +69,6 @@ struct SkyboxData }; ParameterBlock pSkyboxData; -const static float3 vertices[] = { - // Back - float3(-512, -512, 512), - float3(-512, 512, 512), - float3( 512, -512, 512), - - float3( 512, -512, 512), - float3(-512, 512, 512), - float3( 512, 512, 512), - - // Front - float3( 512, -512, -512), - float3( 512, 512, -512), - float3(-512, -512, -512), - - float3(-512, -512, -512), - float3( 512, 512, -512), - float3(-512, 512, -512), - - // Top - float3(-512, -512, -512), - float3(-512, -512, 512), - float3( 512, -512, -512), - - float3( 512, -512, -512), - float3(-512, -512, 512), - float3( 512, -512, 512), - - // Bottom - float3(-512, 512, 512), - float3(-512, 512, -512), - float3( 512, 512, 512), - - float3( 512, 512, 512), - float3(-512, 512, -512), - float3( 512, 512, -512), - - // Left - float3(-512, -512, -512), - float3(-512, 512, -512), - float3(-512, -512, 512), - - float3(-512, -512, 512), - float3(-512, 512, -512), - float3(-512, 512, 512), - - // Right - float3( 512, -512, 512), - float3( 512, 512, 512), - float3( 512, -512, -512), - - float3( 512, -512, -512), - float3( 512, 512, 512), - float3( 512, 512, -512), -}; - [shader("vertex")] VertexShaderOutput vertexMain( uint vertexIndex : SV_VertexId) @@ -101,5 +102,5 @@ float4 fragmentMain( float factor = (output.texCoords.y - lowerLimit) / (upperLimit - lowerLimit); factor = clamp(factor, 0.0, 1.0); - return lerp(float4(pSkyboxData.fogBlend.xyz, 1), finalColor, factor); + return finalColor;//lerp(float4(pSkyboxData.fogBlend.xyz, 1), finalColor, factor); } \ No newline at end of file diff --git a/res/shaders/ToneMapping.slang b/res/shaders/ToneMapping.slang index ecd0fd3..b4dd02a 100644 --- a/res/shaders/ToneMapping.slang +++ b/res/shaders/ToneMapping.slang @@ -113,5 +113,5 @@ float4 toneMapping(float2 uv : UV) : SV_Target value = agxLook(value); value = agxEotf(value); - return float4(hdrValue, 1); + return float4(value, 1); } diff --git a/res/shaders/lib/Scene.slang b/res/shaders/lib/Scene.slang index 3fcba9a..0476343 100644 --- a/res/shaders/lib/Scene.slang +++ b/res/shaders/lib/Scene.slang @@ -59,6 +59,8 @@ ConstantBuffer pOffsets; struct Scene { + StructuredBuffer positions; + StructuredBuffer indexBuffer; StructuredBuffer instances; StructuredBuffer meshData; StructuredBuffer meshletInfos; diff --git a/res/shaders/lib/StaticMeshVertexData.slang b/res/shaders/lib/StaticMeshVertexData.slang index e456b2a..5327398 100644 --- a/res/shaders/lib/StaticMeshVertexData.slang +++ b/res/shaders/lib/StaticMeshVertexData.slang @@ -1,6 +1,7 @@ import Common; import VertexData; import MaterialParameter; +import Scene; struct StaticMeshVertexData : IVertexData { @@ -12,7 +13,7 @@ struct StaticMeshVertexData : IVertexData VertexAttributes getAttributes(uint index) { VertexAttributes attributes; - attributes.position_MS = float3(positions[index * 3 + 0], positions[index * 3 + 1], positions[index * 3 + 2]); + attributes.position_MS = float3(pScene.positions[index * 3 + 0], pScene.positions[index * 3 + 1], pScene.positions[index * 3 + 2]); #ifndef POS_ONLY //attributes.qTangent = qTangent[index]; attributes.normal_MS = float3(normals[index * 3 + 0], normals[index * 3 + 1], normals[index * 3 + 2]); @@ -26,7 +27,6 @@ struct StaticMeshVertexData : IVertexData #endif return attributes; } - StructuredBuffer positions; //StructuredBuffer qTangents; StructuredBuffer normals; StructuredBuffer tangents; diff --git a/src/Editor/Asset/EnvironmentLoader.cpp b/src/Editor/Asset/EnvironmentLoader.cpp index 92cb44c..49e0456 100644 --- a/src/Editor/Asset/EnvironmentLoader.cpp +++ b/src/Editor/Asset/EnvironmentLoader.cpp @@ -16,6 +16,7 @@ EnvironmentLoader::EnvironmentLoader(Gfx::PGraphics graphics) : graphics(graphic .size = {SOURCE_RESOLUTION, SOURCE_RESOLUTION}, .offset = {0, 0}, }, + .fieldOfView = glm::radians(90.0f), }); convolutionViewport = graphics->createViewport(nullptr, ViewportCreateInfo{ .dimensions = @@ -23,6 +24,7 @@ EnvironmentLoader::EnvironmentLoader(Gfx::PGraphics graphics) : graphics(graphic .size = {CONVOLUTED_RESOLUTION, CONVOLUTED_RESOLUTION}, .offset = {0, 0}, }, + .fieldOfView = glm::radians(90.0f), }); cubeSampler = graphics->createSampler({ .magFilter = Gfx::SE_FILTER_LINEAR, @@ -106,7 +108,7 @@ void EnvironmentLoader::import(EnvironmentImportArgs args, PEnvironmentMapAsset .height = (uint32)height, .name = "HDRRaw", }); - Matrix4 captureProjection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f); + Matrix4 captureProjection = cubeRenderViewport->getProjectionMatrix(0.1f, 10.0f); Matrix4 captureViews[] = { glm::lookAt(Vector(0.0f, 0.0f, 0.0f), Vector(1.0f, 0.0f, 0.0f), Vector(0.0f, 1.0f, 0.0f)), glm::lookAt(Vector(0.0f, 0.0f, 0.0f), Vector(-1.0f, 0.0f, 0.0f), Vector(0.0f, 1.0f, 0.0f)), diff --git a/src/Editor/Asset/MeshLoader.cpp b/src/Editor/Asset/MeshLoader.cpp index 8431669..1e3c4eb 100644 --- a/src/Editor/Asset/MeshLoader.cpp +++ b/src/Editor/Asset/MeshLoader.cpp @@ -515,7 +515,7 @@ Vector4 MeshLoader::encodeQTangent(Matrix3 m) { } void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array& materials, Array& globalMeshes, Component::Collider& collider) { - List> work; + //List> work; for (uint32 meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) { aiMesh* mesh = scene->mMeshes[meshIndex]; if (!(mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)) @@ -527,9 +527,9 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const ArraygetMeshOffset(id); collider.boundingbox.adjust(Vector(mesh->mAABB.mMin.x, mesh->mAABB.mMin.y, mesh->mAABB.mMin.z)); collider.boundingbox.adjust(Vector(mesh->mAABB.mMax.x, mesh->mAABB.mMax.y, mesh->mAABB.mMax.z)); - work.add([=, this, &globalMeshes]() { + //work.add([=, this, &globalMeshes]() { // assume static mesh for now - Array positions(mesh->mNumVertices); + Array positions(mesh->mNumVertices); StaticArray, MAX_TEXCOORDS> texCoords; for (size_t i = 0; i < MAX_TEXCOORDS; ++i) { texCoords[i].resize(mesh->mNumVertices); @@ -572,7 +572,6 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const ArrayloadPositions(offset, positions); for (size_t i = 0; i < MAX_TEXCOORDS; ++i) { vertexData->loadTexCoords(offset, i, texCoords[i]); @@ -589,10 +588,7 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const ArraymFaces[faceIndex].mIndices[2]; } - Array meshlets; - meshlets.reserve(indices.size() / (3ull * Gfx::numPrimitivesPerMeshlet)); - Meshlet::build(positions, indices, meshlets); - vertexData->loadMesh(id, indices, meshlets); + vertexData->loadMesh(id, std::move(positions), std::move(indices)); // collider.physicsMesh.addCollider(positions, indices, Matrix4(1.0f)); @@ -604,9 +600,9 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, const ArrayregisterBottomLevelAccelerationStructure(globalMeshes[meshIndex]->blas); - }); + //}); } - getThreadPool().runAndWait(std::move(work)); + //getThreadPool().runAndWait(std::move(work)); } Matrix4 convertMatrix(aiMatrix4x4 matrix) { diff --git a/src/Engine/Actor/DirectionalLightActor.cpp b/src/Engine/Actor/DirectionalLightActor.cpp index 4055ec7..6c55b0f 100644 --- a/src/Engine/Actor/DirectionalLightActor.cpp +++ b/src/Engine/Actor/DirectionalLightActor.cpp @@ -21,7 +21,7 @@ DirectionalLightActor::DirectionalLightActor(PScene scene, Vector color, float i float angle = std::acos(dot); // angle between vectors rotation = glm::angleAxis(angle, axis); } - attachComponent(Math::Transform(Vector(0, 0, 0), rotation)); + getTransform().setRotation(rotation); } DirectionalLightActor::~DirectionalLightActor() {} diff --git a/src/Engine/Actor/PointLightActor.cpp b/src/Engine/Actor/PointLightActor.cpp index 3ef1d9c..3996563 100644 --- a/src/Engine/Actor/PointLightActor.cpp +++ b/src/Engine/Actor/PointLightActor.cpp @@ -6,7 +6,7 @@ PointLightActor::PointLightActor(PScene scene) : Actor(scene) { attachComponent< PointLightActor::PointLightActor(PScene scene, Vector position, float intensity, Vector color, float attenuation) : Actor(scene) { attachComponent(color, intensity, attenuation); - attachComponent(Math::Transform(position)); + getTransform().setPosition(position); } PointLightActor::~PointLightActor() {} diff --git a/src/Engine/Graphics/Enums.h b/src/Engine/Graphics/Enums.h index 9c59c18..fe396ef 100644 --- a/src/Engine/Graphics/Enums.h +++ b/src/Engine/Graphics/Enums.h @@ -161,6 +161,7 @@ static constexpr uint32 numFramesBuffered = 3; static constexpr uint32 numVerticesPerMeshlet = 256; static constexpr uint32 numPrimitivesPerMeshlet = 256; +static constexpr uint32 numMeshletsPerTask = 256; double getCurrentFrameDelta(); double getCurrentFrameTime(); uint32 getCurrentFrameIndex(); diff --git a/src/Engine/Graphics/Meshlet.cpp b/src/Engine/Graphics/Meshlet.cpp index f3e2cee..d3610c6 100644 --- a/src/Engine/Graphics/Meshlet.cpp +++ b/src/Engine/Graphics/Meshlet.cpp @@ -2,8 +2,11 @@ #include "Containers/List.h" #include "Containers/Map.h" #include "Containers/Set.h" +#include #include - +#include +#include +#include using namespace Seele; @@ -185,32 +188,5 @@ bool addTriangle(const Array& positions, Meshlet& current, Triangle& tri } void Meshlet::build(const Array& positions, const Array& indices, Array& meshlets) { - Meshlet current = { - .numVertices = 0, - .numPrimitives = 0, - }; - // TODO: - // Array optimizedIndices = indices; - // tipsifyIndexBuffer(indices, positions.size(), 25, optimizedIndices); - Array triangles(indices.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], - }, - }; - } - while (!triangles.empty()) { - if (!addTriangle(positions, current, triangles.back())) { - completeMeshlet(meshlets, current); - addTriangle(positions, current, triangles.back()); - } - triangles.pop(); - } - if (current.numVertices > 0) { - completeMeshlet(meshlets, current); - } + } diff --git a/src/Engine/Graphics/Meshlet.h b/src/Engine/Graphics/Meshlet.h index bf1d66d..20d2fdf 100644 --- a/src/Engine/Graphics/Meshlet.h +++ b/src/Engine/Graphics/Meshlet.h @@ -9,6 +9,7 @@ struct Meshlet { uint8 primitiveLayout[Gfx::numPrimitivesPerMeshlet * 3]; // indices into the uniqueVertices array, only uint8 needed uint32 numVertices; uint32 numPrimitives; + uint32 lod = 0; 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/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp index 93de5bd..eb1e944 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.cpp +++ b/src/Engine/Graphics/RenderPass/BasePass.cpp @@ -81,7 +81,7 @@ BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics) skybox = Seele::Component::Skybox{ .day = scene->getLightEnvironment()->getEnvironmentMap()->getSkybox(), .night = scene->getLightEnvironment()->getEnvironmentMap()->getSkybox(), - .fogColor = Vector(0.1, 0.1, 0.8), + .fogColor = Vector(0, 0, 0), .blendFactor = 0, }; } diff --git a/src/Engine/Graphics/StaticMeshVertexData.cpp b/src/Engine/Graphics/StaticMeshVertexData.cpp index 5f24ed8..386e68c 100644 --- a/src/Engine/Graphics/StaticMeshVertexData.cpp +++ b/src/Engine/Graphics/StaticMeshVertexData.cpp @@ -16,12 +16,6 @@ StaticMeshVertexData* StaticMeshVertexData::getInstance() { return &instance; } -void StaticMeshVertexData::loadPositions(uint64 offset, const Array& data) { - assert(offset + data.size() <= head); - std::memcpy(posData.data() + offset, data.data(), data.size() * sizeof(PositionType)); - dirty = true; -} - void StaticMeshVertexData::loadTexCoords(uint64 offset, uint64 index, const Array& data) { assert(offset + data.size() <= head); std::memcpy(texData[index].data() + offset, data.data(), data.size() * sizeof(TexCoordType)); @@ -67,17 +61,14 @@ void StaticMeshVertexData::serializeMesh(MeshId id, ArchiveBuffer& buffer) { std::memcpy(tex[i].data(), texData[i].data() + offset, numVertices * sizeof(TexCoordType)); Serialization::save(buffer, tex[i]); } - Array pos(numVertices); Array nor(numVertices); Array tan(numVertices); Array bit(numVertices); Array col(numVertices); - std::memcpy(pos.data(), posData.data() + offset, numVertices * sizeof(PositionType)); std::memcpy(nor.data(), norData.data() + offset, numVertices * sizeof(NormalType)); std::memcpy(tan.data(), tanData.data() + offset, numVertices * sizeof(TangentType)); std::memcpy(bit.data(), bitData.data() + offset, numVertices * sizeof(BiTangentType)); std::memcpy(col.data(), colData.data() + offset, numVertices * sizeof(ColorType)); - Serialization::save(buffer, pos); Serialization::save(buffer, nor); Serialization::save(buffer, tan); Serialization::save(buffer, bit); @@ -97,22 +88,18 @@ uint64 StaticMeshVertexData::deserializeMesh(MeshId id, ArchiveBuffer& buffer) { loadTexCoords(offset, i, tex[i]); result += tex[i].size() * sizeof(TexCoordType); } - Array pos; Array nor; Array tan; Array bit; Array col; - Serialization::load(buffer, pos); Serialization::load(buffer, nor); Serialization::load(buffer, tan); Serialization::load(buffer, bit); Serialization::load(buffer, col); - loadPositions(offset, pos); loadNormals(offset, nor); loadTangents(offset, tan); loadBitangents(offset, bit); loadColors(offset, col); - result += pos.size() * sizeof(PositionType); result += nor.size() * sizeof(NormalType); result += tan.size() * sizeof(TangentType); result += bit.size() * sizeof(BiTangentType); @@ -123,10 +110,6 @@ uint64 StaticMeshVertexData::deserializeMesh(MeshId id, ArchiveBuffer& buffer) { void StaticMeshVertexData::init(Gfx::PGraphics _graphics) { VertexData::init(_graphics); descriptorLayout = _graphics->createDescriptorLayout("pVertexData"); - descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{ - .name = POSITIONS_NAME, - .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, - }); descriptorLayout->addDescriptorBinding(Gfx::DescriptorBinding{ .name = NORMALS_NAME, .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, @@ -157,7 +140,6 @@ void StaticMeshVertexData::destroy() { for (size_t i = 0; i < MAX_TEXCOORDS; ++i) { texCoords[i] = nullptr; } - positions = nullptr; normals = nullptr; tangents = nullptr; biTangents = nullptr; @@ -167,7 +149,7 @@ void StaticMeshVertexData::destroy() { } void StaticMeshVertexData::resizeBuffers() { - posData.resize(verticesAllocated); + VertexData::resizeBuffers(); norData.resize(verticesAllocated); tanData.resize(verticesAllocated); bitData.resize(verticesAllocated); @@ -178,15 +160,7 @@ void StaticMeshVertexData::resizeBuffers() { } void StaticMeshVertexData::updateBuffers() { - positions = graphics->createShaderBuffer(ShaderBufferCreateInfo{ - .sourceData = - { - .size = verticesAllocated * sizeof(PositionType), - .data = (uint8*)posData.data(), - }, - .usage = Gfx::SE_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, - .name = "Positions", - }); + VertexData::updateBuffers(); normals = graphics->createShaderBuffer(ShaderBufferCreateInfo{ .sourceData = { @@ -231,7 +205,6 @@ void StaticMeshVertexData::updateBuffers() { } descriptorLayout->reset(); descriptorSet = descriptorLayout->allocateDescriptorSet(); - descriptorSet->updateBuffer(POSITIONS_NAME, 0, positions); descriptorSet->updateBuffer(NORMALS_NAME, 0, normals); descriptorSet->updateBuffer(TANGENTS_NAME, 0, tangents); descriptorSet->updateBuffer(BITANGENTS_NAME, 0, biTangents); diff --git a/src/Engine/Graphics/StaticMeshVertexData.h b/src/Engine/Graphics/StaticMeshVertexData.h index c6a5a70..0005944 100644 --- a/src/Engine/Graphics/StaticMeshVertexData.h +++ b/src/Engine/Graphics/StaticMeshVertexData.h @@ -8,7 +8,6 @@ namespace Seele { class StaticMeshVertexData : public VertexData { public: - using PositionType = Vector; using NormalType = Vector; using TangentType = Vector; using BiTangentType = Vector; @@ -18,7 +17,6 @@ class StaticMeshVertexData : public VertexData { StaticMeshVertexData(); virtual ~StaticMeshVertexData(); static StaticMeshVertexData* getInstance(); - void loadPositions(uint64 offset, const Array& data); void loadTexCoords(uint64 offset, uint64 index, const Array& data); void loadNormals(uint64 offset, const Array& data); void loadTangents(uint64 offset, const Array& data); @@ -31,14 +29,11 @@ class StaticMeshVertexData : public VertexData { virtual Gfx::PDescriptorLayout getVertexDataLayout() override { return descriptorLayout; } virtual Gfx::PDescriptorSet getVertexDataSet() override { return descriptorSet; } virtual std::string getTypeName() const override { return "StaticMeshVertexData"; } - virtual Gfx::PShaderBuffer getPositionBuffer() const override { return positions; } private: virtual void resizeBuffers() override; virtual void updateBuffers() override; - Gfx::OShaderBuffer positions; - constexpr static const char* POSITIONS_NAME = "positions"; Gfx::OShaderBuffer texCoords[MAX_TEXCOORDS]; constexpr static const char* TEXCOORDS_NAME = "texCoords"; Gfx::OShaderBuffer normals; @@ -49,7 +44,6 @@ class StaticMeshVertexData : public VertexData { constexpr static const char* BITANGENTS_NAME = "biTangents"; Gfx::OShaderBuffer colors; constexpr static const char* COLORS_NAME = "colors"; - Array posData; Array texData[MAX_TEXCOORDS]; Array norData; Array tanData; diff --git a/src/Engine/Graphics/VertexData.cpp b/src/Engine/Graphics/VertexData.cpp index 5173c5f..f65079f 100644 --- a/src/Engine/Graphics/VertexData.cpp +++ b/src/Engine/Graphics/VertexData.cpp @@ -8,6 +8,9 @@ #include "Material/Material.h" #include "Material/MaterialInstance.h" #include +#include +#include +#include using namespace Seele; @@ -58,7 +61,14 @@ void VertexData::updateMesh(uint32 meshletOffset, PMesh mesh, Component::Transfo } BatchedDrawCall& matInstanceData = matData.instances[referencedInstance->getId()]; matInstanceData.materialInstance = referencedInstance; - for (const auto& data : registeredMeshes[mesh->id].meshData) { + const auto& data = registeredMeshes[mesh->id].meshData; + uint32 numMeshlets = data.meshletRange.size; + for (uint32 i = 0; i < (numMeshlets + Gfx::numMeshletsPerTask - 1) / Gfx::numMeshletsPerTask; ++i) { + MeshData chunkMeshData = data; + chunkMeshData.meshletRange = { + .offset = data.meshletRange.offset + i * Gfx::numMeshletsPerTask, + .size = std::min(numMeshlets - i * Gfx::numMeshletsPerTask, Gfx::numMeshletsPerTask), + }; if (mat->hasTransparency()) { auto params = referencedInstance->getMaterialOffsets(); transparentData.add(TransparentDraw{ @@ -73,14 +83,14 @@ void VertexData::updateMesh(uint32 meshletOffset, PMesh mesh, Component::Transfo }, .worldPosition = Vector(inst.transformMatrix[3]), .instanceData = inst, - .meshData = data, + .meshData = chunkMeshData, .cullingOffset = meshletOffset, .rayTracingScene = mesh->blas, }); } else { // opaque matInstanceData.rayTracingData.add(mesh->blas); matInstanceData.instanceData.add(inst); - matInstanceData.instanceMeshData.add(data); + matInstanceData.instanceMeshData.add(chunkMeshData); matInstanceData.cullingOffsets.add(meshletOffset); } } @@ -129,6 +139,8 @@ void VertexData::createDescriptors() { instanceDataLayout->reset(); descriptorSet = instanceDataLayout->allocateDescriptorSet(); + descriptorSet->updateBuffer(POSITIONS_NAME, 0, positionBuffer); + descriptorSet->updateBuffer(INDEXBUFFER_NAME, 0, indexBuffer); descriptorSet->updateBuffer(INSTANCES_NAME, 0, instanceBuffer); descriptorSet->updateBuffer(MESHDATA_NAME, 0, instanceMeshDataBuffer); descriptorSet->updateBuffer(MESHLET_NAME, 0, meshletBuffer); @@ -138,63 +150,167 @@ void VertexData::createDescriptors() { Material::updateDescriptor(); } -void VertexData::loadMesh(MeshId id, Array loadedIndices, Array loadedMeshlets) { +Array VertexData::groupMeshlets(std::span meshlets) { + auto groupWithAllMeshets = [&]() { + MeshletGroup group; + for (uint32 i = 0; i < meshlets.size(); i++) { + group.meshlets.add(i); + } + return Array{group}; + }; + if (meshlets.size() < 8) { + return groupWithAllMeshets(); + } + struct MeshletEdge { + explicit MeshletEdge(size_t a, size_t b) : first(std::min(a, b)), second(std::max(a, b)) {} + + bool operator==(const MeshletEdge& other) const = default; + + const size_t first; + const size_t second; + }; + + struct MeshletEdgeHasher { + size_t operator()(const MeshletEdge& edge) const { return CRC::Calculate(&edge, sizeof(MeshletEdge), CRC::CRC_32()); } + }; + + std::unordered_map, MeshletEdgeHasher> edges2Meshlets; + std::unordered_map> meshlets2Edges; + + for (size_t meshletIndex = 0; meshletIndex < meshlets.size(); ++meshletIndex) { + const auto& meshlet = meshlets[meshletIndex]; + auto getVertexIndex = [&](size_t index) { + return vertexIndices[meshlet.vertexIndices.offset + primitiveIndices[meshlet.primitiveIndices.offset + index]]; + }; + const size_t triangleCount = meshlet.primitiveIndices.size; + + for (size_t triangleIndex = 0; triangleIndex < triangleCount; ++triangleIndex) { + for (size_t i = 0; i < 3; ++i) { + MeshletEdge edge{getVertexIndex(i + triangleIndex * 3), getVertexIndex(((i + 1) % 3) + triangleIndex * 3)}; + edges2Meshlets[edge].add(meshletIndex); + meshlets2Edges[meshletIndex].emplace(edge); + } + } + } + + std::erase_if(edges2Meshlets, [&](const auto& pair) { return pair.second.size() <= 1; }); + if (edges2Meshlets.empty()) { + return groupWithAllMeshets(); + } + + idx_t vertexCount = meshlets.size(); + idx_t ncon = 1; + idx_t nparts = meshlets.size() / 4; + assert(nparts > 1); + idx_t options[METIS_NOPTIONS]; + METIS_SetDefaultOptions(options); + options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT; + options[METIS_OPTION_CCORDER] = 1; + + Array partition; + partition.resize(vertexCount); + + Array xadjacency; + xadjacency.reserve(vertexCount + 1); + + Array edgeAdjacency; + Array edgeWeights; + + for (size_t meshletIndex = 0; meshletIndex < meshlets.size(); ++meshletIndex) { + size_t startIndexInEdgeAdjacency = edgeAdjacency.size(); + for (const auto& edge : meshlets2Edges[meshletIndex]) { + auto connectionsIter = edges2Meshlets.find(edge); + if (connectionsIter == edges2Meshlets.end()) { + continue; + } + const auto& connections = connectionsIter->second; + for (const auto& connectedMeshlet : connections) { + if (connectedMeshlet != meshletIndex) { + auto existingEdgeIter = + std::find(edgeAdjacency.begin() + startIndexInEdgeAdjacency, edgeAdjacency.end(), connectedMeshlet); + if (existingEdgeIter == edgeAdjacency.end()) { + edgeAdjacency.emplace(connectedMeshlet); + edgeWeights.emplace(1); + } else { + ptrdiff_t d = std::distance(edgeAdjacency.begin(), existingEdgeIter); + assert(d >= 0); + assert(d < edgeWeights.size()); + edgeWeights[d]++; + } + } + } + } + xadjacency.add(startIndexInEdgeAdjacency); + } + xadjacency.add(edgeAdjacency.size()); + assert(xadjacency.size() == meshlets.size() + 1); + assert(edgeAdjacency.size() == edgeWeights.size()); + + idx_t edgeCut; + int result = METIS_PartGraphKway(&vertexCount, &ncon, xadjacency.data(), edgeAdjacency.data(), nullptr, nullptr, edgeWeights.data(), + &nparts, nullptr, nullptr, options, &edgeCut, partition.data()); + + assert(result == METIS_OK); + + Array groups; + groups.resize(nparts); + for (size_t i = 0; i < meshlets.size(); ++i) { + idx_t partitionNumber = partition[i]; + groups[partitionNumber].meshlets.add(i); + } + return groups; +} + +void VertexData::loadMesh(MeshId id, Array loadedPositions, Array loadedIndices) { std::unique_lock l(vertexDataLock); RegisteredMesh& mesh = registeredMeshes[id]; - assert(mesh.meshData.empty()); // TODO: update if not empty - uint32 numChunks = (loadedMeshlets.size() + 2047) / 2048; - for (uint32 chunkIdx = 0; chunkIdx < numChunks; ++chunkIdx) { - uint32 chunkOffset = chunkIdx * 2048; - uint32 numRemaining = loadedMeshlets.size() - chunkOffset; + MeshData& data = mesh.meshData; - AABB meshAABB; - uint32 meshletOffset = meshlets.size(); - for (uint32 chunk = 0; chunk < std::min(numRemaining, 2048u); chunk++) { - Meshlet& m = loadedMeshlets[chunkOffset + chunk]; - //... - meshAABB = meshAABB.combine(m.boundingBox); + // generate an LOD hierarchy for the given source mesh + // load LOD 0 + loadMeshlets(id, loadedPositions, loadedIndices); + size_t previousMeshletsStart = data.meshletRange.offset; // todo: - uint32 vertexOffset = (uint32)vertexIndices.size(); - vertexIndices.resize(vertexOffset + m.numVertices); - std::memcpy(vertexIndices.data() + vertexOffset, m.uniqueVertices, m.numVertices * sizeof(uint32)); + /* const int maxLod = 25; + for (int lod = 0; lod < maxLod; ++lod) { + float tLod = lod / (float)maxLod; - uint32 primitiveOffset = (uint32)primitiveIndices.size(); - primitiveIndices.resize(primitiveOffset + (m.numPrimitives * 3)); - std::memcpy(primitiveIndices.data() + primitiveOffset, m.primitiveLayout, m.numPrimitives * 3 * sizeof(uint8)); - - meshlets.add(MeshletDescription{ - .bounding = m.boundingBox, //.toSphere(), - .vertexIndices = - { - .offset = vertexOffset, - .size = m.numVertices, - }, - .primitiveIndices = - { - .offset = primitiveOffset, - .size = m.numPrimitives, - }, - .color = Vector((float)rand() / RAND_MAX, (float)rand() / RAND_MAX, (float)rand() / RAND_MAX), - .indicesOffset = (uint32)registeredMeshes[id].vertexOffset, - }); + std::span previousLevelMeshlets = + std::span{meshlets.data() + previousMeshletsStart, data.meshletRange.size}; + if (previousLevelMeshlets.size() <= 1) { + return; } - registeredMeshes[id].meshData.add(MeshData{ - .bounding = meshAABB, //.toSphere(), - .meshletRange = - { - .offset = meshletOffset, - .size = std::min(numRemaining, 2048u), - }, - }); - } - // todo: in case of a index split for 16 bit, do something here - registeredMeshes[id].meshData[0].indicesRange = { - .offset = (uint32)indices.size(), - .size = (uint32)loadedIndices.size(), - }; - indices.resize(indices.size() + loadedIndices.size()); - std::memcpy(indices.data() + registeredMeshes[id].meshData[0].indicesRange.offset, loadedIndices.data(), - loadedIndices.size() * sizeof(uint32)); + auto groups = groupMeshlets(previousLevelMeshlets); + const uint32 newMeshletStart = ; + for (const auto& group : groups) { + Array groupVertexIndices; + for (const auto& meshletIndex : group.meshlets) { + const auto& meshlet = meshlets[meshletIndex]; + size_t start = groupVertexIndices.size(); + groupVertexIndices.resize(start + meshlet.numPrimitives * 3); + for (size_t j = 0; j < meshlet.numPrimitives * 3; ++j) { + groupVertexIndices[j + start] = meshlet.uniqueVertices[meshlet.primitiveLayout[j]]; + } + } + float targetError = 0.01f; + const float threshold = 0.5f; + size_t targetIndexCount = groupVertexIndices.size() * threshold; + uint32 options = meshopt_SimplifyLockBorder; + + Array simplifiedIndexBuffer; + simplifiedIndexBuffer.resize(groupVertexIndices.size()); + float simplificationError = 0.f; + + size_t simplifiedIndexCount = meshopt_simplify( + simplifiedIndexBuffer.data(), groupVertexIndices.data(), groupVertexIndices.size(), (float*)loadedPositions.data(), + loadedPositions.size(), sizeof(Vector), targetIndexCount, targetError, options, &simplificationError); + simplifiedIndexBuffer.resize(simplifiedIndexCount); + if (simplifiedIndexCount > 0) { + // loadMeshlets(); + } + } + }*/ + std::memcpy(positions.data() + mesh.vertexOffset, loadedPositions.data(), loadedPositions.size() * sizeof(Vector)); } void VertexData::removeMesh(MeshId id) { @@ -205,34 +321,33 @@ void VertexData::removeMesh(MeshId id) { uint32 numVertexIndices = 0; uint32 primitiveIndicesOffset = primitiveIndices.size(); uint32 numPrimitiveIndices = 0; - uint32 indicesOffset = removing.meshData[0].indicesRange.offset; - uint32 numIndices = removing.meshData[0].indicesRange.size; - for (const auto& data : removing.meshData) { - meshletOffset = std::min(meshletOffset, data.meshletRange.offset); - numMeshlets += data.meshletRange.size; - for (uint32 m = 0; m < data.meshletRange.size; ++m) { - MeshletDescription& meshlet = meshlets[data.meshletRange.offset + m]; - vertexIndicesOffset = std::min(vertexIndicesOffset, meshlet.vertexIndices.offset); - numVertexIndices += meshlet.vertexIndices.size; - primitiveIndicesOffset = std::min(primitiveIndicesOffset, meshlet.primitiveIndices.offset); - numPrimitiveIndices += meshlet.primitiveIndices.size; - } + uint32 indicesOffset = removing.meshData.indicesRange.offset; + uint32 numIndices = removing.meshData.indicesRange.size; + const auto& data = removing.meshData; + meshletOffset = std::min(meshletOffset, data.meshletRange.offset); + numMeshlets += data.meshletRange.size; + for (uint32 m = 0; m < data.meshletRange.size; ++m) { + MeshletDescription& meshlet = meshlets[data.meshletRange.offset + m]; + vertexIndicesOffset = std::min(vertexIndicesOffset, meshlet.vertexIndices.offset); + numVertexIndices += meshlet.vertexIndices.size; + primitiveIndicesOffset = std::min(primitiveIndicesOffset, meshlet.primitiveIndices.offset); + numPrimitiveIndices += meshlet.primitiveIndices.size; } + for (auto& mesh : registeredMeshes) { - for (auto& data : mesh.meshData) { - if (data.meshletRange.offset > meshletOffset) { - for (uint32 i = 0; i < data.meshletRange.size; ++i) { - MeshletDescription& m = meshlets[data.meshletRange.offset + i]; - if (m.primitiveIndices.offset > primitiveIndicesOffset) { - m.primitiveIndices.offset -= numPrimitiveIndices; - } - if (m.vertexIndices.offset > vertexIndicesOffset) { - m.vertexIndices.offset -= numVertexIndices; - } + auto& data = mesh.meshData; + if (data.meshletRange.offset > meshletOffset) { + for (uint32 i = 0; i < data.meshletRange.size; ++i) { + MeshletDescription& m = meshlets[data.meshletRange.offset + i]; + if (m.primitiveIndices.offset > primitiveIndicesOffset) { + m.primitiveIndices.offset -= numPrimitiveIndices; + } + if (m.vertexIndices.offset > vertexIndicesOffset) { + m.vertexIndices.offset -= numVertexIndices; } - data.meshletRange.offset -= numMeshlets; - data.indicesRange.offset -= numIndices; } + data.meshletRange.offset -= numMeshlets; + data.indicesRange.offset -= numIndices; } } uint32 numMeshletsToMove = meshlets.size() - (meshletOffset + numMeshlets); @@ -305,6 +420,7 @@ MeshId VertexData::allocateVertexData(uint64 numVertices) { if (head > verticesAllocated) { verticesAllocated = 2 * head; // double capacity std::cout << "Resizing buffers to " << verticesAllocated << std::endl; + resizeBuffers(); } return res; @@ -312,34 +428,22 @@ MeshId VertexData::allocateVertexData(uint64 numVertices) { void VertexData::serializeMesh(MeshId id, ArchiveBuffer& buffer) { std::unique_lock l(vertexDataLock); - Array out; - for (uint32 n = 0; n < registeredMeshes[id].meshData.size(); ++n) { - MeshData data = registeredMeshes[id].meshData[n]; - for (size_t i = 0; i < data.meshletRange.size; ++i) { - MeshletDescription& desc = meshlets[i + data.meshletRange.offset]; - Meshlet m; - std::memcpy(m.uniqueVertices, &vertexIndices[desc.vertexIndices.offset], desc.vertexIndices.size * sizeof(uint32)); - std::memcpy(m.primitiveLayout, &primitiveIndices[desc.primitiveIndices.offset], desc.primitiveIndices.size * 3 * sizeof(uint8)); - m.numPrimitives = desc.primitiveIndices.size; - m.numVertices = desc.vertexIndices.size; - m.boundingBox = desc.bounding; - out.add(std::move(m)); - } - } - Array ind(registeredMeshes[id].meshData[0].indicesRange.size); - std::memcpy(ind.data(), &indices[registeredMeshes[id].meshData[0].indicesRange.offset], - registeredMeshes[id].meshData[0].indicesRange.size * sizeof(uint32)); - Serialization::save(buffer, out); + Array ind(registeredMeshes[id].meshData.indicesRange.size); + std::memcpy(ind.data(), indices.data() + registeredMeshes[id].meshData.indicesRange.offset, + registeredMeshes[id].meshData.indicesRange.size * sizeof(uint32)); + Array pos(registeredMeshes[id].vertexCount); + std::memcpy(pos.data(), positions.data() + registeredMeshes[id].vertexOffset, registeredMeshes[id].vertexCount * sizeof(Vector)); Serialization::save(buffer, ind); + Serialization::save(buffer, pos); } uint64 VertexData::deserializeMesh(MeshId id, ArchiveBuffer& buffer) { - Array in; + Array pos; Array ind; - Serialization::load(buffer, in); Serialization::load(buffer, ind); - loadMesh(id, ind, in); - uint64 result = in.size() * sizeof(MeshletDescription); + Serialization::load(buffer, pos); + loadMesh(id, pos, ind); + uint64 result = pos.size() * sizeof(Vector); result += ind.size() * sizeof(uint32); return result; } @@ -364,6 +468,16 @@ void VertexData::init(Gfx::PGraphics _graphics) { verticesAllocated = NUM_DEFAULT_ELEMENTS; instanceDataLayout = graphics->createDescriptorLayout("pScene"); + // positions + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .name = POSITIONS_NAME, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, + }); + // indexBuffer + instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{ + .name = INDEXBUFFER_NAME, + .descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER, + }); // instanceData instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{ .name = INSTANCES_NAME, @@ -430,10 +544,91 @@ void VertexData::destroy() { uint32 VertexData::addCullingMapping(MeshId id) { uint32 result = (uint32)meshletCount; - for (const auto& md : getMeshData(id)) { - meshletCount += md.meshletRange.size; - } + const auto& md = getMeshData(id); + meshletCount += md.meshletRange.size; return result; } +void VertexData::resizeBuffers() { positions.resize(verticesAllocated); } + +void VertexData::updateBuffers() { + positionBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{ + .sourceData = + { + .size = verticesAllocated * sizeof(Vector), + .data = (uint8*)positions.data(), + }, + .usage = Gfx::SE_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, + .name = "Positions", + }); +} + +void VertexData::loadMeshlets(MeshId id, const Array& loadedPositions, const Array& loadedIndices) { + // Array optimizedIndices = indices; + // tipsifyIndexBuffer(indices, positions.size(), 25, optimizedIndices); + + const float coneWeight = 0.0f; + + const uint32 meshletOffset = meshlets.size(); + const uint32 vertexOffset = vertexIndices.size(); + const uint32 primitiveOffset = primitiveIndices.size(); + const uint32 maxMeshlets = meshopt_buildMeshletsBound(loadedIndices.size(), Gfx::numVerticesPerMeshlet, Gfx::numPrimitivesPerMeshlet); + Array meshoptMeshlets; + meshoptMeshlets.resize(maxMeshlets); + + Array meshletVertexIndices; + Array meshletTriangles; + meshletVertexIndices.resize(maxMeshlets * Gfx::numVerticesPerMeshlet); + meshletTriangles.resize(maxMeshlets * Gfx::numVerticesPerMeshlet * 3); + + const uint32 meshletCount = + meshopt_buildMeshlets(meshoptMeshlets.data(), meshletVertexIndices.data(), meshletTriangles.data(), loadedIndices.data(), + loadedIndices.size(), (float*)loadedPositions.data(), loadedPositions.size(), sizeof(Vector), + Gfx::numVerticesPerMeshlet, Gfx::numPrimitivesPerMeshlet, coneWeight); + + const meshopt_Meshlet& last = meshoptMeshlets[meshletCount - 1]; + const uint32 vertexCount = last.vertex_offset + last.vertex_count; + const uint32 indexCount = last.triangle_offset + ((last.triangle_count * 3 + 3) & ~3); + vertexIndices.resize(vertexOffset + vertexCount); + primitiveIndices.resize(primitiveOffset + indexCount); + meshlets.resize(meshletOffset + meshletCount); + + std::memcpy(vertexIndices.data() + vertexOffset, meshletVertexIndices.data(), vertexCount * sizeof(uint32)); + std::memcpy(primitiveIndices.data() + primitiveOffset, meshletTriangles.data(), indexCount * sizeof(uint8)); + + for (size_t i = 0; i < meshletCount; ++i) { + MeshletDescription& m = meshlets[meshletOffset + i]; + m.vertexIndices = { + .offset = vertexOffset + meshoptMeshlets[i].vertex_offset, + .size = meshoptMeshlets[i].vertex_count, + }; + m.primitiveIndices = { + .offset = primitiveOffset + meshoptMeshlets[i].triangle_offset, + .size = meshoptMeshlets[i].triangle_count, + }; + // todo: use meshopt for bb generation + m.bounding = AABB(); + for (size_t j = 0; j < m.vertexIndices.size; ++j) { + m.bounding.adjust(loadedPositions[vertexIndices[meshoptMeshlets[i].vertex_offset + j]]); + } + } + registeredMeshes[id].meshData = MeshData{ + .bounding = AABB(), + .meshletRange = + { + .offset = meshletOffset, + .size = meshletCount, + }, + .indicesRange = + { + .offset = (uint32)indices.size(), + .size = (uint32)loadedIndices.size(), + }, + }; + // todo: in case of a index split for 16 bit, do something here + indices.resize(indices.size() + loadedIndices.size()); + std::memcpy(indices.data() + registeredMeshes[id].meshData.indicesRange.offset, loadedIndices.data(), + loadedIndices.size() * sizeof(uint32)); +} + VertexData::VertexData() : idCounter(0), head(0), verticesAllocated(0), dirty(false) {} diff --git a/src/Engine/Graphics/VertexData.h b/src/Engine/Graphics/VertexData.h index d85c63d..510a2a8 100644 --- a/src/Engine/Graphics/VertexData.h +++ b/src/Engine/Graphics/VertexData.h @@ -57,7 +57,7 @@ class VertexData { void resetMeshData(); void updateMesh(uint32 meshletOffset, PMesh mesh, Component::Transform& transform); virtual void createDescriptors(); - void loadMesh(MeshId id, Array indices, Array meshlets); + void loadMesh(MeshId id, Array positions, Array indices); virtual void removeMesh(MeshId id); void commitMeshes(); MeshId allocateVertexData(uint64 numVertices); @@ -68,7 +68,7 @@ class VertexData { virtual Gfx::PDescriptorLayout getVertexDataLayout() = 0; virtual Gfx::PDescriptorSet getVertexDataSet() = 0; virtual std::string getTypeName() const = 0; - virtual Gfx::PShaderBuffer getPositionBuffer() const = 0; + Gfx::PShaderBuffer getPositionBuffer() const { return positionBuffer; } Gfx::PIndexBuffer getIndexBuffer() const { return indexBuffer; } uint32* getIndexData() const { return indices.data(); } Gfx::PDescriptorLayout getInstanceDataLayout() { return instanceDataLayout; } @@ -76,7 +76,7 @@ class VertexData { const Array& getMaterialData() const { return materialData; } const Array& getTransparentData() const { return transparentData; } const Array& getRayTracingData() const { return rayTracingScene; } - const Array& getMeshData(MeshId id) const { return registeredMeshes[id].meshData; } + const MeshData& getMeshData(MeshId id) const { return registeredMeshes[id].meshData; } void registerBottomLevelAccelerationStructure(Gfx::PBottomLevelAS blas) { dataToBuild.add(blas); } uint32 getIndicesOffset(uint32 meshletIndex) { return meshlets[meshletIndex].indicesOffset; } uint64 getNumInstances() const { return instanceData.size(); } @@ -91,8 +91,10 @@ class VertexData { constexpr static const char* CULLINGDATA_NAME = "cullingData"; protected: - virtual void resizeBuffers() = 0; - virtual void updateBuffers() = 0; + virtual void resizeBuffers(); + virtual void updateBuffers(); + void loadMeshlets(MeshId id, const Array& positions, const Array& indices); + VertexData(); struct MeshletDescription { AABB bounding; @@ -100,9 +102,11 @@ class VertexData { PoolRange vertexIndices; // range into primitiveIndices array PoolRange primitiveIndices; - Vector color; // gets added to vertex indices so that they reference the global mesh pool uint32 indicesOffset = 0; + uint32 lod = 0; + uint32 pad0; + uint32 pad1; }; std::mutex materialDataLock; Array materialData; @@ -111,8 +115,8 @@ class VertexData { std::mutex vertexDataLock; struct RegisteredMesh { - // each mesh id can have multiple meshdata, in case it needs to be split for having too many meshlets - Array meshData; + // this mesh data can have an unlimited number of meshlets, gets split when updating shader buffers + MeshData meshData; uint64 vertexOffset; uint64 vertexCount; }; @@ -121,6 +125,7 @@ class VertexData { Array meshlets; Array primitiveIndices; Array vertexIndices; + Array positions; Array indices; static uint64 meshletCount; @@ -128,6 +133,10 @@ class VertexData { Gfx::PGraphics graphics; Gfx::ODescriptorLayout instanceDataLayout; // for mesh shading + Gfx::OShaderBuffer positionBuffer; + constexpr static const char* POSITIONS_NAME = "positions"; + Gfx::OIndexBuffer indexBuffer; + constexpr static const char* INDEXBUFFER_NAME = "indexBuffer"; Gfx::OShaderBuffer meshletBuffer; constexpr static const char* MESHLET_NAME = "meshlets"; Gfx::OShaderBuffer vertexIndicesBuffer; @@ -137,9 +146,6 @@ class VertexData { Gfx::OShaderBuffer cullingOffsetBuffer; constexpr static const char* CULLINGOFFSETS_NAME = "cullingOffsets"; - // for legacy pipeline - Gfx::OIndexBuffer indexBuffer; - constexpr static const char* INDEXBUFFER_NAME = "indexBuffer"; Array dataToBuild; // Material data Array instanceData; @@ -157,5 +163,10 @@ class VertexData { uint64 head; uint64 verticesAllocated; bool dirty; + + struct MeshletGroup { + Array meshlets; + }; + Array groupMeshlets(std::span meshlets); }; } // namespace Seele diff --git a/src/Engine/Graphics/Vulkan/RayTracing.cpp b/src/Engine/Graphics/Vulkan/RayTracing.cpp index 6962da2..bb88127 100644 --- a/src/Engine/Graphics/Vulkan/RayTracing.cpp +++ b/src/Engine/Graphics/Vulkan/RayTracing.cpp @@ -23,7 +23,7 @@ BottomLevelAS::BottomLevelAS(PGraphics graphics, const Gfx::BottomLevelASCreateI }; VertexData* vertexData = createInfo.mesh->vertexData; //todo: indices might be split as well - MeshData meshData = vertexData->getMeshData(createInfo.mesh->id)[0]; + MeshData meshData = vertexData->getMeshData(createInfo.mesh->id); vertexOffset = vertexData->getMeshOffset(createInfo.mesh->id) * sizeof(Vector); vertexCount = vertexData->getMeshVertexCount(createInfo.mesh->id); indexOffset = meshData.indicesRange.offset * sizeof(uint32); diff --git a/src/Engine/System/MeshUpdater.cpp b/src/Engine/System/MeshUpdater.cpp index ea716e6..5940733 100644 --- a/src/Engine/System/MeshUpdater.cpp +++ b/src/Engine/System/MeshUpdater.cpp @@ -10,7 +10,6 @@ MeshUpdater::MeshUpdater(PScene scene) : ComponentSystemaccessComponent(id); if (comp.meshletOffsets.empty()) { for (uint32 i = 0; i < comp.asset->meshes.size(); ++i) { comp.meshletOffsets.add(comp.asset->meshes[i]->vertexData->addCullingMapping(comp.asset->meshes[i]->id)); diff --git a/vcpkg.json b/vcpkg.json index e5182c0..31abe54 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -14,6 +14,8 @@ "vulkan-memory-allocator", "lunasvg", "harfbuzz", - "shader-slang" + "shader-slang", + "metis", + "meshoptimizer" ] } \ No newline at end of file