summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/gltf/llgltfloader.cpp86
-rw-r--r--indra/newview/gltf/llgltfloader.h3
2 files changed, 88 insertions, 1 deletions
diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp
index 2dc1aa369b..8fe5a8f2fb 100644
--- a/indra/newview/gltf/llgltfloader.cpp
+++ b/indra/newview/gltf/llgltfloader.cpp
@@ -76,6 +76,13 @@ static const glm::mat4 coord_system_rotation(
);
+static const glm::mat4 coord_system_rotationxy(
+ 0.f, 1.f, 0.f, 0.f,
+ -1.f, 0.f, 0.f, 0.f,
+ 0.f, 0.f, 1.f, 0.f,
+ 0.f, 0.f, 0.f, 1.f
+);
+
LLGLTFLoader::LLGLTFLoader(std::string filename,
S32 lod,
LLModelLoader::load_callback_t load_cb,
@@ -254,6 +261,11 @@ bool LLGLTFLoader::parseMeshes()
node.makeMatrixValid();
}
+ if (mGLTFAsset.mSkins.size() > 0)
+ {
+ checkForXYrotation(mGLTFAsset.mSkins[0]);
+ }
+
// Populate the joints from skins first.
// There's not many skins - and you can pretty easily iterate through the nodes from that.
for (S32 i = 0; i < mGLTFAsset.mSkins.size(); i++)
@@ -461,7 +473,11 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
computeCombinedNodeTransform(mGLTFAsset, node_index, hierarchy_transform);
// Combine transforms: coordinate rotation applied to hierarchy transform
- const glm::mat4 final_transform = coord_system_rotation * hierarchy_transform;
+ glm::mat4 final_transform = coord_system_rotation * hierarchy_transform;
+ if (mApplyXYRotation)
+ {
+ final_transform = coord_system_rotationxy * final_transform;
+ }
// Check if we have a negative scale (flipped coordinate system)
bool hasNegativeScale = glm::determinant(final_transform) < 0.0f;
@@ -864,6 +880,10 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
// This is very likely incomplete in some way.
// Root shouldn't be the only one to need full coordinate fix
joint_mat = coord_system_rotation * joint_mat;
+ if (mApplyXYRotation)
+ {
+ joint_mat = coord_system_rotationxy * joint_mat;
+ }
}
LLMatrix4 original_joint_transform(glm::value_ptr(joint_mat));
@@ -1151,9 +1171,73 @@ glm::mat4 LLGLTFLoader::computeGltfToViewerSkeletonTransform(const LL::GLTF::Ski
// Compute transformation from GLTF space to viewer space
// This assumes both skeletons are in rest pose initially
+ if (mApplyXYRotation)
+ {
+ return viewer_joint_rest_pose * glm::inverse(gltf_joint_rest_pose);
+ }
return viewer_joint_rest_pose * glm::inverse(gltf_joint_rest_pose);
}
+bool LLGLTFLoader::checkForXYrotation(const LL::GLTF::Skin& gltf_skin, S32 joint_idx, S32 bind_indx)
+{
+ glm::mat4 gltf_joint_rest = buildGltfRestMatrix(joint_idx, gltf_skin);
+ glm::mat4 test_mat = glm::inverse(gltf_joint_rest) * gltf_skin.mInverseBindMatricesData[bind_indx];
+ // Normally for shoulders it should be something close to
+ // {1,0,0,0;0,-1,0,0;0,0,-1,0;0,0,0,1}
+ // rotated one will look like
+ // {0,0,0,-1;1,0,0,0;0,-1,0,0;0,0,0,1}
+ // Todo: This is a cheap hack,
+ // figure out how rotation is supposed to work
+ return abs(test_mat[0][0]) < 0.5 && abs(test_mat[1][1]) < 0.5 && abs(test_mat[2][2]) < 0.5;
+}
+
+void LLGLTFLoader::checkForXYrotation(const LL::GLTF::Skin& gltf_skin)
+{
+ // HACK: figure out model's rotation from shoulders' matrix.
+ // This is wrong on many levels:
+ // Too limited (only models that have shoulders),
+ // Will not work well with things that emulate 3 hands in some manner
+ // Only supports xy 90 degree rotation
+ // Todo: figure out how to find skeleton's orientation Correctly
+ // when model is rotated at a triangle level
+ constexpr char right_shoulder_str[] = "mShoulderRight";
+ constexpr char left_shoulder_str[] = "mShoulderLeft";
+
+ S32 size = (S32)gltf_skin.mJoints.size();
+ S32 joints_found = 0;
+ for (S32 i= 0; i < size; i++)
+ {
+ S32 joint = gltf_skin.mJoints[i];
+ auto joint_node = mGLTFAsset.mNodes[joint];
+
+ // todo: we are doing this search thing everywhere,
+ // just pre-translate every joint
+ JointMap::iterator found = mJointMap.find(joint_node.mName);
+ if (found == mJointMap.end())
+ {
+ // unsupported joint
+ continue;
+ }
+ if (found->second == right_shoulder_str || found->second == left_shoulder_str)
+ {
+ if (checkForXYrotation(gltf_skin, joint, i))
+ {
+ joints_found++;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
+ if (joints_found == 2)
+ {
+ // Both joints in a weird position/rotation, assume rotated model
+ mApplyXYRotation = true;
+ }
+}
+
bool LLGLTFLoader::parseMaterials()
{
if (!mGltfLoaded) return false;
diff --git a/indra/newview/gltf/llgltfloader.h b/indra/newview/gltf/llgltfloader.h
index 41e6a2dd6d..50a63c1cd8 100644
--- a/indra/newview/gltf/llgltfloader.h
+++ b/indra/newview/gltf/llgltfloader.h
@@ -156,6 +156,7 @@ protected:
bool mGltfLoaded;
bool mMeshesLoaded;
bool mMaterialsLoaded;
+ bool mApplyXYRotation = false;
U32 mGeneratedModelLimit;
std::vector<gltf_mesh> mMeshes;
@@ -190,6 +191,8 @@ private:
S32 findParentNode(S32 node) const;
glm::mat4 buildGltfRestMatrix(S32 joint_node_index, const LL::GLTF::Skin& gltf_skin) const;
glm::mat4 computeGltfToViewerSkeletonTransform(const LL::GLTF::Skin& gltf_skin, S32 joint_index, const std::string& joint_name) const;
+ bool checkForXYrotation(const LL::GLTF::Skin& gltf_skin, S32 joint_idx, S32 bind_indx);
+ void checkForXYrotation(const LL::GLTF::Skin& gltf_skin);
LLUUID imageBufferToTextureUUID(const gltf_texture& tex);
void notifyUnsupportedExtension(bool unsupported);