From afc1ab06303396581b740f8e114f9033506b9513 Mon Sep 17 00:00:00 2001 From: Ian Chen Date: Mon, 23 Oct 2023 09:28:38 -0700 Subject: [PATCH] Fix glTF / glb root node transform (#543) Signed-off-by: Ian Chen --- graphics/src/AssimpLoader.cc | 50 ++++++++++++++---- graphics/src/AssimpLoader_TEST.cc | 43 +++++++++++++++ .../multiple_texture_coordinates_triangle.glb | Bin 0 -> 2132 bytes 3 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 test/data/multiple_texture_coordinates_triangle.glb diff --git a/graphics/src/AssimpLoader.cc b/graphics/src/AssimpLoader.cc index ba2c5765..79f513b4 100644 --- a/graphics/src/AssimpLoader.cc +++ b/graphics/src/AssimpLoader.cc @@ -155,6 +155,15 @@ class AssimpLoader::Implementation /// calculated from the "old" parent model transform. /// \param[in] _skeleton the skeleton to work on public: void ApplyInvBindTransform(SkeletonPtr _skeleton) const; + + /// Get the updated root node transform. The function updates the original + /// transform by setting the rotation to identity if requested. + /// \param[in] _scene Scene with axes info stored in meta data + /// \param[in] _useIdentityRotation Whether to set rotation to identity. + /// Note: This is currently set to false for glTF / glb meshes. + /// \return Updated transform + public: aiMatrix4x4 UpdatedRootNodeTransform(const aiScene *_scene, + bool _useIdentityRotation = true); }; ////////////////////////////////////////////////// @@ -645,16 +654,15 @@ Mesh *AssimpLoader::Load(const std::string &_filename) } auto& rootNode = scene->mRootNode; auto rootName = ToString(rootNode->mName); - auto transform = scene->mRootNode->mTransformation; - aiVector3D rootScaling, rootAxis, rootPos; - float angle; - transform.Decompose(rootScaling, rootAxis, angle, rootPos); - // drop rotation, but keep scaling and position - // TODO(luca) it seems imported assets are rotated by 90 degrees - // as documented here https://github.com/assimp/assimp/issues/849 - // remove workaround when fixed - transform = aiMatrix4x4(rootScaling, aiQuaternion(), rootPos); + // compute assimp root node transform + std::string extension = _filename.substr(_filename.rfind(".") + 1, + _filename.size()); + std::transform(extension.begin(), extension.end(), + extension.begin(), ::tolower); + bool useIdentityRotation = (extension != "glb" && extension != "glTF"); + auto transform = this->dataPtr->UpdatedRootNodeTransform(scene, + useIdentityRotation); auto rootTransform = this->dataPtr->ConvertTransform(transform); // Add the materials first @@ -750,5 +758,29 @@ void AssimpLoader::Implementation::ApplyInvBindTransform( } } +///////////////////////////////////////////////// +aiMatrix4x4 AssimpLoader::Implementation::UpdatedRootNodeTransform( + const aiScene *_scene, bool _useIdentityRotation) +{ + // Some assets apear to be rotated by 90 degrees as documented here + // https://github.com/assimp/assimp/issues/849. + auto transform = _scene->mRootNode->mTransformation; + if (_useIdentityRotation) + { + // drop rotation, but keep scaling and position + aiVector3D rootScaling, rootAxis, rootPos; + float angle; + transform.Decompose(rootScaling, rootAxis, angle, rootPos); + transform = aiMatrix4x4(rootScaling, aiQuaternion(), rootPos); + } + // for glTF / glb meshes, it was found that the transform is needed to + // produce a result that is consistent with other engines / glTF viewers. + else + { + transform = _scene->mRootNode->mTransformation; + } + return transform; +} + } } diff --git a/graphics/src/AssimpLoader_TEST.cc b/graphics/src/AssimpLoader_TEST.cc index f171d427..fffd50f4 100644 --- a/graphics/src/AssimpLoader_TEST.cc +++ b/graphics/src/AssimpLoader_TEST.cc @@ -744,3 +744,46 @@ TEST_F(AssimpLoader, CheckNonRootDisplacement) auto xDisplacement = skelAnim->XDisplacement(); ASSERT_TRUE(xDisplacement); } + +///////////////////////////////////////////////// +TEST_F(AssimpLoader, LoadGLTF2Triangle) +{ + common::AssimpLoader loader; + common::Mesh *mesh = loader.Load( + common::testing::TestFile("data", + "multiple_texture_coordinates_triangle.glb")); + ASSERT_TRUE(mesh); + + EXPECT_EQ(6u, mesh->VertexCount()); + EXPECT_EQ(6u, mesh->NormalCount()); + EXPECT_EQ(6u, mesh->IndexCount()); + EXPECT_EQ(6u, mesh->TexCoordCount()); + EXPECT_EQ(2u, mesh->SubMeshCount()); + EXPECT_EQ(1u, mesh->MaterialCount()); + + auto sm = mesh->SubMeshByIndex(0u); + auto subMesh = sm.lock(); + EXPECT_NE(nullptr, subMesh); + EXPECT_EQ(math::Vector3d(0, 0, 0), subMesh->Vertex(0u)); + EXPECT_EQ(math::Vector3d(10, 0, 0), subMesh->Vertex(1u)); + EXPECT_EQ(math::Vector3d(10, 10, 0), subMesh->Vertex(2u)); + EXPECT_EQ(math::Vector3d(0, 0, 1), subMesh->Normal(0u)); + EXPECT_EQ(math::Vector3d(0, 0, 1), subMesh->Normal(1u)); + EXPECT_EQ(math::Vector3d(0, 0, 1), subMesh->Normal(2u)); + EXPECT_EQ(math::Vector2d(0, 1), subMesh->TexCoord(0u)); + EXPECT_EQ(math::Vector2d(0, 1), subMesh->TexCoord(1u)); + EXPECT_EQ(math::Vector2d(0, 1), subMesh->TexCoord(2u)); + + auto smb = mesh->SubMeshByIndex(1u); + auto subMeshB = smb.lock(); + EXPECT_NE(nullptr, subMeshB); + EXPECT_EQ(math::Vector3d(10, 0, 0), subMeshB->Vertex(0u)); + EXPECT_EQ(math::Vector3d(20, 0, 0), subMeshB->Vertex(1u)); + EXPECT_EQ(math::Vector3d(20, 10, 0), subMeshB->Vertex(2u)); + EXPECT_EQ(math::Vector3d(0, 0, 1), subMeshB->Normal(0u)); + EXPECT_EQ(math::Vector3d(0, 0, 1), subMeshB->Normal(1u)); + EXPECT_EQ(math::Vector3d(0, 0, 1), subMeshB->Normal(2u)); + EXPECT_EQ(math::Vector2d(0, 1), subMeshB->TexCoord(0u)); + EXPECT_EQ(math::Vector2d(0, 1), subMeshB->TexCoord(1u)); + EXPECT_EQ(math::Vector2d(0, 1), subMeshB->TexCoord(2u)); +} diff --git a/test/data/multiple_texture_coordinates_triangle.glb b/test/data/multiple_texture_coordinates_triangle.glb new file mode 100644 index 0000000000000000000000000000000000000000..547c93e3cab7e69fd2049405800cda33672b7b34 GIT binary patch literal 2132 zcmb_d!EV|>5Z(0B9((Q0no|!hwbulS4~+;-BwC6qu%b#4sthcSCA>!VLK`8Z{s#Fb z`cIu*aBvL*htwSG+3}nA_RX;N$L{qDLWui{khd=h`P_BdbMTUc39#qjGtOd9L^0U# z}Prv&WVIdCt; zHR!6G4m=t%nJ{#-x9Dx-IfN{^Q{W9k#DT~CF~iDf(!}@I<0)f-f*1G zrymB`G!vR&Tj)T*hrvKrC@*?a_CB=*dCzr7c`F$r^Yxk-_45KTGGgr!61{la#ksnS=h6$aRGY~MN( z3IjJ+4NLVYTN~{a=-s^%Q* z*dbSOc8)09qIX@zQF{iu_B1rk+IE_VWB57c19z0lHma)yx5nA znpLh_ctZ0n3GxnaewSew?+Sv7az7*T+x_pA<@=xfMCo3wRv#tb!*Z$ae^xEEZdsPPKP=x|`~@r8SV8~* literal 0 HcmV?d00001