From 01e439597730371f0ff2f9d89141c05c74f81597 Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Fri, 25 Apr 2025 22:49:39 +0200 Subject: [PATCH] glTF: Clean up rigid animation --- irr/src/CGLTFMeshFileLoader.cpp | 39 +++-------- src/unittest/test_irr_gltf_mesh_loader.cpp | 76 ++++++++++++---------- 2 files changed, 52 insertions(+), 63 deletions(-) diff --git a/irr/src/CGLTFMeshFileLoader.cpp b/irr/src/CGLTFMeshFileLoader.cpp index bd8356c91..f70f6692b 100644 --- a/irr/src/CGLTFMeshFileLoader.cpp +++ b/irr/src/CGLTFMeshFileLoader.cpp @@ -364,18 +364,6 @@ IAnimatedMesh* SelfType::createMesh(io::IReadFile* file) return nullptr; } -static void transformVertices(std::vector &vertices, const core::matrix4 &transform) -{ - for (auto &vertex : vertices) { - // Apply scaling, rotation and rotation (in that order) to the position. - transform.transformVect(vertex.Pos); - // For the normal, we do not want to apply the translation. - vertex.Normal = transform.rotateAndScaleVect(vertex.Normal); - // Renormalize (length might have been affected by scaling). - vertex.Normal.normalize(); - } -} - static void checkIndices(const std::vector &indices, const std::size_t nVerts) { for (u16 index : indices) { @@ -425,12 +413,6 @@ void SelfType::MeshExtractor::addPrimitive( if (n_vertices >= std::numeric_limits::max()) throw std::runtime_error("too many vertices"); - // Apply the global transform along the parent chain. - // "Only the joint transforms are applied to the skinned mesh; - // the transform of the skinned mesh node MUST be ignored." - if (!skinIdx) - transformVertices(*vertices, parent->GlobalMatrix); - auto maybeIndices = getIndices(primitive); std::vector indices; if (maybeIndices.has_value()) { @@ -441,10 +423,9 @@ void SelfType::MeshExtractor::addPrimitive( indices = generateIndices(vertices->size()); } - m_irr_model->addMeshBuffer( - new SSkinMeshBuffer(std::move(*vertices), std::move(indices))); + auto *meshbuf = new SSkinMeshBuffer(std::move(*vertices), std::move(indices)); + m_irr_model->addMeshBuffer(meshbuf); const auto meshbufNr = m_irr_model->getMeshBufferCount() - 1; - auto *meshbuf = m_irr_model->getMeshBuffer(meshbufNr); if (primitive.material.has_value()) { const auto &material = m_gltf_model.materials->at(*primitive.material); @@ -463,17 +444,17 @@ void SelfType::MeshExtractor::addPrimitive( } } - if (!skinIdx.has_value()) { - // No skin => all vertices belong entirely to their parent - for (std::size_t v = 0; v < n_vertices; ++v) { - auto *weight = m_irr_model->addWeight(parent); - weight->buffer_id = meshbufNr; - weight->vertex_id = v; - weight->strength = 1.0f; - } + if (!skinIdx) { + // Apply the global transform along the parent chain. + meshbuf->Transformation = parent->GlobalMatrix; + // Set up rigid animation + parent->AttachedMeshes.push_back(meshbufNr); return; } + // Otherwise: "Only the joint transforms are applied to the skinned mesh; + // the transform of the skinned mesh node MUST be ignored." + const auto &skin = m_gltf_model.skins->at(*skinIdx); const auto &attrs = primitive.attributes; diff --git a/src/unittest/test_irr_gltf_mesh_loader.cpp b/src/unittest/test_irr_gltf_mesh_loader.cpp index 51d8e2251..f689838db 100644 --- a/src/unittest/test_irr_gltf_mesh_loader.cpp +++ b/src/unittest/test_irr_gltf_mesh_loader.cpp @@ -91,6 +91,20 @@ SECTION("minimal triangle") { } } +auto check_cube_vertices = [](auto *meshbuf) { + REQUIRE(meshbuf->getVertexCount() == 24); + auto vertices = static_cast( + meshbuf->getVertices()); + CHECK(vertices[0].Pos == v3f{-1.0f, -1.0f, -1.0f}); + CHECK(vertices[3].Pos == v3f{-1.0f, 1.0f, -1.0f}); + CHECK(vertices[6].Pos == v3f{-1.0f, -1.0f, 1.0f}); + CHECK(vertices[9].Pos == v3f{-1.0f, 1.0f, 1.0f}); + CHECK(vertices[12].Pos == v3f{1.0f, -1.0f, -1.0f}); + CHECK(vertices[15].Pos == v3f{1.0f, 1.0f, -1.0f}); + CHECK(vertices[18].Pos == v3f{1.0f, -1.0f, 1.0f}); + CHECK(vertices[21].Pos == v3f{1.0f, 1.0f, 1.0f}); +}; + SECTION("blender cube") { const auto path = GENERATE( model_stem + "blender_cube.gltf", @@ -98,24 +112,20 @@ SECTION("blender cube") { const auto mesh = loadMesh(path); REQUIRE(mesh); REQUIRE(mesh->getMeshBufferCount() == 1); + auto *meshbuf = dynamic_cast( + mesh->getMeshBuffer(0)); + REQUIRE(meshbuf); SECTION("vertex coordinates are correct") { - REQUIRE(mesh->getMeshBuffer(0)->getVertexCount() == 24); - auto vertices = static_cast( - mesh->getMeshBuffer(0)->getVertices()); - CHECK(vertices[0].Pos == v3f{-10.0f, -10.0f, -10.0f}); - CHECK(vertices[3].Pos == v3f{-10.0f, 10.0f, -10.0f}); - CHECK(vertices[6].Pos == v3f{-10.0f, -10.0f, 10.0f}); - CHECK(vertices[9].Pos == v3f{-10.0f, 10.0f, 10.0f}); - CHECK(vertices[12].Pos == v3f{10.0f, -10.0f, -10.0f}); - CHECK(vertices[15].Pos == v3f{10.0f, 10.0f, -10.0f}); - CHECK(vertices[18].Pos == v3f{10.0f, -10.0f, 10.0f}); - CHECK(vertices[21].Pos == v3f{10.0f, 10.0f, 10.0f}); + core::matrix4 scale; + scale.setScale(v3f(10.0f)); + REQUIRE(meshbuf->Transformation == scale); + check_cube_vertices(meshbuf); } SECTION("vertex indices are correct") { - REQUIRE(mesh->getMeshBuffer(0)->getIndexCount() == 36); + REQUIRE(meshbuf->getIndexCount() == 36); auto indices = static_cast( - mesh->getMeshBuffer(0)->getIndices()); + meshbuf->getIndices()); CHECK(indices[0] == 16); CHECK(indices[1] == 5); CHECK(indices[2] == 22); @@ -123,9 +133,9 @@ SECTION("blender cube") { } SECTION("vertex normals are correct") { - REQUIRE(mesh->getMeshBuffer(0)->getVertexCount() == 24); + REQUIRE(meshbuf->getVertexCount() == 24); auto vertices = static_cast( - mesh->getMeshBuffer(0)->getVertices()); + meshbuf->getVertices()); CHECK(vertices[0].Normal == v3f{-1.0f, 0.0f, 0.0f}); CHECK(vertices[1].Normal == v3f{0.0f, -1.0f, 0.0f}); CHECK(vertices[2].Normal == v3f{0.0f, 0.0f, -1.0f}); @@ -136,9 +146,9 @@ SECTION("blender cube") { } SECTION("texture coords are correct") { - REQUIRE(mesh->getMeshBuffer(0)->getVertexCount() == 24); + REQUIRE(meshbuf->getVertexCount() == 24); auto vertices = static_cast( - mesh->getMeshBuffer(0)->getVertices()); + meshbuf->getVertices()); CHECK(vertices[0].TCoords == v2f{0.375f, 1.0f}); CHECK(vertices[1].TCoords == v2f{0.125f, 0.25f}); CHECK(vertices[2].TCoords == v2f{0.375f, 0.0f}); @@ -151,20 +161,15 @@ SECTION("blender cube scaled") { const auto mesh = loadMesh(model_stem + "blender_cube_scaled.gltf"); REQUIRE(mesh); REQUIRE(mesh->getMeshBufferCount() == 1); + auto *meshbuf = dynamic_cast( + mesh->getMeshBuffer(0)); + REQUIRE(meshbuf); SECTION("Scaling is correct") { - REQUIRE(mesh->getMeshBuffer(0)->getVertexCount() == 24); - auto vertices = static_cast( - mesh->getMeshBuffer(0)->getVertices()); - - CHECK(vertices[0].Pos == v3f{-150.0f, -1.0f, -21.5f}); - CHECK(vertices[3].Pos == v3f{-150.0f, 1.0f, -21.5f}); - CHECK(vertices[6].Pos == v3f{-150.0f, -1.0f, 21.5f}); - CHECK(vertices[9].Pos == v3f{-150.0f, 1.0f, 21.5f}); - CHECK(vertices[12].Pos == v3f{150.0f, -1.0f, -21.5f}); - CHECK(vertices[15].Pos == v3f{150.0f, 1.0f, -21.5f}); - CHECK(vertices[18].Pos == v3f{150.0f, -1.0f, 21.5f}); - CHECK(vertices[21].Pos == v3f{150.0f, 1.0f, 21.5f}); + core::matrix4 scale; + scale.setScale(v3f{150.0f, 1.0f, 21.5f}); + REQUIRE(meshbuf->Transformation == scale); + check_cube_vertices(meshbuf); } } @@ -174,14 +179,17 @@ SECTION("blender cube matrix transform") { REQUIRE(mesh->getMeshBufferCount() == 1); SECTION("Transformation is correct") { - REQUIRE(mesh->getMeshBuffer(0)->getVertexCount() == 24); + auto *meshbuf = dynamic_cast( + mesh->getMeshBuffer(0)); + REQUIRE(meshbuf); + REQUIRE(meshbuf->getVertexCount() == 24); auto vertices = static_cast( - mesh->getMeshBuffer(0)->getVertices()); + meshbuf->getVertices()); const auto checkVertex = [&](const std::size_t i, v3f vec) { // The transform scales by (1, 2, 3) and translates by (4, 5, 6). - CHECK(vertices[i].Pos == vec * v3f{1, 2, 3} - // The -6 is due to the coordinate system conversion. - + v3f{4, 5, -6}); + // The -6 is due to the coordinate system conversion. + CHECK(meshbuf->Transformation.transformVect(vertices[i].Pos) + == vec * v3f{1, 2, 3} + v3f{4, 5, -6}); }; checkVertex(0, v3f{-1, -1, -1}); checkVertex(3, v3f{-1, 1, -1});