#4148 Skeleton Translation
parent
6924862d2e
commit
b20d10c0cc
|
|
@ -34,11 +34,11 @@
|
|||
#include "llpolymorph.h"
|
||||
#include "llpolymesh.h"
|
||||
#include "llpolyskeletaldistortion.h"
|
||||
#include "llstl.h"
|
||||
#include "lltexglobalcolor.h"
|
||||
#include "llwearabledata.h"
|
||||
#include "boost/bind.hpp"
|
||||
#include "boost/tokenizer.hpp"
|
||||
#include "v4math.h"
|
||||
|
||||
using namespace LLAvatarAppearanceDefines;
|
||||
|
||||
|
|
@ -71,6 +71,7 @@ public:
|
|||
mChildren.clear();
|
||||
}
|
||||
bool parseXml(LLXmlTreeNode* node);
|
||||
glm::mat4 getJointMatrix();
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
|
|
@ -105,11 +106,14 @@ public:
|
|||
S32 getNumBones() const { return mNumBones; }
|
||||
S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; }
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
S32 mNumBones;
|
||||
S32 mNumCollisionVolumes;
|
||||
LLAvatarAppearance::joint_alias_map_t mJointAliasMap;
|
||||
typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t;
|
||||
bone_info_list_t mBoneInfoList;
|
||||
};
|
||||
|
||||
|
|
@ -1623,6 +1627,21 @@ bool LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
glm::mat4 LLAvatarBoneInfo::getJointMatrix()
|
||||
{
|
||||
glm::mat4 mat(1.0f);
|
||||
// 1. Scaling
|
||||
mat = glm::scale(mat, glm::vec3(mScale[0], mScale[1], mScale[2]));
|
||||
// 2. Rotation (Euler angles rad)
|
||||
mat = glm::rotate(mat, mRot[0], glm::vec3(1, 0, 0));
|
||||
mat = glm::rotate(mat, mRot[1], glm::vec3(0, 1, 0));
|
||||
mat = glm::rotate(mat, mRot[2], glm::vec3(0, 0, 1));
|
||||
// 3. Position
|
||||
mat = glm::translate(mat, glm::vec3(mPos[0], mPos[1], mPos[2]));
|
||||
return mat;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLAvatarSkeletonInfo::parseXml()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -1653,6 +1672,22 @@ bool LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
|
|||
return true;
|
||||
}
|
||||
|
||||
void LLAvatarSkeletonInfo::getJointRestMatrices(
|
||||
const bone_info_list_t& bone_list,
|
||||
LLAvatarAppearance::joint_rest_map_t& result,
|
||||
const glm::mat4& parent_mat)
|
||||
{
|
||||
for (LLAvatarBoneInfo* bone_info : bone_list)
|
||||
{
|
||||
if (bone_info->mIsJoint)
|
||||
{
|
||||
glm::mat4 rest_mat = parent_mat * bone_info->getJointMatrix();
|
||||
result[bone_info->mName] = rest_mat;
|
||||
getJointRestMatrices(bone_info->mChildren, result, rest_mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Make aliases for joint and push to map.
|
||||
void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info)
|
||||
{
|
||||
|
|
@ -1714,6 +1749,14 @@ const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases
|
|||
return mJointAliasMap;
|
||||
}
|
||||
|
||||
LLAvatarAppearance::joint_rest_map_t LLAvatarAppearance:: getJointRestMatrices() const
|
||||
{
|
||||
LLAvatarAppearance::joint_rest_map_t result;
|
||||
glm::mat4 identity(1.f);
|
||||
LLAvatarSkeletonInfo::getJointRestMatrices(sAvatarSkeletonInfo->mBoneInfoList, result, identity);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "lltexlayer.h"
|
||||
#include "llviewervisualparam.h"
|
||||
#include "llxmltree.h"
|
||||
#include "v4math.h"
|
||||
|
||||
class LLTexLayerSet;
|
||||
class LLTexGlobalColor;
|
||||
|
|
@ -153,7 +154,8 @@ 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, glm::mat4> joint_rest_map_t;
|
||||
joint_rest_map_t getJointRestMatrices() const;
|
||||
|
||||
protected:
|
||||
static bool parseSkeletonFile(const std::string& filename, LLXmlTree& skeleton_xml_tree);
|
||||
|
|
|
|||
|
|
@ -87,7 +87,8 @@ LLGLTFLoader::LLGLTFLoader(std::string filename,
|
|||
JointNameSet & jointsFromNodes,
|
||||
std::map<std::string, std::string> &jointAliasMap,
|
||||
U32 maxJointsPerMesh,
|
||||
U32 modelLimit) //,
|
||||
U32 modelLimit,
|
||||
joint_rest_map_t jointRestMatrices) //,
|
||||
//bool preprocess)
|
||||
: LLModelLoader( filename,
|
||||
lod,
|
||||
|
|
@ -103,7 +104,8 @@ LLGLTFLoader::LLGLTFLoader(std::string filename,
|
|||
//mPreprocessGLTF(preprocess),
|
||||
mMeshesLoaded(false),
|
||||
mMaterialsLoaded(false),
|
||||
mGeneratedModelLimit(modelLimit)
|
||||
mGeneratedModelLimit(modelLimit),
|
||||
mJointRestMatrices(jointRestMatrices)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -917,20 +919,24 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
|
|||
}
|
||||
else if (inverse_count > i)
|
||||
{
|
||||
LL::GLTF::mat4 gltf_mat = skin.mInverseBindMatricesData[i];
|
||||
|
||||
// Todo: there should be a simpler way
|
||||
glm::mat4 original_bind_matrix = glm::inverse(gltf_mat);
|
||||
glm::mat4 original_bind_matrix = glm::inverse(skin.mInverseBindMatricesData[i]);
|
||||
glm::mat4 rotated_original = coord_system_rotation * original_bind_matrix;
|
||||
glm::mat4 rotated_inverse_bind_matrix = glm::inverse(rotated_original);
|
||||
LLMatrix4 gltf_transform = LLMatrix4(glm::value_ptr(rotated_inverse_bind_matrix));
|
||||
glm::mat4 skeleton_transform = computeGltfToViewerSkeletonTransform(skin, i, 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;
|
||||
mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform));
|
||||
}
|
||||
else
|
||||
{
|
||||
LLMatrix4 gltf_transform;
|
||||
glm::mat4 inv_bind(1.0f);
|
||||
glm::mat4 skeleton_transform = computeGltfToViewerSkeletonTransform(skin, i, 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;
|
||||
mInverseBindMatrices[skin_idx].push_back(LLMatrix4a(gltf_transform));
|
||||
|
|
@ -1074,6 +1080,69 @@ S32 LLGLTFLoader::findParentNode(S32 node) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
glm::mat4 LLGLTFLoader::buildGltfRestMatrix(S32 joint_node_index, const LL::GLTF::Skin& gltf_skin) const
|
||||
{
|
||||
// This is inefficient since we are recalculating some joints multiple times over
|
||||
// Todo: cache it?
|
||||
|
||||
if (joint_node_index < 0 || joint_node_index >= static_cast<S32>(mGLTFAsset.mNodes.size()))
|
||||
{
|
||||
return glm::mat4(1.0f);
|
||||
}
|
||||
|
||||
const auto& node = mGLTFAsset.mNodes[joint_node_index];
|
||||
|
||||
// Find and apply parent transform if it exists
|
||||
for (size_t i = 0; i < mGLTFAsset.mNodes.size(); ++i)
|
||||
{
|
||||
const auto& potential_parent = mGLTFAsset.mNodes[i];
|
||||
auto it = std::find(potential_parent.mChildren.begin(), potential_parent.mChildren.end(), joint_node_index);
|
||||
|
||||
if (it != potential_parent.mChildren.end())
|
||||
{
|
||||
// Found parent
|
||||
if (std::find(gltf_skin.mJoints.begin(), gltf_skin.mJoints.end(), joint_node_index) != gltf_skin.mJoints.end())
|
||||
{
|
||||
// parent is a joint - recursively combine transform
|
||||
// assumes that matrix is already valid
|
||||
return buildGltfRestMatrix(static_cast<S32>(i), gltf_skin) * node.mMatrix;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Should we return armature or stop earlier?
|
||||
return node.mMatrix;
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
joint_rest_map_t::const_iterator found = mJointRestMatrices.find(joint_name);
|
||||
if (found == mJointRestMatrices.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
|
||||
// Warn or assert about missing joints
|
||||
return glm::mat4(1.0f);
|
||||
}
|
||||
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;
|
||||
|
||||
LL_INFOS("GLTF_DEBUG") << "rest matrix for joint " << joint_name << ": ";
|
||||
|
||||
LLMatrix4 transform(glm::value_ptr(gltf_joint_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);
|
||||
}
|
||||
|
||||
bool LLGLTFLoader::parseMaterials()
|
||||
{
|
||||
if (!mGltfLoaded) return false;
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ class LLGLTFLoader : public LLModelLoader
|
|||
{
|
||||
public:
|
||||
typedef std::map<std::string, LLImportMaterial> material_map;
|
||||
typedef std::map<std::string, LLVector3> joint_pos_map_t;
|
||||
typedef std::map<std::string, glm::mat4> joint_rest_map_t;
|
||||
|
||||
LLGLTFLoader(std::string filename,
|
||||
S32 lod,
|
||||
|
|
@ -134,7 +134,8 @@ class LLGLTFLoader : public LLModelLoader
|
|||
JointNameSet & jointsFromNodes,
|
||||
std::map<std::string, std::string> &jointAliasMap,
|
||||
U32 maxJointsPerMesh,
|
||||
U32 modelLimit); //,
|
||||
U32 modelLimit,
|
||||
joint_rest_map_t jointRestMatrices); //,
|
||||
//bool preprocess );
|
||||
virtual ~LLGLTFLoader();
|
||||
|
||||
|
|
@ -164,6 +165,10 @@ protected:
|
|||
std::vector<gltf_image> mImages;
|
||||
std::vector<gltf_sampler> mSamplers;
|
||||
|
||||
// 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;
|
||||
|
||||
// vector of vectors because of a posibility of having more than one skin
|
||||
typedef std::vector<LLMeshSkinInfo::matrix_list_t> bind_matrices_t;
|
||||
|
|
@ -183,6 +188,8 @@ private:
|
|||
S32 findValidRootJointNode(S32 source_joint_node, const LL::GLTF::Skin& gltf_skin) const;
|
||||
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;
|
||||
LLUUID imageBufferToTextureUUID(const gltf_texture& tex);
|
||||
|
||||
void notifyUnsupportedExtension(bool unsupported);
|
||||
|
|
|
|||
|
|
@ -810,6 +810,8 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
|
|||
}
|
||||
else
|
||||
{
|
||||
LLVOAvatar* av = getPreviewAvatar();
|
||||
LLAvatarAppearance::joint_rest_map_t rest_pose = av->getJointRestMatrices();
|
||||
mModelLoader = new LLGLTFLoader(
|
||||
filename,
|
||||
lod,
|
||||
|
|
@ -822,7 +824,8 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
|
|||
mJointsFromNode,
|
||||
joint_alias_map,
|
||||
LLSkinningUtil::getMaxJointCount(),
|
||||
gSavedSettings.getU32("ImporterModelLimit"));
|
||||
gSavedSettings.getU32("ImporterModelLimit"),
|
||||
rest_pose);
|
||||
}
|
||||
|
||||
if (force_disable_slm)
|
||||
|
|
|
|||
Loading…
Reference in New Issue