Skip to content

Commit

Permalink
Fix glTF / glb root node transform (#543)
Browse files Browse the repository at this point in the history
Signed-off-by: Ian Chen <[email protected]>
  • Loading branch information
iche033 authored Oct 23, 2023
1 parent d9d1722 commit afc1ab0
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 9 deletions.
50 changes: 41 additions & 9 deletions graphics/src/AssimpLoader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};

//////////////////////////////////////////////////
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

}
}
43 changes: 43 additions & 0 deletions graphics/src/AssimpLoader_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Binary file not shown.

0 comments on commit afc1ab0

Please sign in to comment.