From 4e0122ec6128a69e3ac68e8a6aa7d288d6bfdeed Mon Sep 17 00:00:00 2001 From: gomkyung2 Date: Tue, 26 Nov 2024 18:43:06 +0900 Subject: [PATCH] Replaced some glm usage with fastgltf built-ins. --- impl/MainApp.cpp | 31 ++++++++++--------- impl/control/ImGuiTaskCollector.cpp | 20 +++++-------- impl/gltf/AssetSceneGpuBuffers.cpp | 6 ++-- impl/vulkan/Frame.cpp | 2 +- interface/MainApp.cppm | 2 +- interface/control/ImGuiTaskCollector.cppm | 2 +- interface/gltf/AssetSceneGpuBuffers.cppm | 14 ++++----- interface/gltf/AssetSceneHierarchy.cppm | 20 ++++++------- interface/gltf/algorithm/bounding_box.cppm | 23 +++++++------- interface/gltf/algorithm/miniball.cppm | 20 +++++-------- interface/gltf/algorithm/traversal.cppm | 31 ++++++++++--------- interface/helpers/fastgltf.cppm | 35 ++++++++++++++++------ 12 files changed, 108 insertions(+), 98 deletions(-) diff --git a/impl/MainApp.cpp b/impl/MainApp.cpp index 089abc36..4f923098 100644 --- a/impl/MainApp.cpp +++ b/impl/MainApp.cpp @@ -254,12 +254,7 @@ void vk_gltf_viewer::MainApp::run() { imguiTaskCollector.inputControl(appState.camera, appState.automaticNearFarPlaneAdjustment, appState.useFrustumCulling, appState.hoveringNodeOutline, appState.selectedNodeOutline); imguiTaskCollector.imguizmo(appState.camera, appState.gltfAsset.and_then([this](auto &x) { return value_if(x.selectedNodeIndices.size() == 1, [&]() { - return std::tuple, std::uint16_t, ImGuizmo::OPERATION> { - x.asset, - gltf->sceneHierarchy.nodeWorldTransforms, - *x.selectedNodeIndices.begin(), - appState.imGuizmoOperation, - }; + return std::tie(x.asset, gltf->sceneHierarchy.nodeWorldTransforms, *x.selectedNodeIndices.begin(), appState.imGuizmoOperation); }); })); } @@ -322,7 +317,7 @@ void vk_gltf_viewer::MainApp::run() { // Adjust the camera based on the scene enclosing sphere. const auto &[center, radius] = gltf->sceneMiniball; const float distance = radius / std::sin(appState.camera.fov / 2.f); - appState.camera.position = center - glm::dvec3 { distance * normalize(appState.camera.direction) }; + appState.camera.position = glm::make_vec3(center.data()) - glm::dvec3 { distance * normalize(appState.camera.direction) }; appState.camera.zMin = distance - radius; appState.camera.zMax = distance + radius; appState.camera.targetDistance = distance; @@ -363,7 +358,7 @@ void vk_gltf_viewer::MainApp::run() { // Adjust the camera based on the scene enclosing sphere. const auto &[center, radius] = gltf->sceneMiniball; const float distance = radius / std::sin(appState.camera.fov / 2.f); - appState.camera.position = center - glm::dvec3 { distance * normalize(appState.camera.direction) }; + appState.camera.position = glm::make_vec3(center.data()) - glm::dvec3 { distance * normalize(appState.camera.direction) }; appState.camera.zMin = distance - radius; appState.camera.zMax = distance + radius; appState.camera.targetDistance = distance; @@ -413,21 +408,25 @@ void vk_gltf_viewer::MainApp::run() { // Scene enclosing sphere would be changed. Adjust the camera's near/far plane if necessary. if (appState.automaticNearFarPlaneAdjustment) { const auto &[center, radius] - = (gltf->sceneMiniball = gltf::algorithm::getMiniball(gltf->asset, gltf->scene, LIFT(gltf->sceneGpuBuffers.getMeshNodeWorldTransform))); - appState.camera.tightenNearFar(center, radius); + = gltf->sceneMiniball + = gltf::algorithm::getMiniball( + gltf->asset, gltf->scene, [this](std::size_t nodeIndex, std::size_t instanceIndex) { + return cast(gltf->sceneGpuBuffers.getMeshNodeWorldTransform(nodeIndex, instanceIndex)); + }); + appState.camera.tightenNearFar(glm::make_vec3(center.data()), radius); } }, [this](control::task::TightenNearFarPlane) { if (gltf) { const auto &[center, radius] = gltf->sceneMiniball; - appState.camera.tightenNearFar(center, radius); + appState.camera.tightenNearFar(glm::make_vec3(center.data()), radius); } }, [this](control::task::ChangeCameraView) { if (appState.automaticNearFarPlaneAdjustment && gltf) { // Tighten near/far plane based on the scene enclosing sphere. const auto &[center, radius] = gltf->sceneMiniball; - appState.camera.tightenNearFar(center, radius); + appState.camera.tightenNearFar(glm::make_vec3(center.data()), radius); } }, [&](control::task::InvalidateDrawCommandSeparation) { @@ -556,13 +555,17 @@ vk_gltf_viewer::MainApp::Gltf::Gltf( assetGpuBuffers { asset, gpu, threadPool, assetExternalBuffers }, assetGpuTextures { asset, directory, gpu, threadPool, assetExternalBuffers }, sceneGpuBuffers { asset, scene, sceneHierarchy, gpu, assetExternalBuffers }, - sceneMiniball{ gltf::algorithm::getMiniball(asset, scene, LIFT(sceneGpuBuffers.getMeshNodeWorldTransform)) } { } + sceneMiniball { gltf::algorithm::getMiniball(asset, scene, [this](std::size_t nodeIndex, std::size_t instanceIndex) { + return cast(sceneGpuBuffers.getMeshNodeWorldTransform(nodeIndex, instanceIndex)); + }) } { } void vk_gltf_viewer::MainApp::Gltf::setScene(std::size_t sceneIndex) { scene = asset.scenes[sceneIndex]; sceneHierarchy = { asset, scene }; sceneGpuBuffers = { asset, scene, sceneHierarchy, gpu, assetExternalBuffers }; - sceneMiniball = gltf::algorithm::getMiniball(asset, scene, LIFT(sceneGpuBuffers.getMeshNodeWorldTransform)); + sceneMiniball = gltf::algorithm::getMiniball(asset, scene, [this](std::size_t nodeIndex, std::size_t instanceIndex) { + return cast(sceneGpuBuffers.getMeshNodeWorldTransform(nodeIndex, instanceIndex)); + }); } auto vk_gltf_viewer::MainApp::createInstance() const -> vk::raii::Instance { diff --git a/impl/control/ImGuiTaskCollector.cpp b/impl/control/ImGuiTaskCollector.cpp index f28e8c35..1c1ac5bd 100644 --- a/impl/control/ImGuiTaskCollector.cpp +++ b/impl/control/ImGuiTaskCollector.cpp @@ -837,8 +837,7 @@ void vk_gltf_viewer::control::ImGuiTaskCollector::nodeInspector( } if (ImGui::Selectable("Transform Matrix", !isTrs) && isTrs) { const auto &trs = get(node.transform); - constexpr fastgltf::math::fmat4x4 identity { 1.f }; - node.transform.emplace(translate(identity, trs.translation) * rotate(identity, trs.rotation) * scale(identity, trs.scale)); + node.transform.emplace(toMatrix(trs)); } ImGui::EndCombo(); } @@ -1067,7 +1066,7 @@ void vk_gltf_viewer::control::ImGuiTaskCollector::inputControl( void vk_gltf_viewer::control::ImGuiTaskCollector::imguizmo( Camera &camera, - const std::optional, std::uint16_t, ImGuizmo::OPERATION>> &assetAndNodeWorldTransformsAndSelectedNodeIndexAndImGuizmoOperation + const std::optional, std::uint16_t, ImGuizmo::OPERATION>> &assetAndNodeWorldTransformsAndSelectedNodeIndexAndImGuizmoOperation ) { // Set ImGuizmo rect. ImGuizmo::BeginFrame(); @@ -1075,20 +1074,17 @@ void vk_gltf_viewer::control::ImGuiTaskCollector::imguizmo( if (assetAndNodeWorldTransformsAndSelectedNodeIndexAndImGuizmoOperation) { auto &[asset, nodeWorldTransforms, selectedNodeIndex, operation] = *assetAndNodeWorldTransformsAndSelectedNodeIndexAndImGuizmoOperation; - if (glm::mat4 worldTransform = nodeWorldTransforms[selectedNodeIndex]; - Manipulate(value_ptr(camera.getViewMatrix()), value_ptr(camera.getProjectionMatrixForwardZ()), operation, ImGuizmo::MODE::WORLD, value_ptr(worldTransform))) { + fastgltf::math::fmat4x4 deltaMatrix; + if (fastgltf::math::fmat4x4 worldTransform = nodeWorldTransforms[selectedNodeIndex]; + Manipulate(value_ptr(camera.getViewMatrix()), value_ptr(camera.getProjectionMatrixForwardZ()), operation, ImGuizmo::MODE::WORLD, worldTransform.data(), deltaMatrix.data())) { - const glm::mat4 deltaMatrix = worldTransform * inverse(nodeWorldTransforms[selectedNodeIndex]); visit(fastgltf::visitor { [&](fastgltf::math::fmat4x4 &transformMatrix) { - const glm::mat4 newTransform = deltaMatrix * fastgltf::toMatrix(transformMatrix); - std::copy_n(value_ptr(newTransform), 16, transformMatrix.data()); + transformMatrix = deltaMatrix * transformMatrix; }, [&](fastgltf::TRS &trs) { - const glm::mat4 newTransform = deltaMatrix * toMatrix(trs); - fastgltf::math::fmat4x4 newTransformMatrix; - std::copy_n(value_ptr(newTransform), 16, newTransformMatrix.data()); - fastgltf::math::decomposeTransformMatrix(newTransformMatrix, trs.scale, trs.rotation, trs.translation); + const fastgltf::math::fmat4x4 newTransform = deltaMatrix * toMatrix(trs); + decomposeTransformMatrix(newTransform, trs.scale, trs.rotation, trs.translation); }, }, asset.nodes[selectedNodeIndex].transform); tasks.emplace_back(std::in_place_type, selectedNodeIndex); diff --git a/impl/gltf/AssetSceneGpuBuffers.cpp b/impl/gltf/AssetSceneGpuBuffers.cpp index 2df21346..076d73c9 100644 --- a/impl/gltf/AssetSceneGpuBuffers.cpp +++ b/impl/gltf/AssetSceneGpuBuffers.cpp @@ -13,8 +13,8 @@ import :helpers.ranges; #define FWD(...) static_cast(__VA_ARGS__) #define LIFT(...) [&](auto &&...xs) { return (__VA_ARGS__)(FWD(xs)...); } -const glm::mat4 &vk_gltf_viewer::gltf::AssetSceneGpuBuffers::getMeshNodeWorldTransform(std::uint16_t nodeIndex, std::uint32_t instanceIndex) const noexcept { - return meshNodeWorldTransformBuffer.asRange()[instanceOffsets[nodeIndex] + instanceIndex]; +const fastgltf::math::fmat4x4 &vk_gltf_viewer::gltf::AssetSceneGpuBuffers::getMeshNodeWorldTransform(std::uint16_t nodeIndex, std::uint32_t instanceIndex) const noexcept { + return meshNodeWorldTransformBuffer.asRange()[instanceOffsets[nodeIndex] + instanceIndex]; } std::vector vk_gltf_viewer::gltf::AssetSceneGpuBuffers::createInstanceCounts(const fastgltf::Scene &scene) const { @@ -50,7 +50,7 @@ vku::AllocatedBuffer vk_gltf_viewer::gltf::AssetSceneGpuBuffers::createNodeBuffe vku::AllocatedBuffer stagingBuffer = vku::MappedBuffer { gpu.allocator, std::from_range, instanceOffsets | std::views::transform([=](std::uint32_t offset) { - return nodeTransformBufferStartAddress + sizeof(glm::mat4) * offset; + return nodeTransformBufferStartAddress + sizeof(fastgltf::math::fmat4x4) * offset; }), gpu.isUmaDevice ? vk::BufferUsageFlagBits::eStorageBuffer : vk::BufferUsageFlagBits::eTransferSrc, }.unmap(); diff --git a/impl/vulkan/Frame.cpp b/impl/vulkan/Frame.cpp index f1e466ab..4bfa17d5 100644 --- a/impl/vulkan/Frame.cpp +++ b/impl/vulkan/Frame.cpp @@ -180,7 +180,7 @@ auto vk_gltf_viewer::vulkan::Frame::update(const ExecutionTask &task) -> UpdateR const gltf::AssetPrimitiveInfo &primitiveInfo = task.gltf->assetGpuBuffers.primitiveInfos.at(&primitive); - const glm::mat4 &nodeWorldTransform = task.gltf->sceneHierarchy.nodeWorldTransforms[nodeIndex]; + const glm::mat4 nodeWorldTransform = glm::make_mat4(task.gltf->sceneHierarchy.nodeWorldTransforms[nodeIndex].data()); const glm::vec3 transformedMin { nodeWorldTransform * glm::vec4 { primitiveInfo.min, 1.f } }; const glm::vec3 transformedMax { nodeWorldTransform * glm::vec4 { primitiveInfo.max, 1.f } }; diff --git a/interface/MainApp.cppm b/interface/MainApp.cppm index 4821279e..1ae9832b 100644 --- a/interface/MainApp.cppm +++ b/interface/MainApp.cppm @@ -78,7 +78,7 @@ namespace vk_gltf_viewer { * * The first of the pair is the center, and the second is the radius of the miniball. */ - std::pair sceneMiniball; + std::pair sceneMiniball; Gltf( fastgltf::Parser &parser, diff --git a/interface/control/ImGuiTaskCollector.cppm b/interface/control/ImGuiTaskCollector.cppm index 85323d47..b0633f03 100644 --- a/interface/control/ImGuiTaskCollector.cppm +++ b/interface/control/ImGuiTaskCollector.cppm @@ -23,7 +23,7 @@ namespace vk_gltf_viewer::control { void background(bool canSelectSkyboxBackground, full_optional &solidBackground); void imageBasedLighting(const AppState::ImageBasedLighting &info, vk::DescriptorSet eqmapTextureImGuiDescriptorSet); void inputControl(Camera &camera, bool& automaticNearFarPlaneAdjustment, bool &useFrustumCulling, full_optional &hoveringNodeOutline, full_optional &selectedNodeOutline); - void imguizmo(Camera &camera, const std::optional, std::uint16_t, ImGuizmo::OPERATION>> &assetAndNodeWorldTransformsAndSelectedNodeIndexAndImGuizmoOperation); + void imguizmo(Camera &camera, const std::optional, std::uint16_t, ImGuizmo::OPERATION>> &assetAndNodeWorldTransformsAndSelectedNodeIndexAndImGuizmoOperation); private: std::vector &tasks; diff --git a/interface/gltf/AssetSceneGpuBuffers.cppm b/interface/gltf/AssetSceneGpuBuffers.cppm index 335fa94d..32bf3304 100644 --- a/interface/gltf/AssetSceneGpuBuffers.cppm +++ b/interface/gltf/AssetSceneGpuBuffers.cppm @@ -29,7 +29,7 @@ namespace vk_gltf_viewer::gltf { /** * @brief Buffer that stores the mesh nodes' transform matrices, with flattened instance matrices. * - * The term "mesh node" means a node that has a mesh. This buffer only contains transform matrices of mesh nodes. In other words, meshNodeWorldTransformBuffer.asRange()[nodeIndex] may NOT represent the world transformation matrix of the nodeIndex-th node, because maybe there were nodes with no mesh prior to the nodeIndex-th node. + * The term "mesh node" means a node that has a mesh. This buffer only contains transform matrices of mesh nodes. In other words, meshNodeWorldTransformBuffer.asRange()[nodeIndex] may NOT represent the world transformation matrix of the nodeIndex-th node, because maybe there were nodes with no mesh prior to the nodeIndex-th node. * * For example, a scene has 4 nodes (denoted as A B C D) and A has 2 instances (M1, M2), B has 3 instances (M3, M4, M5), C is meshless, and D has 1 instance (M6), then the flattened matrices will be laid out as: * @code @@ -67,7 +67,7 @@ namespace vk_gltf_viewer::gltf { * @warning \p nodeIndex-th node MUST have a mesh. No exception thrown for constraint violation. * @warning \p instanceIndex-th instance MUST be less than the instance count of the node. No exception thrown for constraint violation. */ - [[nodiscard]] const glm::mat4 &getMeshNodeWorldTransform(std::uint16_t nodeIndex, std::uint32_t instanceIndex = 0) const noexcept; + [[nodiscard]] const fastgltf::math::fmat4x4 &getMeshNodeWorldTransform(std::uint16_t nodeIndex, std::uint32_t instanceIndex = 0) const noexcept; /** * @brief Update the mesh node world transforms from given \p nodeIndex, to its descendants. @@ -78,7 +78,7 @@ namespace vk_gltf_viewer::gltf { */ template void updateMeshNodeTransformsFrom(std::uint16_t nodeIndex, const AssetSceneHierarchy &sceneHierarchy, const BufferDataAdapter &adapter = {}) { - const std::span meshNodeWorldTransforms = meshNodeWorldTransformBuffer.asRange(); + const std::span meshNodeWorldTransforms = meshNodeWorldTransformBuffer.asRange(); algorithm::traverseNode(*pAsset, nodeIndex, [&](std::size_t nodeIndex) { const fastgltf::Node &node = pAsset->nodes[nodeIndex]; if (!node.meshIndex) { @@ -91,7 +91,7 @@ namespace vk_gltf_viewer::gltf { else { for (std::uint32_t instanceIndex : ranges::views::upto(instanceCounts[nodeIndex])) { meshNodeWorldTransforms[instanceOffsets[nodeIndex] + instanceIndex] - = sceneHierarchy.nodeWorldTransforms[nodeIndex] * fastgltf::toMatrix(instanceTransforms[instanceIndex]); + = sceneHierarchy.nodeWorldTransforms[nodeIndex] * instanceTransforms[instanceIndex]; } } }); @@ -196,7 +196,7 @@ namespace vk_gltf_viewer::gltf { vma::Allocator allocator, const BufferDataAdapter &adapter ) const { - std::vector meshNodeWorldTransforms(instanceOffsets.back() + instanceCounts.back()); + std::vector meshNodeWorldTransforms(instanceOffsets.back() + instanceCounts.back()); algorithm::traverseScene(*pAsset, scene, [&](std::size_t nodeIndex) { const fastgltf::Node &node = pAsset->nodes[nodeIndex]; if (!node.meshIndex) { @@ -209,14 +209,14 @@ namespace vk_gltf_viewer::gltf { else { for (std::uint32_t instanceIndex : ranges::views::upto(instanceCounts[nodeIndex])) { meshNodeWorldTransforms[instanceOffsets[nodeIndex] + instanceIndex] - = sceneHierarchy.nodeWorldTransforms[nodeIndex] * fastgltf::toMatrix(instanceTransforms[instanceIndex]); + = sceneHierarchy.nodeWorldTransforms[nodeIndex] * instanceTransforms[instanceIndex]; } } }); return vku::MappedBuffer { allocator, - std::from_range, meshNodeWorldTransforms, + std::from_range, as_bytes(std::span { meshNodeWorldTransforms }), vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eShaderDeviceAddress, }; } diff --git a/interface/gltf/AssetSceneHierarchy.cppm b/interface/gltf/AssetSceneHierarchy.cppm index f8e06904..1062a3eb 100644 --- a/interface/gltf/AssetSceneHierarchy.cppm +++ b/interface/gltf/AssetSceneHierarchy.cppm @@ -2,15 +2,11 @@ export module vk_gltf_viewer:gltf.AssetSceneHierarchy; import std; export import fastgltf; -export import glm; import :gltf.algorithm.traversal; import :helpers.fastgltf; import :helpers.optional; import :helpers.ranges; -#define FWD(...) static_cast(__VA_ARGS__) -#define LIFT(...) [&](auto &&...xs) { return (__VA_ARGS__)(FWD(xs)...); } - namespace vk_gltf_viewer::gltf { /** * @brief Scene hierarchy information of the glTF asset scene. @@ -31,7 +27,7 @@ namespace vk_gltf_viewer::gltf { /** * @brief World transformation matrices of each node. nodeWorldTransforms[i] = (world transformation matrix of the i-th node). */ - std::vector nodeWorldTransforms; + std::vector nodeWorldTransforms; AssetSceneHierarchy(const fastgltf::Asset &asset, const fastgltf::Scene &scene) : pAsset { &asset } @@ -55,13 +51,17 @@ namespace vk_gltf_viewer::gltf { * @param nodeIndex Node index to be started. */ void updateDescendantNodeTransformsFrom(std::size_t nodeIndex) { - glm::mat4 currentNodeWorldTransform = visit(LIFT(fastgltf::toMatrix), pAsset->nodes[nodeIndex].transform); + fastgltf::math::fmat4x4 currentNodeWorldTransform = visit(fastgltf::visitor { + + [&](const fastgltf::TRS &trs) { return toMatrix(trs); }, + [&](const fastgltf::math::fmat4x4 &matrix) { return matrix; }, + }, pAsset->nodes[nodeIndex].transform); // If node is not root node, pre-multiply the parent node's world transform. if (auto parentNodeIndex = getParentNodeIndex(nodeIndex)) { currentNodeWorldTransform = nodeWorldTransforms[*parentNodeIndex] * currentNodeWorldTransform; } - algorithm::traverseNode(*pAsset, nodeIndex, [this](std::size_t nodeIndex, const glm::mat4 &nodeWorldTransform) { + algorithm::traverseNode(*pAsset, nodeIndex, [this](std::size_t nodeIndex, const fastgltf::math::fmat4x4 &nodeWorldTransform) { nodeWorldTransforms[nodeIndex] = nodeWorldTransform; }, currentNodeWorldTransform); } @@ -77,9 +77,9 @@ namespace vk_gltf_viewer::gltf { return result; } - [[nodiscard]] std::vector createNodeWorldTransforms(const fastgltf::Scene &scene) const noexcept { - std::vector result(pAsset->nodes.size()); - algorithm::traverseScene(*pAsset, scene, [&](std::size_t nodeIndex, const glm::mat4 &nodeWorldTransform) { + [[nodiscard]] std::vector createNodeWorldTransforms(const fastgltf::Scene &scene) const noexcept { + std::vector result(pAsset->nodes.size()); + algorithm::traverseScene(*pAsset, scene, [&](std::size_t nodeIndex, const fastgltf::math::fmat4x4 &nodeWorldTransform) { result[nodeIndex] = nodeWorldTransform; }); return result; diff --git a/interface/gltf/algorithm/bounding_box.cppm b/interface/gltf/algorithm/bounding_box.cppm index 75d08d7d..e356dfab 100644 --- a/interface/gltf/algorithm/bounding_box.cppm +++ b/interface/gltf/algorithm/bounding_box.cppm @@ -2,7 +2,6 @@ export module vk_gltf_viewer:gltf.algorithm.bounding_box; import std; export import fastgltf; -export import glm; namespace vk_gltf_viewer::gltf::algorithm { /** @@ -21,24 +20,24 @@ namespace vk_gltf_viewer::gltf::algorithm { * @return Array of 8 corner points of the bounding box. */ export - [[nodiscard]] std::array getBoundingBoxCornerPoints(const fastgltf::Asset &asset, const fastgltf::Primitive &primitive) { + [[nodiscard]] std::array getBoundingBoxCornerPoints(const fastgltf::Asset &asset, const fastgltf::Primitive &primitive) { const fastgltf::Accessor &accessor = asset.accessors[primitive.findAttribute("POSITION")->accessorIndex]; // TODO: current glTF specification guarantees that there are min/max attributes for POSITION with // dvec3 type, but KHR_mesh_quantization extension offers non-double precision POSITION attributes, // which would be problematic in future. Need caution. - const std::span min { std::get_if>(&accessor.min)->data(), 3 }; - const std::span max { std::get_if>(&accessor.max)->data(), 3 }; + const double *const pMin = std::get_if>(&accessor.min)->data(); + const double *const pMax = std::get_if>(&accessor.max)->data(); return { - glm::dvec3 { min[0], min[1], min[2] }, - glm::dvec3 { min[0], min[1], max[2] }, - glm::dvec3 { min[0], max[1], min[2] }, - glm::dvec3 { min[0], max[1], max[2] }, - glm::dvec3 { max[0], min[1], min[2] }, - glm::dvec3 { max[0], min[1], max[2] }, - glm::dvec3 { max[0], max[1], min[2] }, - glm::dvec3 { max[0], max[1], max[2] }, + fastgltf::math::dvec3 { pMin[0], pMin[1], pMin[2] }, + fastgltf::math::dvec3 { pMin[0], pMin[1], pMax[2] }, + fastgltf::math::dvec3 { pMin[0], pMax[1], pMin[2] }, + fastgltf::math::dvec3 { pMin[0], pMax[1], pMax[2] }, + fastgltf::math::dvec3 { pMax[0], pMin[1], pMin[2] }, + fastgltf::math::dvec3 { pMax[0], pMin[1], pMax[2] }, + fastgltf::math::dvec3 { pMax[0], pMax[1], pMin[2] }, + fastgltf::math::dvec3 { pMax[0], pMax[1], pMax[2] }, }; } } \ No newline at end of file diff --git a/interface/gltf/algorithm/miniball.cppm b/interface/gltf/algorithm/miniball.cppm index f166a4c2..ea0e62ab 100644 --- a/interface/gltf/algorithm/miniball.cppm +++ b/interface/gltf/algorithm/miniball.cppm @@ -8,15 +8,11 @@ export module vk_gltf_viewer:gltf.algorithm.miniball; import std; export import fastgltf; -export import glm; import :gltf.algorithm.bounding_box; import :gltf.algorithm.traversal; import :helpers.concepts; import :helpers.ranges; -#define FWD(...) static_cast(__VA_ARGS__) -#define LIFT(...) [&](auto &&...xs) { return (__VA_ARGS__)(FWD(xs)...); } - namespace vk_gltf_viewer::gltf::algorithm { /** * @brief The smallest enclosing sphere of the scene meshes' bounding boxes, i.e. miniball. @@ -27,8 +23,8 @@ namespace vk_gltf_viewer::gltf::algorithm { * @param transformGetter A function that follows the MeshNodeTransformGetter concept. * @return The pair of the miniball's center and radius. */ - template MeshNodeTransformGetter> - [[nodiscard]] std::pair getMiniball(const fastgltf::Asset &asset, const fastgltf::Scene &scene, const MeshNodeTransformGetter &transformGetter) { + template MeshNodeTransformGetter> + [[nodiscard]] std::pair getMiniball(const fastgltf::Asset &asset, const fastgltf::Scene &scene, const MeshNodeTransformGetter &transformGetter) { // See https://doc.cgal.org/latest/Bounding_volumes/index.html for the original code. using Traits = CGAL::Min_sphere_of_points_d_traits_3, double>; std::vector meshBoundingBoxPoints; @@ -41,11 +37,11 @@ namespace vk_gltf_viewer::gltf::algorithm { } const fastgltf::Mesh &mesh = asset.meshes[*node.meshIndex]; - const auto collectTransformedBoundingBoxPoints = [&](const glm::dmat4 &worldTransform) { + const auto collectTransformedBoundingBoxPoints = [&](const fastgltf::math::dmat4x4 &worldTransform) { for (const fastgltf::Primitive &primitive : mesh.primitives) { - for (const glm::dvec3 &point : getBoundingBoxCornerPoints(asset, primitive)) { - const glm::dvec3 transformedPoint { worldTransform * glm::dvec4 { point, 1.0 } }; - meshBoundingBoxPoints.emplace_back(transformedPoint.x, transformedPoint.y, transformedPoint.z); + for (const fastgltf::math::dvec3 &point : getBoundingBoxCornerPoints(asset, primitive)) { + const fastgltf::math::dvec3 transformedPoint { worldTransform * fastgltf::math::dvec4 { point.x(), point.y(), point.z(), 1.0 } }; + meshBoundingBoxPoints.emplace_back(transformedPoint.x(), transformedPoint.y(), transformedPoint.z()); } } }; @@ -62,8 +58,8 @@ namespace vk_gltf_viewer::gltf::algorithm { CGAL::Min_sphere_of_spheres_d ms { meshBoundingBoxPoints.begin(), meshBoundingBoxPoints.end() }; - glm::dvec3 center; - std::copy(ms.center_cartesian_begin(), ms.center_cartesian_end(), value_ptr(center)); + fastgltf::math::dvec3 center; + std::copy(ms.center_cartesian_begin(), ms.center_cartesian_end(), center.data()); return { center, ms.radius() }; } } \ No newline at end of file diff --git a/interface/gltf/algorithm/traversal.cppm b/interface/gltf/algorithm/traversal.cppm index a64155c6..341ab49f 100644 --- a/interface/gltf/algorithm/traversal.cppm +++ b/interface/gltf/algorithm/traversal.cppm @@ -1,13 +1,9 @@ export module vk_gltf_viewer:gltf.algorithm.traversal; import std; -export import glm; export import fastgltf; import :helpers.fastgltf; -#define FWD(...) static_cast(__VA_ARGS__) -#define LIFT(...) [&](auto &&...xs) { return (__VA_ARGS__)(FWD(xs)...); } - namespace vk_gltf_viewer::gltf::algorithm { /** * Traverse node's descendants using preorder traversal. @@ -41,19 +37,22 @@ namespace vk_gltf_viewer::gltf::algorithm { /** * Traverse node's descendants with accumulated transforms (i.e. world transform) using preorder traversal. - * @tparam F Function type that can be executed with node index and glm::mat4. If it returns contextually convertible to bool type, the return value will be determined as the traversal continuation (true -> continue traversal). + * @tparam F Function type that can be executed with node index and fastgltf::math::fmat4x4. If it returns contextually convertible to bool type, the return value will be determined as the traversal continuation (true -> continue traversal). * @param asset fastgltf Asset. * @param nodeIndex Node index to start traversal. - * @param f Function that would be invoked with node index and glm::mat4. + * @param f Function that would be invoked with node index and fastgltf::math::fmat4x4. * @param initialNodeWorldTransform World transform matrix of the start node. */ - export template F> - void traverseNode(const fastgltf::Asset &asset, std::size_t nodeIndex, const F &f, const glm::mat4 &initialNodeWorldTransform) noexcept(std::is_nothrow_invocable_v) { - [&](this const auto &self, std::size_t nodeIndex, glm::mat4 worldTransform) -> void { + export template F> + void traverseNode(const fastgltf::Asset &asset, std::size_t nodeIndex, const F &f, const fastgltf::math::fmat4x4 &initialNodeWorldTransform) noexcept(std::is_nothrow_invocable_v) { + [&](this const auto &self, std::size_t nodeIndex, fastgltf::math::fmat4x4 worldTransform) -> void { const fastgltf::Node &node = asset.nodes[nodeIndex]; - worldTransform *= visit(LIFT(fastgltf::toMatrix), node.transform); + visit(fastgltf::visitor { + [&](const fastgltf::TRS &trs) { worldTransform = worldTransform * toMatrix(trs); }, + [&](const fastgltf::math::fmat4x4 &matrix) { worldTransform = worldTransform * matrix; }, + }, node.transform); - if constexpr (std::convertible_to, bool>) { + if constexpr (std::convertible_to, bool>) { // If F's return type is bool type, traverse continuation have to be determined by the return value of f. if (f(nodeIndex, worldTransform)) { // Continue traversal only if f returns true. @@ -87,15 +86,15 @@ namespace vk_gltf_viewer::gltf::algorithm { /** * Traverse \p scene with accumulated transforms (i.e. world transform) using preorder traversal. - * @tparam F Function type that can be executed with node index and glm::mat4. If it returns contextually convertible to bool type, the return value will be determined as the traversal continuation (true -> continue traversal). + * @tparam F Function type that can be executed with node index and fastgltf::math::fmat4x4. If it returns contextually convertible to bool type, the return value will be determined as the traversal continuation (true -> continue traversal). * @param asset fastgltf Asset. * @param scene fastgltf Scene. This must be originated from \p asset. - * @param f Function that would be invoked with node index and glm::mat4. + * @param f Function that would be invoked with node index and fastgltf::math::fmat4x4. */ - export template F> - void traverseScene(const fastgltf::Asset &asset, const fastgltf::Scene &scene, const F &f) noexcept(std::is_nothrow_invocable_v) { + export template F> + void traverseScene(const fastgltf::Asset &asset, const fastgltf::Scene &scene, const F &f) noexcept(std::is_nothrow_invocable_v) { for (std::size_t nodeIndex : scene.nodeIndices) { - traverseNode(asset, nodeIndex, f, glm::mat4 { 1.f }); + traverseNode(asset, nodeIndex, f, fastgltf::math::fmat4x4 { 1.f }); } } } \ No newline at end of file diff --git a/interface/helpers/fastgltf.cppm b/interface/helpers/fastgltf.cppm index e0eaaa3c..3b77f452 100644 --- a/interface/helpers/fastgltf.cppm +++ b/interface/helpers/fastgltf.cppm @@ -2,11 +2,10 @@ export module vk_gltf_viewer:helpers.fastgltf; import std; export import fastgltf; -export import glm; export import :helpers.cstring_view; export import :helpers.optional; -#define FWD(...) static_cast(__VA_ARGS__) +#define INDEX_SEQ(Is, N, ...) [&](std::index_sequence) __VA_ARGS__ (std::make_index_sequence{}) #define DEFINE_FORMATTER(Type) \ export template <> \ struct std::formatter : formatter { \ @@ -141,15 +140,15 @@ namespace fastgltf { } } + /** + * @brief Convert TRS to 4x4 matrix. + * @param trs TRS to convert. + * @return 4x4 matrix. + */ export - [[nodiscard]] glm::mat4 toMatrix(const math::fmat4x4 &transformMatrix) noexcept { - return glm::make_mat4(transformMatrix.data()); - } - - export - [[nodiscard]] glm::mat4 toMatrix(const TRS &trs) noexcept { + [[nodiscard]] math::fmat4x4 toMatrix(const TRS &trs) noexcept { constexpr math::fmat4x4 identity { 1.f }; - return toMatrix(translate(identity, trs.translation) * rotate(identity, trs.rotation) * scale(identity, trs.scale)); + return translate(identity, trs.translation) * rotate(identity, trs.rotation) * scale(identity, trs.scale); } /** @@ -253,6 +252,24 @@ namespace fastgltf { return std::move(expected.get()); } + +namespace math { + /** + * @brief Convert matrix of type \tp U to matrix of type \tp T. + * @tparam T The destination matrix type. + * @tparam U The source matrix type. + * @tparam N The number of columns. + * @tparam M The number of rows. + * @param m The source matrix. + * @return The converted matrix of type \tp T. + */ + export template + [[nodiscard]] mat cast(const mat &m) noexcept { + return INDEX_SEQ(Is, M, { + return mat { vec { m[Is] }... }; + }); + } +} } DEFINE_FORMATTER(fastgltf::PrimitiveType);