summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llappearance/llavatarappearance.cpp22
-rw-r--r--indra/llappearance/llavatarappearance.h3
-rw-r--r--indra/newview/gltf/llgltfloader.cpp126
-rw-r--r--indra/newview/gltf/llgltfloader.h12
-rw-r--r--indra/newview/llmodelpreview.cpp7
5 files changed, 97 insertions, 73 deletions
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index a3032325c9..f3e474dba7 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -108,7 +108,12 @@ public:
private:
typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t;
- static void getJointRestMatrices(const bone_info_list_t& bone_list, LLAvatarAppearance::joint_rest_map_t& result, const glm::mat4 &parent_mat);
+ static void getJointRestMatrices(
+ const bone_info_list_t& bone_list,
+ const std::string &parent_name,
+ LLAvatarAppearance::joint_rest_map_t& rest,
+ LLAvatarAppearance::joint_parent_map_t& parent_map,
+ const glm::mat4& parent_mat);
private:
S32 mNumBones;
@@ -1674,14 +1679,17 @@ bool LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
void LLAvatarSkeletonInfo::getJointRestMatrices(
const bone_info_list_t& bone_list,
- LLAvatarAppearance::joint_rest_map_t& result,
+ const std::string& parent_name,
+ LLAvatarAppearance::joint_rest_map_t& rest,
+ LLAvatarAppearance::joint_parent_map_t& parent_map,
const glm::mat4& parent_mat)
{
for (LLAvatarBoneInfo* bone_info : bone_list)
{
glm::mat4 rest_mat = parent_mat * bone_info->getJointMatrix();
- result[bone_info->mName] = rest_mat;
- getJointRestMatrices(bone_info->mChildren, result, rest_mat);
+ rest[bone_info->mName] = rest_mat;
+ parent_map[bone_info->mName] = parent_name;
+ getJointRestMatrices(bone_info->mChildren, bone_info->mName, rest, parent_map, rest_mat);
}
}
@@ -1746,12 +1754,10 @@ const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases
return mJointAliasMap;
}
-LLAvatarAppearance::joint_rest_map_t LLAvatarAppearance:: getJointRestMatrices() const
+void LLAvatarAppearance:: getJointRestMatrices(LLAvatarAppearance::joint_rest_map_t& rest_map, LLAvatarAppearance::joint_parent_map_t& parent_map) const
{
- LLAvatarAppearance::joint_rest_map_t result;
glm::mat4 identity(1.f);
- LLAvatarSkeletonInfo::getJointRestMatrices(sAvatarSkeletonInfo->mBoneInfoList, result, identity);
- return result;
+ LLAvatarSkeletonInfo::getJointRestMatrices(sAvatarSkeletonInfo->mBoneInfoList, std::string(), rest_map, parent_map, identity);
}
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index cea2a837cd..e48d80b8ce 100644
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -154,8 +154,9 @@ public:
const avatar_joint_list_t& getSkeleton() { return mSkeleton; }
typedef std::map<std::string, std::string> joint_alias_map_t;
const joint_alias_map_t& getJointAliases();
+ typedef std::map<std::string, std::string> joint_parent_map_t; // matrix plus parent
typedef std::map<std::string, glm::mat4> joint_rest_map_t;
- joint_rest_map_t getJointRestMatrices() const;
+ void getJointRestMatrices(joint_rest_map_t& rest_map, joint_parent_map_t& parent_map) const;
protected:
static bool parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree);
diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp
index 40b9334e63..292fd09035 100644
--- a/indra/newview/gltf/llgltfloader.cpp
+++ b/indra/newview/gltf/llgltfloader.cpp
@@ -95,7 +95,8 @@ LLGLTFLoader::LLGLTFLoader(std::string filename,
std::map<std::string, std::string> &jointAliasMap,
U32 maxJointsPerMesh,
U32 modelLimit,
- joint_rest_map_t jointRestMatrices) //,
+ joint_viewer_rest_map_t jointRestMatrices,
+ joint_viewer_parent_map_t jointParentMap) //,
//bool preprocess)
: LLModelLoader( filename,
lod,
@@ -107,12 +108,13 @@ LLGLTFLoader::LLGLTFLoader(std::string filename,
jointTransformMap,
jointsFromNodes,
jointAliasMap,
- maxJointsPerMesh ),
+ maxJointsPerMesh )
//mPreprocessGLTF(preprocess),
- mMeshesLoaded(false),
- mMaterialsLoaded(false),
- mGeneratedModelLimit(modelLimit),
- mJointRestMatrices(jointRestMatrices)
+ , mMeshesLoaded(false)
+ , mMaterialsLoaded(false)
+ , mGeneratedModelLimit(modelLimit)
+ , mJointViewerRestMatrices(jointRestMatrices)
+ , mJointViewerParentMap(jointParentMap)
{
}
@@ -929,6 +931,16 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
if (mInverseBindMatrices.size() <= skin_idx)
{
mInverseBindMatrices.resize(skin_idx + 1);
+ mAlternateBindMatrices.resize(skin_idx + 1);
+ }
+
+ // Build gltf rest matrices
+ // This is very inefficienct, todo: run from root to children, not from children to root
+ joint_node_mat4_map_t gltf_rest_map;
+ for (S32 i = 0; i < joint_count; i++)
+ {
+ S32 joint = skin.mJoints[i];
+ gltf_rest_map[joint] = buildGltfRestMatrix(joint, skin);
}
for (S32 i = 0; i < joint_count; i++)
@@ -943,86 +955,84 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
legal_joint = true;
}
+ // Compute bind matrices
+
if (!legal_joint)
{
- // add placeholder to not break index
+ // Add placeholder to not break index.
+ // Not going to be used by viewer, will be stripped from skin_info.
LLMatrix4 gltf_transform;
gltf_transform.setIdentity();
mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform));
}
else if (inverse_count > i)
{
+ // Transalte existing bind matrix to viewer's skeleton
+ // todo: probably should be 'to viewer's overriden skeleton'
glm::mat4 original_bind_matrix = glm::inverse(skin.mInverseBindMatricesData[i]);
glm::mat4 rotated_original = coord_system_rotation * original_bind_matrix;
- glm::mat4 skeleton_transform = computeGltfToViewerSkeletonTransform(skin, i, legal_name);
+ glm::mat4 skeleton_transform = computeGltfToViewerSkeletonTransform(gltf_rest_map, joint, legal_name);
glm::mat4 tranlated_original = skeleton_transform * rotated_original;
glm::mat4 final_inverse_bind_matrix = glm::inverse(tranlated_original);
LLMatrix4 gltf_transform = LLMatrix4(glm::value_ptr(final_inverse_bind_matrix));
-
- LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " val: " << gltf_transform << LL_ENDL;
+ LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " Translated val: " << gltf_transform << LL_ENDL;
mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform));
}
else
{
+ // If bind matrices aren't present (they are optional in gltf),
+ // assume an identy matrix
+ // todo: find a model with this, might need to use rotated matrix
glm::mat4 inv_bind(1.0f);
- glm::mat4 skeleton_transform = computeGltfToViewerSkeletonTransform(skin, i, legal_name);
+ glm::mat4 skeleton_transform = computeGltfToViewerSkeletonTransform(gltf_rest_map, joint, legal_name);
inv_bind = glm::inverse(skeleton_transform * inv_bind);
LLMatrix4 gltf_transform = LLMatrix4(glm::value_ptr(inv_bind));
- gltf_transform.setIdentity();
- LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " val: " << gltf_transform << LL_ENDL;
+ LL_INFOS("GLTF_DEBUG") << "mInvBindMatrix name: " << legal_name << " Generated val: " << gltf_transform << LL_ENDL;
mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform));
}
- // Todo: this seems blatantly wrong
- glm::mat4 joint_mat = jointNode.mMatrix;
- S32 root_joint = findValidRootJointNode(joint, skin); // skeleton can have multiple real roots and one gltf root to group them
- if (root_joint == joint)
+ // Compute Alternative matrices also known as overrides
+
+ glm::mat4 joint_mat = glm::mat4(1.f);
+ if (legal_joint)
{
- // This is very likely incomplete in some way.
- joint_mat = coord_system_rotation;
- if (mApplyXYRotation)
+ joint_viewer_parent_map_t::const_iterator found = mJointViewerParentMap.find(legal_name);
+ if (found != mJointViewerParentMap.end() && !found->second.empty())
{
- joint_mat = coord_system_rotationxy * joint_mat;
+ glm::mat4 gltf_joint_rest_pose = coord_system_rotation * buildGltfRestMatrix(joint, skin);
+ if (mApplyXYRotation)
+ {
+ gltf_joint_rest_pose = coord_system_rotationxy * gltf_joint_rest_pose;
+ }
+ // Compute viewer's override by moving joint to viewer's base
+ // This might be overused or somewhat incorect for regular cases
+ // But this logic should be solid for cases where model lacks
+ // parent joints that viewer has.
+ // ex: like boots that have only knees and feet, but no pelvis,
+ // or anything else, in which case we take viewer's pelvis
+ glm::mat4 viewer_rest = mJointViewerRestMatrices[found->second];
+ joint_mat = glm::inverse(viewer_rest) * gltf_joint_rest_pose;
}
}
LLMatrix4 original_joint_transform(glm::value_ptr(joint_mat));
+ // Viewer seems to care only about translation part,
+ // but for parity with collada taking original value
+ LLMatrix4 newInverse = LLMatrix4(mInverseBindMatrices[skin_idx].back().getF32ptr());
+ newInverse.setTranslation(original_joint_transform.getTranslation());
+
LL_INFOS("GLTF_DEBUG") << "mAlternateBindMatrix name: " << legal_name << " val: " << original_joint_transform << LL_ENDL;
mAlternateBindMatrices[skin_idx].push_back(LLMatrix4a(original_joint_transform));
- if (!legal_joint)
- {
- LL_DEBUGS("GLTF") << "Ignoring unrecognized joint: " << legal_name << LL_ENDL;
- continue;
- }
-
- // Debug: Log original joint matrix
- glm::mat4 gltf_joint_matrix = jointNode.mMatrix;
- LL_INFOS("GLTF_DEBUG") << "Joint '" << legal_name << "' original matrix:" << LL_ENDL;
- for(int i = 0; i < 4; i++)
- {
- LL_INFOS("GLTF_DEBUG") << " [" << gltf_joint_matrix[i][0] << ", " << gltf_joint_matrix[i][1]
- << ", " << gltf_joint_matrix[i][2] << ", " << gltf_joint_matrix[i][3] << "]" << LL_ENDL;
- }
-
- // Apply coordinate system rotation to joint transform
- glm::mat4 rotated_joint_matrix = coord_system_rotation * gltf_joint_matrix;
-
- // Debug: Log rotated joint matrix
- LL_INFOS("GLTF_DEBUG") << "Joint '" << legal_name << "' rotated matrix:" << LL_ENDL;
- for(int i = 0; i < 4; i++)
+ if (legal_joint)
{
- LL_INFOS("GLTF_DEBUG") << " [" << rotated_joint_matrix[i][0] << ", " << rotated_joint_matrix[i][1]
- << ", " << rotated_joint_matrix[i][2] << ", " << rotated_joint_matrix[i][3] << "]" << LL_ENDL;
+ // Might be needed for uploader UI to correctly identify overriden joints
+ // but going to be incorrect if multiple skins are present
+ mJointList[legal_name] = newInverse;
+ mJointsFromNode.push_front(legal_name);
}
-
- LLMatrix4 gltf_transform = LLMatrix4(glm::value_ptr(rotated_joint_matrix));
- mJointList[legal_name] = gltf_transform;
- mJointsFromNode.push_front(legal_name);
-
- LL_INFOS("GLTF_DEBUG") << "mJointList name: " << legal_name << " val: " << gltf_transform << LL_ENDL;
}
}
@@ -1164,10 +1174,11 @@ glm::mat4 LLGLTFLoader::buildGltfRestMatrix(S32 joint_node_index, const LL::GLTF
// This function computes the transformation matrix needed to convert from GLTF skeleton space
// to viewer skeleton space for a specific joint
-glm::mat4 LLGLTFLoader::computeGltfToViewerSkeletonTransform(const LL::GLTF::Skin& gltf_skin, S32 gltf_joint_index, const std::string& joint_name) const
+
+glm::mat4 LLGLTFLoader::computeGltfToViewerSkeletonTransform(const joint_node_mat4_map_t& gltf_rest_map, S32 gltf_node_index, const std::string& joint_name) const
{
- joint_rest_map_t::const_iterator found = mJointRestMatrices.find(joint_name);
- if (found == mJointRestMatrices.end())
+ joint_viewer_rest_map_t::const_iterator found = mJointViewerRestMatrices.find(joint_name);
+ if (found == mJointViewerRestMatrices.end())
{
// For now assume they are identical and return an identity (for ease of debuging)
// But there should be no joints viewer isn't aware about
@@ -1177,19 +1188,18 @@ glm::mat4 LLGLTFLoader::computeGltfToViewerSkeletonTransform(const LL::GLTF::Ski
glm::mat4 viewer_joint_rest_pose = found->second;
// Get the GLTF joint's rest pose (in GLTF coordinate system)
- S32 joint_node_index = gltf_skin.mJoints[gltf_joint_index];
- glm::mat4 gltf_joint_rest_pose = buildGltfRestMatrix(joint_node_index, gltf_skin);
- gltf_joint_rest_pose = coord_system_rotation * gltf_joint_rest_pose;
+ const glm::mat4 &gltf_joint_rest_pose = gltf_rest_map.at(gltf_node_index);
+ glm::mat4 rest_pose = coord_system_rotation * gltf_joint_rest_pose;
LL_INFOS("GLTF_DEBUG") << "rest matrix for joint " << joint_name << ": ";
- LLMatrix4 transform(glm::value_ptr(gltf_joint_rest_pose));
+ LLMatrix4 transform(glm::value_ptr(rest_pose));
LL_CONT << transform << LL_ENDL;
// Compute transformation from GLTF space to viewer space
// This assumes both skeletons are in rest pose initially
- return viewer_joint_rest_pose * glm::inverse(gltf_joint_rest_pose);
+ return viewer_joint_rest_pose * glm::inverse(rest_pose);
}
bool LLGLTFLoader::checkForXYrotation(const LL::GLTF::Skin& gltf_skin, S32 joint_idx, S32 bind_indx)
diff --git a/indra/newview/gltf/llgltfloader.h b/indra/newview/gltf/llgltfloader.h
index 6009a8e0c7..bf5f830d47 100644
--- a/indra/newview/gltf/llgltfloader.h
+++ b/indra/newview/gltf/llgltfloader.h
@@ -121,7 +121,9 @@ class LLGLTFLoader : public LLModelLoader
{
public:
typedef std::map<std::string, LLImportMaterial> material_map;
- typedef std::map<std::string, glm::mat4> joint_rest_map_t;
+ typedef std::map<std::string, std::string> joint_viewer_parent_map_t;
+ typedef std::map<std::string, glm::mat4> joint_viewer_rest_map_t;
+ typedef std::map<S32, glm::mat4> joint_node_mat4_map_t;
LLGLTFLoader(std::string filename,
S32 lod,
@@ -135,7 +137,8 @@ class LLGLTFLoader : public LLModelLoader
std::map<std::string, std::string> &jointAliasMap,
U32 maxJointsPerMesh,
U32 modelLimit,
- joint_rest_map_t jointRestMatrices); //,
+ joint_viewer_rest_map_t jointRestMatrices,
+ joint_viewer_parent_map_t jointParentPap); //,
//bool preprocess );
virtual ~LLGLTFLoader();
@@ -169,7 +172,8 @@ protected:
// GLTF isn't aware of viewer's skeleton and uses it's own,
// so need to take viewer's joints and use them to
// recalculate iverse bind matrices
- joint_rest_map_t mJointRestMatrices;
+ joint_viewer_rest_map_t mJointViewerRestMatrices;
+ joint_viewer_parent_map_t mJointViewerParentMap;
// vector of vectors because of a posibility of having more than one skin
typedef std::vector<LLMeshSkinInfo::matrix_list_t> bind_matrices_t;
@@ -191,7 +195,7 @@ private:
S32 findGLTFRootJointNode(const LL::GLTF::Skin& gltf_skin) const; // if there are multiple roots, gltf stores them under one commor joint
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;
+ glm::mat4 computeGltfToViewerSkeletonTransform(const joint_node_mat4_map_t &gltf_rest_map, S32 gltf_node_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);
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 40b6d186b8..d6b438a6e2 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -811,7 +811,9 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
else
{
LLVOAvatar* av = getPreviewAvatar();
- LLAvatarAppearance::joint_rest_map_t rest_pose = av->getJointRestMatrices();
+ LLAvatarAppearance::joint_rest_map_t rest_pose;
+ LLAvatarAppearance::joint_parent_map_t rest_parent_map;
+ av->getJointRestMatrices(rest_pose, rest_parent_map);
mModelLoader = new LLGLTFLoader(
filename,
lod,
@@ -825,7 +827,8 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
joint_alias_map,
LLSkinningUtil::getMaxJointCount(),
gSavedSettings.getU32("ImporterModelLimit"),
- rest_pose);
+ rest_pose,
+ rest_parent_map);
}
if (force_disable_slm)