#4148 Skeleton Translation #2

meow-7.2.2
Andrey Kleshchev 2025-06-10 14:28:07 +03:00 committed by Andrey Kleshchev
parent b4fb66c4a2
commit 4bbd6319c7
2 changed files with 88 additions and 1 deletions

View File

@ -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;

View File

@ -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);