#4142 Joint grouping and stripping
Viewer only supports 110 joints at a time, when model has more bones than that importer has to strip some, use groups for stripping.master
parent
4a40eaa87f
commit
8c9d0c6145
|
|
@ -78,6 +78,7 @@ private:
|
||||||
std::string mName;
|
std::string mName;
|
||||||
std::string mSupport;
|
std::string mSupport;
|
||||||
std::string mAliases;
|
std::string mAliases;
|
||||||
|
std::string mGroup;
|
||||||
bool mIsJoint;
|
bool mIsJoint;
|
||||||
LLVector3 mPos;
|
LLVector3 mPos;
|
||||||
LLVector3 mEnd;
|
LLVector3 mEnd;
|
||||||
|
|
@ -1606,6 +1607,15 @@ bool LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
|
||||||
mSupport = "base";
|
mSupport = "base";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skeleton has 133 bones, but shader only allows 110 (LL_MAX_JOINTS_PER_MESH_OBJECT)
|
||||||
|
// Groups can be used by importer to cut out unused groups of joints
|
||||||
|
static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group");
|
||||||
|
if (!node->getFastAttributeString(group_string, mGroup))
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Bone without group " << mName << LL_ENDL;
|
||||||
|
mGroup = "global";
|
||||||
|
}
|
||||||
|
|
||||||
if (mIsJoint)
|
if (mIsJoint)
|
||||||
{
|
{
|
||||||
static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
|
static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
|
||||||
|
|
@ -1687,6 +1697,7 @@ void LLAvatarSkeletonInfo::getJointMatricesAndHierarhy(
|
||||||
data.mRotation = bone_info->mRot;
|
data.mRotation = bone_info->mRot;
|
||||||
data.mRestMatrix = parent_mat * data.mJointMatrix;
|
data.mRestMatrix = parent_mat * data.mJointMatrix;
|
||||||
data.mIsJoint = bone_info->mIsJoint;
|
data.mIsJoint = bone_info->mIsJoint;
|
||||||
|
data.mGroup = bone_info->mGroup;
|
||||||
for (LLAvatarBoneInfo* child_info : bone_info->mChildren)
|
for (LLAvatarBoneInfo* child_info : bone_info->mChildren)
|
||||||
{
|
{
|
||||||
LLJointData& child_data = data.mChildren.emplace_back();
|
LLJointData& child_data = data.mChildren.emplace_back();
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ class LLJointData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::string mName;
|
std::string mName;
|
||||||
|
std::string mGroup;
|
||||||
glm::mat4 mJointMatrix;
|
glm::mat4 mJointMatrix;
|
||||||
glm::mat4 mRestMatrix;
|
glm::mat4 mRestMatrix;
|
||||||
glm::vec3 mScale;
|
glm::vec3 mScale;
|
||||||
|
|
|
||||||
|
|
@ -258,13 +258,14 @@ bool LLGLTFLoader::parseMeshes()
|
||||||
if (mGLTFAsset.mSkins.size() > 0)
|
if (mGLTFAsset.mSkins.size() > 0)
|
||||||
{
|
{
|
||||||
checkForXYrotation(mGLTFAsset.mSkins[0]);
|
checkForXYrotation(mGLTFAsset.mSkins[0]);
|
||||||
|
populateJointGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate the joints from skins first.
|
// Populate the joints from skins first.
|
||||||
// There's not many skins - and you can pretty easily iterate through the nodes from that.
|
// 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++)
|
for (S32 i = 0; i < mGLTFAsset.mSkins.size(); i++)
|
||||||
{
|
{
|
||||||
populateJointFromSkin(i);
|
populateJointsFromSkin(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track how many times each mesh name has been used
|
// Track how many times each mesh name has been used
|
||||||
|
|
@ -463,6 +464,24 @@ void LLGLTFLoader::computeCombinedNodeTransform(const LL::GLTF::Asset& asset, S3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LLGLTFLoader::addJointToModelSkin(LLMeshSkinInfo& skin_info, S32 gltf_skin_idx, size_t gltf_joint_idx) const
|
||||||
|
{
|
||||||
|
const std::string& legal_name = mJointNames[gltf_skin_idx][gltf_joint_idx];
|
||||||
|
if (legal_name.empty())
|
||||||
|
{
|
||||||
|
llassert(false); // should have been stopped by gltf_joint_index_use[i] == -1
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
skin_info.mJointNames.push_back(legal_name);
|
||||||
|
skin_info.mJointNums.push_back(-1);
|
||||||
|
|
||||||
|
// In scope of same skin multiple meshes reuse same bind matrices
|
||||||
|
skin_info.mInvBindMatrix.push_back(mInverseBindMatrices[gltf_skin_idx][gltf_joint_idx]);
|
||||||
|
skin_info.mAlternateBindMatrix.push_back(mAlternateBindMatrices[gltf_skin_idx][gltf_joint_idx]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& mesh, const LL::GLTF::Node& nodeno, material_map& mats, S32 instance_count)
|
bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh& mesh, const LL::GLTF::Node& nodeno, material_map& mats, S32 instance_count)
|
||||||
{
|
{
|
||||||
// Set the requested label for the floater display and uploading
|
// Set the requested label for the floater display and uploading
|
||||||
|
|
@ -519,15 +538,9 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
|
||||||
size_t jointCnt = gltf_skin.mJoints.size();
|
size_t jointCnt = gltf_skin.mJoints.size();
|
||||||
gltf_joint_index_use.resize(jointCnt);
|
gltf_joint_index_use.resize(jointCnt);
|
||||||
|
|
||||||
S32 replacement_index = 0;
|
|
||||||
for (size_t i = 0; i < jointCnt; ++i)
|
for (size_t i = 0; i < jointCnt; ++i)
|
||||||
{
|
{
|
||||||
// Process joint name and idnex
|
if (mJointNames[i].empty())
|
||||||
S32 joint = gltf_skin.mJoints[i];
|
|
||||||
LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint];
|
|
||||||
|
|
||||||
std::string legal_name(jointNode.mName);
|
|
||||||
if (mJointMap.find(legal_name) == mJointMap.end())
|
|
||||||
{
|
{
|
||||||
// This might need to hold a substitute index
|
// This might need to hold a substitute index
|
||||||
gltf_joint_index_use[i] = -1; // mark as unsupported
|
gltf_joint_index_use[i] = -1; // mark as unsupported
|
||||||
|
|
@ -959,65 +972,106 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
|
||||||
// Call normalizeVolumeFacesAndWeights to compute proper extents
|
// Call normalizeVolumeFacesAndWeights to compute proper extents
|
||||||
pModel->normalizeVolumeFacesAndWeights();
|
pModel->normalizeVolumeFacesAndWeights();
|
||||||
|
|
||||||
// Fill joint names, bind matrices and prepare to remap weight indices
|
// Fill joint names, bind matrices and remap weight indices
|
||||||
if (skinIdx >= 0)
|
if (skinIdx >= 0)
|
||||||
{
|
{
|
||||||
LL::GLTF::Skin& gltf_skin = mGLTFAsset.mSkins[skinIdx];
|
LL::GLTF::Skin& gltf_skin = mGLTFAsset.mSkins[skinIdx];
|
||||||
LLMeshSkinInfo& skin_info = pModel->mSkinInfo;
|
LLMeshSkinInfo& skin_info = pModel->mSkinInfo;
|
||||||
S32 valid_joints_count = mValidJointsCount[skinIdx];
|
S32 valid_joints_count = mValidJointsCount[skinIdx];
|
||||||
|
|
||||||
|
S32 replacement_index = 0;
|
||||||
std::vector<S32> gltfindex_to_joitindex_map;
|
std::vector<S32> gltfindex_to_joitindex_map;
|
||||||
size_t jointCnt = gltf_skin.mJoints.size();
|
size_t jointCnt = gltf_skin.mJoints.size();
|
||||||
gltfindex_to_joitindex_map.resize(jointCnt);
|
gltfindex_to_joitindex_map.resize(jointCnt);
|
||||||
|
|
||||||
S32 replacement_index = 0;
|
if (valid_joints_count > LL_MAX_JOINTS_PER_MESH_OBJECT)
|
||||||
S32 stripped_valid_joints = 0;
|
|
||||||
for (size_t i = 0; i < jointCnt; ++i)
|
|
||||||
{
|
{
|
||||||
// Process joint name and idnex
|
std::map<std::string, S32> goup_use_count;
|
||||||
S32 joint = gltf_skin.mJoints[i];
|
// Assume that 'Torso' group is always in use since that's what everything else is attached to
|
||||||
if (gltf_joint_index_use[i] < 0)
|
goup_use_count["Torso"] = 1;
|
||||||
{
|
// Note that Collisions and Extra groups are all over the place, might want to include them from the start
|
||||||
// unsupported (-1) joint, drop it
|
// or add individual when parents are added
|
||||||
continue;
|
|
||||||
}
|
|
||||||
LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint];
|
|
||||||
|
|
||||||
std::string legal_name(jointNode.mName);
|
// Check which groups are in use
|
||||||
if (mJointMap.find(legal_name) != mJointMap.end())
|
for (size_t i = 0; i < jointCnt; ++i)
|
||||||
{
|
{
|
||||||
legal_name = mJointMap[legal_name];
|
std::string& joint_name = mJointNames[skinIdx][i];
|
||||||
}
|
if (!joint_name.empty())
|
||||||
else
|
{
|
||||||
{
|
if (gltf_joint_index_use[i] > 0)
|
||||||
llassert(false); // should have been stopped by gltf_joint_index_use[i] == -1
|
{
|
||||||
continue;
|
const JointGroups &group = mJointGroups[joint_name];
|
||||||
|
// Joint in use, increment it's groups
|
||||||
|
goup_use_count[group.mGroup]++;
|
||||||
|
goup_use_count[group.mParentGroup]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid_joints_count > LL_MAX_JOINTS_PER_MESH_OBJECT
|
// 1. add joints that are in use directly
|
||||||
&& gltf_joint_index_use[i] == 0
|
for (size_t i = 0; i < jointCnt; ++i)
|
||||||
&& legal_name != "mPelvis")
|
|
||||||
{
|
{
|
||||||
// Unused (0) joint
|
// Process joint name and idnex
|
||||||
// It's perfectly valid to have more joints than is in use
|
S32 joint = gltf_skin.mJoints[i];
|
||||||
// Ex: sandals that make your legs digitigrade despite not skining to
|
if (gltf_joint_index_use[i] <= 0)
|
||||||
// knees or the like.
|
{
|
||||||
// But if model is over limid, drop extras sans pelvis.
|
// unsupported (-1) joint, drop it
|
||||||
// Keeping 'pelvis' is a workaround to keep preview whole.
|
// unused (0) joint, drop it
|
||||||
// Todo: consider improving this, either take as much as possible or
|
continue;
|
||||||
// ensure common parents/roots are included
|
}
|
||||||
continue;
|
|
||||||
|
if (addJointToModelSkin(skin_info, skinIdx, i))
|
||||||
|
{
|
||||||
|
gltfindex_to_joitindex_map[i] = replacement_index++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gltfindex_to_joitindex_map[i] = replacement_index++;
|
// 2. add joints from groups that this model's joints belong to
|
||||||
|
// It's perfectly valid to have more joints than is in use
|
||||||
|
// Ex: sandals that make your legs digitigrade despite not skining to
|
||||||
|
// knees or the like.
|
||||||
|
// Todo: sort and add by usecount
|
||||||
|
for (size_t i = 0; i < jointCnt; ++i)
|
||||||
|
{
|
||||||
|
S32 joint = gltf_skin.mJoints[i];
|
||||||
|
if (gltf_joint_index_use[i] != 0)
|
||||||
|
{
|
||||||
|
// this step needs only joints that have zero uses
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (skin_info.mInvBindMatrix.size() > LL_MAX_JOINTS_PER_MESH_OBJECT)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const std::string& legal_name = mJointNames[skinIdx][i];
|
||||||
|
std::string group_name = mJointGroups[legal_name].mGroup;
|
||||||
|
if (goup_use_count[group_name] > 0)
|
||||||
|
{
|
||||||
|
if (addJointToModelSkin(skin_info, skinIdx, i))
|
||||||
|
{
|
||||||
|
gltfindex_to_joitindex_map[i] = replacement_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Less than 110, just add every valid joint
|
||||||
|
for (size_t i = 0; i < jointCnt; ++i)
|
||||||
|
{
|
||||||
|
// Process joint name and idnex
|
||||||
|
S32 joint = gltf_skin.mJoints[i];
|
||||||
|
if (gltf_joint_index_use[i] < 0)
|
||||||
|
{
|
||||||
|
// unsupported (-1) joint, drop it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
skin_info.mJointNames.push_back(legal_name);
|
if (addJointToModelSkin(skin_info, skinIdx, i))
|
||||||
skin_info.mJointNums.push_back(-1);
|
{
|
||||||
|
gltfindex_to_joitindex_map[i] = replacement_index++;
|
||||||
// In scope of same skin multiple meshes reuse same bind matrices
|
}
|
||||||
skin_info.mInvBindMatrix.push_back(mInverseBindMatrices[skinIdx][i]);
|
}
|
||||||
|
|
||||||
skin_info.mAlternateBindMatrix.push_back(mAlternateBindMatrices[skinIdx][i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skin_info.mInvBindMatrix.size() > LL_MAX_JOINTS_PER_MESH_OBJECT)
|
if (skin_info.mInvBindMatrix.size() > LL_MAX_JOINTS_PER_MESH_OBJECT)
|
||||||
|
|
@ -1046,7 +1100,7 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
|
void LLGLTFLoader::populateJointsFromSkin(S32 skin_idx)
|
||||||
{
|
{
|
||||||
const LL::GLTF::Skin& skin = mGLTFAsset.mSkins[skin_idx];
|
const LL::GLTF::Skin& skin = mGLTFAsset.mSkins[skin_idx];
|
||||||
|
|
||||||
|
|
@ -1066,6 +1120,7 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
|
||||||
{
|
{
|
||||||
mInverseBindMatrices.resize(skin_idx + 1);
|
mInverseBindMatrices.resize(skin_idx + 1);
|
||||||
mAlternateBindMatrices.resize(skin_idx + 1);
|
mAlternateBindMatrices.resize(skin_idx + 1);
|
||||||
|
mJointNames.resize(skin_idx + 1);
|
||||||
mValidJointsCount.resize(skin_idx + 1, 0);
|
mValidJointsCount.resize(skin_idx + 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1135,6 +1190,11 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
|
||||||
{
|
{
|
||||||
legal_name = mJointMap[legal_name];
|
legal_name = mJointMap[legal_name];
|
||||||
legal_joint = true;
|
legal_joint = true;
|
||||||
|
mJointNames[skin_idx].push_back(legal_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mJointNames[skin_idx].emplace_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute bind matrices
|
// Compute bind matrices
|
||||||
|
|
@ -1196,6 +1256,15 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLGLTFLoader::populateJointGroups()
|
||||||
|
{
|
||||||
|
std::string parent;
|
||||||
|
for (auto& viewer_data : mViewerJointData)
|
||||||
|
{
|
||||||
|
buildJointGroup(viewer_data, parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
S32 LLGLTFLoader::findClosestValidJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const
|
S32 LLGLTFLoader::findClosestValidJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const
|
||||||
{
|
{
|
||||||
|
|
@ -1299,6 +1368,18 @@ S32 LLGLTFLoader::findParentNode(S32 node) const
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LLGLTFLoader::buildJointGroup(LLJointData& viewer_data, const std::string &parent_group)
|
||||||
|
{
|
||||||
|
JointGroups& jount_group_data = mJointGroups[viewer_data.mName];
|
||||||
|
jount_group_data.mGroup = viewer_data.mGroup;
|
||||||
|
jount_group_data.mParentGroup = parent_group;
|
||||||
|
|
||||||
|
for (LLJointData& child_data : viewer_data.mChildren)
|
||||||
|
{
|
||||||
|
buildJointGroup(child_data, viewer_data.mGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LLGLTFLoader::buildOverrideMatrix(LLJointData& viewer_data, joints_data_map_t &gltf_nodes, joints_name_to_node_map_t &names_to_nodes, glm::mat4& parent_rest, glm::mat4& parent_support_rest) const
|
void LLGLTFLoader::buildOverrideMatrix(LLJointData& viewer_data, joints_data_map_t &gltf_nodes, joints_name_to_node_map_t &names_to_nodes, glm::mat4& parent_rest, glm::mat4& parent_support_rest) const
|
||||||
{
|
{
|
||||||
glm::mat4 new_lefover(1.f);
|
glm::mat4 new_lefover(1.f);
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,20 @@ protected:
|
||||||
|
|
||||||
// vector of vectors because of a posibility of having more than one skin
|
// vector of vectors because of a posibility of having more than one skin
|
||||||
typedef std::vector<LLMeshSkinInfo::matrix_list_t> bind_matrices_t;
|
typedef std::vector<LLMeshSkinInfo::matrix_list_t> bind_matrices_t;
|
||||||
|
typedef std::vector<std::vector<std::string> > joint_names_t;
|
||||||
bind_matrices_t mInverseBindMatrices;
|
bind_matrices_t mInverseBindMatrices;
|
||||||
bind_matrices_t mAlternateBindMatrices;
|
bind_matrices_t mAlternateBindMatrices;
|
||||||
|
joint_names_t mJointNames; // empty string when no legal name for a given idx
|
||||||
|
|
||||||
|
// what group a joint belongs to.
|
||||||
|
// For purpose of stripping unused groups when joints are over limit.
|
||||||
|
struct JointGroups
|
||||||
|
{
|
||||||
|
std::string mGroup;
|
||||||
|
std::string mParentGroup;
|
||||||
|
};
|
||||||
|
typedef std::map<std::string, JointGroups> joint_to_group_map_t;
|
||||||
|
joint_to_group_map_t mJointGroups;
|
||||||
|
|
||||||
// per skin joint count, needs to be tracked for the sake of limits check.
|
// per skin joint count, needs to be tracked for the sake of limits check.
|
||||||
std::vector<S32> mValidJointsCount;
|
std::vector<S32> mValidJointsCount;
|
||||||
|
|
@ -122,13 +134,16 @@ private:
|
||||||
bool parseMeshes();
|
bool parseMeshes();
|
||||||
void computeCombinedNodeTransform(const LL::GLTF::Asset& asset, S32 node_index, glm::mat4& combined_transform) const;
|
void computeCombinedNodeTransform(const LL::GLTF::Asset& asset, S32 node_index, glm::mat4& combined_transform) const;
|
||||||
void processNodeHierarchy(S32 node_idx, std::map<std::string, S32>& mesh_name_counts, U32 submodel_limit, const LLVolumeParams& volume_params);
|
void processNodeHierarchy(S32 node_idx, std::map<std::string, S32>& mesh_name_counts, U32 submodel_limit, const LLVolumeParams& volume_params);
|
||||||
|
bool addJointToModelSkin(LLMeshSkinInfo& skin_info, S32 gltf_skin_idx, size_t gltf_joint_idx) const;
|
||||||
bool populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh &mesh, const LL::GLTF::Node &node, material_map& mats, S32 instance_count);
|
bool populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh &mesh, const LL::GLTF::Node &node, material_map& mats, S32 instance_count);
|
||||||
void populateJointFromSkin(S32 skin_idx);
|
void populateJointsFromSkin(S32 skin_idx);
|
||||||
|
void populateJointGroups();
|
||||||
void addModelToScene(LLModel* pModel, U32 submodel_limit, const LLMatrix4& transformation, const LLVolumeParams& volume_params, const material_map& mats);
|
void addModelToScene(LLModel* pModel, U32 submodel_limit, const LLMatrix4& transformation, const LLVolumeParams& volume_params, const material_map& mats);
|
||||||
S32 findClosestValidJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const;
|
S32 findClosestValidJoint(S32 source_joint, const LL::GLTF::Skin& gltf_skin) const;
|
||||||
S32 findValidRootJointNode(S32 source_joint_node, const LL::GLTF::Skin& gltf_skin) const;
|
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 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;
|
S32 findParentNode(S32 node) const;
|
||||||
|
void buildJointGroup(LLJointData& viewer_data, const std::string& parent_group);
|
||||||
void buildOverrideMatrix(LLJointData& data, joints_data_map_t &gltf_nodes, joints_name_to_node_map_t &names_to_nodes, glm::mat4& parent_rest, glm::mat4& support_rest) const;
|
void buildOverrideMatrix(LLJointData& data, joints_data_map_t &gltf_nodes, joints_name_to_node_map_t &names_to_nodes, glm::mat4& parent_rest, glm::mat4& support_rest) const;
|
||||||
glm::mat4 buildGltfRestMatrix(S32 joint_node_index, const LL::GLTF::Skin& gltf_skin) const;
|
glm::mat4 buildGltfRestMatrix(S32 joint_node_index, const LL::GLTF::Skin& gltf_skin) const;
|
||||||
glm::mat4 buildGltfRestMatrix(S32 joint_node_index, const joints_data_map_t& joint_data) const;
|
glm::mat4 buildGltfRestMatrix(S32 joint_node_index, const joints_data_map_t& joint_data) const;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue