From 750b550f30158847b7fd0d5d21fc291f5d57d371 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Fri, 10 May 2024 13:47:22 +0800 Subject: [PATCH 1/2] add bounds min,max to gltf --- shards/gfx/gltf/gltf.cpp | 58 ++++++++++++++++++++++++++++- shards/gfx/gltf/gltf.hpp | 2 + shards/modules/gfx/gltf.cpp | 4 ++ shards/modules/gfx/shards_types.hpp | 4 ++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/shards/gfx/gltf/gltf.cpp b/shards/gfx/gltf/gltf.cpp index 1262207c79..17375132bf 100644 --- a/shards/gfx/gltf/gltf.cpp +++ b/shards/gfx/gltf/gltf.cpp @@ -646,7 +646,7 @@ struct Loader { loadMeshes(); loadNodes(); - // Unify everyhing into a single node per scene + // Unify everything into a single node per scene // needs to be done before computing animation paths in skins size_t numScenes = model.scenes.size(); sceneMap.resize(numScenes); @@ -674,6 +674,57 @@ struct Loader { } }; +// Helper function to convert tinygltf matrix to linalg matrix +linalg::mat convertMatrix(const std::vector &m) { + return {{m[0], m[1], m[2], m[3]}, {m[4], m[5], m[6], m[7]}, {m[8], m[9], m[10], m[11]}, {m[12], m[13], m[14], m[15]}}; +} + +// Compute the model matrix for a node +linalg::mat getModelMatrix(const tinygltf::Node &node) { + auto translation = node.translation.empty() + ? linalg::vec{0, 0, 0} + : linalg::vec{node.translation[0], node.translation[1], node.translation[2]}; + auto rotation = node.rotation.empty() + ? linalg::vec{0, 0, 0, 1} + : linalg::vec{node.rotation[0], node.rotation[1], node.rotation[2], node.rotation[3]}; + auto scale = + node.scale.empty() ? linalg::vec{1, 1, 1} : linalg::vec{node.scale[0], node.scale[1], node.scale[2]}; + auto matrix = node.matrix.empty() ? linalg::identity_t{4} : convertMatrix(node.matrix); + + // Combine transformations + auto T = linalg::translation_matrix(translation); + auto R = linalg::rotation_matrix(rotation); + auto S = linalg::scaling_matrix(scale); + return linalg::mul(linalg::mul(linalg::mul(matrix, T), R), S); +} + +void computeBoundingBox(const tinygltf::Node &node, const tinygltf::Model &model, linalg::vec &global_min, + linalg::vec &global_max, + const linalg::mat &parentTransform = linalg::identity_t{4}) { + linalg::mat modelMatrix = linalg::mul(parentTransform, getModelMatrix(node)); + + if (node.mesh != -1) { + const tinygltf::Mesh &mesh = model.meshes[node.mesh]; + for (const auto &primitive : mesh.primitives) { + const tinygltf::Accessor &accessor = model.accessors[primitive.attributes.find("POSITION")->second]; + const tinygltf::BufferView &bufferView = model.bufferViews[accessor.bufferView]; + const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer]; + + const double *positions = reinterpret_cast(&(buffer.data[bufferView.byteOffset + accessor.byteOffset])); + for (size_t i = 0; i < accessor.count; ++i) { + linalg::vec vertex(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]); + vertex = linalg::mul(modelMatrix, linalg::vec{vertex, 1}).xyz(); + global_min = linalg::min(global_min, vertex); + global_max = linalg::max(global_max, vertex); + } + } + } + + for (int child : node.children) { + computeBoundingBox(model.nodes[child], model, global_min, global_max, modelMatrix); + } +} + template glTF load(T loader) { tinygltf::Model model; loader(model); @@ -693,6 +744,11 @@ template glTF load(T loader) { result.root = std::move(gfxLoader.sceneMap[model.defaultScene]); result.animations = std::move(gfxLoader.animations); result.materials = std::move(gfxLoader.materials); + + // compute bounding box + if (model.scenes[model.defaultScene].nodes.size() > 0) + computeBoundingBox(model.nodes[model.scenes[model.defaultScene].nodes[0]], model, result.boundsMin, result.boundsMax); + return result; } diff --git a/shards/gfx/gltf/gltf.hpp b/shards/gfx/gltf/gltf.hpp index a62fdb6bf1..63942766b6 100644 --- a/shards/gfx/gltf/gltf.hpp +++ b/shards/gfx/gltf/gltf.hpp @@ -13,6 +13,8 @@ struct glTF { MeshTreeDrawable::Ptr root; std::unordered_map animations; std::unordered_map materials; + linalg::vec boundsMin = {0, 0, 0}; + linalg::vec boundsMax = {0, 0, 0}; glTF() = default; diff --git a/shards/modules/gfx/gltf.cpp b/shards/modules/gfx/gltf.cpp index a44408da91..569e3f08e1 100644 --- a/shards/modules/gfx/gltf.cpp +++ b/shards/modules/gfx/gltf.cpp @@ -555,6 +555,8 @@ struct GLTFShard { _model->root = std::static_pointer_cast(other->clone()); _model->animations = shOther.animations; _model->materials = shOther.materials; + _model->boundsMin = shOther.boundsMin; + _model->boundsMax = shOther.boundsMax; rootNodeWrapped = shOther.rootNodeWrapped; } break; case LoadMode::LoadFileStatic: @@ -573,6 +575,8 @@ struct GLTFShard { _drawable->drawable = _model->root; _drawable->animations = _model->animations; _drawable->materials = _model->materials; + _drawable->boundsMin = _model->boundsMin; + _drawable->boundsMax = _model->boundsMax; if (hasAnimationController()) { shardifyAnimationData(); diff --git a/shards/modules/gfx/shards_types.hpp b/shards/modules/gfx/shards_types.hpp index fcac4bbfc5..ac063bbad6 100644 --- a/shards/modules/gfx/shards_types.hpp +++ b/shards/modules/gfx/shards_types.hpp @@ -1,6 +1,7 @@ #ifndef E452293C_6700_4675_8B6E_5293674E0A33 #define E452293C_6700_4675_8B6E_5293674E0A33 +#include "shards/shards.h" #include #include #include @@ -28,6 +29,9 @@ struct SHDrawable { Variant drawable; std::unordered_map animations; std::unordered_map materials; + linalg::vec boundsMin = {0, 0, 0}; + linalg::vec boundsMax = {0, 0, 0}; + bool rootNodeWrapped{}; void assign(const std::shared_ptr &generic) { From 9b00dede361763dc82afa29bebb1f2075b815232 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Fri, 10 May 2024 14:09:31 +0800 Subject: [PATCH 2/2] PR fixes --- shards/gfx/gltf/gltf.cpp | 35 +++++++++++++---------------- shards/gfx/gltf/gltf.hpp | 4 ++-- shards/modules/gfx/shards_types.hpp | 4 ++-- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/shards/gfx/gltf/gltf.cpp b/shards/gfx/gltf/gltf.cpp index 17375132bf..763ca70b89 100644 --- a/shards/gfx/gltf/gltf.cpp +++ b/shards/gfx/gltf/gltf.cpp @@ -674,22 +674,17 @@ struct Loader { } }; -// Helper function to convert tinygltf matrix to linalg matrix -linalg::mat convertMatrix(const std::vector &m) { - return {{m[0], m[1], m[2], m[3]}, {m[4], m[5], m[6], m[7]}, {m[8], m[9], m[10], m[11]}, {m[12], m[13], m[14], m[15]}}; -} - // Compute the model matrix for a node -linalg::mat getModelMatrix(const tinygltf::Node &node) { +linalg::mat getModelMatrix(const tinygltf::Node &node) { auto translation = node.translation.empty() - ? linalg::vec{0, 0, 0} - : linalg::vec{node.translation[0], node.translation[1], node.translation[2]}; + ? linalg::vec{0, 0, 0} + : linalg::vec{node.translation[0], node.translation[1], node.translation[2]}; auto rotation = node.rotation.empty() - ? linalg::vec{0, 0, 0, 1} - : linalg::vec{node.rotation[0], node.rotation[1], node.rotation[2], node.rotation[3]}; + ? linalg::vec{0, 0, 0, 1} + : linalg::vec{node.rotation[0], node.rotation[1], node.rotation[2], node.rotation[3]}; auto scale = - node.scale.empty() ? linalg::vec{1, 1, 1} : linalg::vec{node.scale[0], node.scale[1], node.scale[2]}; - auto matrix = node.matrix.empty() ? linalg::identity_t{4} : convertMatrix(node.matrix); + node.scale.empty() ? linalg::vec{1, 1, 1} : linalg::vec{node.scale[0], node.scale[1], node.scale[2]}; + auto matrix = node.matrix.empty() ? linalg::identity_t{4} : convertNodeTransform(node).getMatrix(); // Combine transformations auto T = linalg::translation_matrix(translation); @@ -698,10 +693,10 @@ linalg::mat getModelMatrix(const tinygltf::Node &node) { return linalg::mul(linalg::mul(linalg::mul(matrix, T), R), S); } -void computeBoundingBox(const tinygltf::Node &node, const tinygltf::Model &model, linalg::vec &global_min, - linalg::vec &global_max, - const linalg::mat &parentTransform = linalg::identity_t{4}) { - linalg::mat modelMatrix = linalg::mul(parentTransform, getModelMatrix(node)); +void computeBoundingBox(const tinygltf::Node &node, const tinygltf::Model &model, linalg::vec &global_min, + linalg::vec &global_max, + const linalg::mat &parentTransform = linalg::identity_t{4}) { + linalg::mat modelMatrix = linalg::mul(parentTransform, getModelMatrix(node)); if (node.mesh != -1) { const tinygltf::Mesh &mesh = model.meshes[node.mesh]; @@ -710,10 +705,12 @@ void computeBoundingBox(const tinygltf::Node &node, const tinygltf::Model &model const tinygltf::BufferView &bufferView = model.bufferViews[accessor.bufferView]; const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer]; - const double *positions = reinterpret_cast(&(buffer.data[bufferView.byteOffset + accessor.byteOffset])); + // Adjusting buffer data interpretation to float instead of double + const float *positions = reinterpret_cast(&(buffer.data[bufferView.byteOffset + accessor.byteOffset])); for (size_t i = 0; i < accessor.count; ++i) { - linalg::vec vertex(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]); - vertex = linalg::mul(modelMatrix, linalg::vec{vertex, 1}).xyz(); + linalg::vec vertex(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]); + linalg::vec vertex_homogeneous(vertex, 1.0f); // Homogenize the vertex for transformation + vertex = linalg::mul(modelMatrix, vertex_homogeneous).xyz(); // Apply transformation and reduce back to 3D global_min = linalg::min(global_min, vertex); global_max = linalg::max(global_max, vertex); } diff --git a/shards/gfx/gltf/gltf.hpp b/shards/gfx/gltf/gltf.hpp index 63942766b6..b22f5dc0c2 100644 --- a/shards/gfx/gltf/gltf.hpp +++ b/shards/gfx/gltf/gltf.hpp @@ -13,8 +13,8 @@ struct glTF { MeshTreeDrawable::Ptr root; std::unordered_map animations; std::unordered_map materials; - linalg::vec boundsMin = {0, 0, 0}; - linalg::vec boundsMax = {0, 0, 0}; + linalg::vec boundsMin = {0, 0, 0}; + linalg::vec boundsMax = {0, 0, 0}; glTF() = default; diff --git a/shards/modules/gfx/shards_types.hpp b/shards/modules/gfx/shards_types.hpp index ac063bbad6..4bca29ad1a 100644 --- a/shards/modules/gfx/shards_types.hpp +++ b/shards/modules/gfx/shards_types.hpp @@ -29,8 +29,8 @@ struct SHDrawable { Variant drawable; std::unordered_map animations; std::unordered_map materials; - linalg::vec boundsMin = {0, 0, 0}; - linalg::vec boundsMax = {0, 0, 0}; + linalg::vec boundsMin = {0, 0, 0}; + linalg::vec boundsMax = {0, 0, 0}; bool rootNodeWrapped{};