Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions indra/llappearance/llavatarappearance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class LLAvatarBoneInfo
std::string mName;
std::string mSupport;
std::string mAliases;
std::string mGroup;
bool mIsJoint;
LLVector3 mPos;
LLVector3 mEnd;
Expand Down Expand Up @@ -1606,6 +1607,15 @@ bool LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
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)
{
static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
Expand Down Expand Up @@ -1687,6 +1697,7 @@ void LLAvatarSkeletonInfo::getJointMatricesAndHierarhy(
data.mRotation = bone_info->mRot;
data.mRestMatrix = parent_mat * data.mJointMatrix;
data.mIsJoint = bone_info->mIsJoint;
data.mGroup = bone_info->mGroup;
for (LLAvatarBoneInfo* child_info : bone_info->mChildren)
{
LLJointData& child_data = data.mChildren.emplace_back();
Expand Down
1 change: 1 addition & 0 deletions indra/llappearance/lljointdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class LLJointData
{
public:
std::string mName;
std::string mGroup;
glm::mat4 mJointMatrix;
glm::mat4 mRestMatrix;
glm::vec3 mScale;
Expand Down
177 changes: 129 additions & 48 deletions indra/newview/gltf/llgltfloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,14 @@ bool LLGLTFLoader::parseMeshes()
if (mGLTFAsset.mSkins.size() > 0)
{
checkForXYrotation(mGLTFAsset.mSkins[0]);
populateJointGroups();
}

// 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++)
{
populateJointFromSkin(i);
populateJointsFromSkin(i);
}

// Track how many times each mesh name has been used
Expand Down Expand Up @@ -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)
{
// Set the requested label for the floater display and uploading
Expand Down Expand Up @@ -519,15 +538,9 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
size_t jointCnt = gltf_skin.mJoints.size();
gltf_joint_index_use.resize(jointCnt);

S32 replacement_index = 0;
for (size_t i = 0; i < jointCnt; ++i)
{
// Process joint name and idnex
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())
if (mJointNames[i].empty())
{
// This might need to hold a substitute index
gltf_joint_index_use[i] = -1; // mark as unsupported
Expand Down Expand Up @@ -959,65 +972,106 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
// Call normalizeVolumeFacesAndWeights to compute proper extents
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)
{
LL::GLTF::Skin& gltf_skin = mGLTFAsset.mSkins[skinIdx];
LLMeshSkinInfo& skin_info = pModel->mSkinInfo;
S32 valid_joints_count = mValidJointsCount[skinIdx];

S32 replacement_index = 0;
std::vector<S32> gltfindex_to_joitindex_map;
size_t jointCnt = gltf_skin.mJoints.size();
gltfindex_to_joitindex_map.resize(jointCnt);

S32 replacement_index = 0;
S32 stripped_valid_joints = 0;
for (size_t i = 0; i < jointCnt; ++i)
if (valid_joints_count > LL_MAX_JOINTS_PER_MESH_OBJECT)
{
// Process joint name and idnex
S32 joint = gltf_skin.mJoints[i];
if (gltf_joint_index_use[i] < 0)
std::map<std::string, S32> goup_use_count;
// Assume that 'Torso' group is always in use since that's what everything else is attached to
goup_use_count["Torso"] = 1;
// Note that Collisions and Extra groups are all over the place, might want to include them from the start
// or add individual when parents are added

// Check which groups are in use
for (size_t i = 0; i < jointCnt; ++i)
{
// unsupported (-1) joint, drop it
continue;
std::string& joint_name = mJointNames[skinIdx][i];
if (!joint_name.empty())
{
if (gltf_joint_index_use[i] > 0)
{
const JointGroups &group = mJointGroups[joint_name];
// Joint in use, increment it's groups
goup_use_count[group.mGroup]++;
goup_use_count[group.mParentGroup]++;
}
}
}
LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint];

std::string legal_name(jointNode.mName);
if (mJointMap.find(legal_name) != mJointMap.end())
// 1. add joints that are in use directly
for (size_t i = 0; i < jointCnt; ++i)
{
legal_name = mJointMap[legal_name];
}
else
{
llassert(false); // should have been stopped by gltf_joint_index_use[i] == -1
continue;
// Process joint name and idnex
S32 joint = gltf_skin.mJoints[i];
if (gltf_joint_index_use[i] <= 0)
{
// unsupported (-1) joint, drop it
// unused (0) joint, drop it
continue;
}

if (addJointToModelSkin(skin_info, skinIdx, i))
{
gltfindex_to_joitindex_map[i] = replacement_index++;
}
}

if (valid_joints_count > LL_MAX_JOINTS_PER_MESH_OBJECT
&& gltf_joint_index_use[i] == 0
&& legal_name != "mPelvis")
// 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)
{
// Unused (0) joint
// 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.
// But if model is over limid, drop extras sans pelvis.
// Keeping 'pelvis' is a workaround to keep preview whole.
// Todo: consider improving this, either take as much as possible or
// ensure common parents/roots are included
continue;
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;
}

gltfindex_to_joitindex_map[i] = replacement_index++;

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[skinIdx][i]);

skin_info.mAlternateBindMatrix.push_back(mAlternateBindMatrices[skinIdx][i]);
if (addJointToModelSkin(skin_info, skinIdx, i))
{
gltfindex_to_joitindex_map[i] = replacement_index++;
}
}
}

if (skin_info.mInvBindMatrix.size() > LL_MAX_JOINTS_PER_MESH_OBJECT)
Expand Down Expand Up @@ -1046,7 +1100,7 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
return true;
}

void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
void LLGLTFLoader::populateJointsFromSkin(S32 skin_idx)
{
const LL::GLTF::Skin& skin = mGLTFAsset.mSkins[skin_idx];

Expand All @@ -1066,6 +1120,7 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
{
mInverseBindMatrices.resize(skin_idx + 1);
mAlternateBindMatrices.resize(skin_idx + 1);
mJointNames.resize(skin_idx + 1);
mValidJointsCount.resize(skin_idx + 1, 0);
}

Expand Down Expand Up @@ -1135,6 +1190,11 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
{
legal_name = mJointMap[legal_name];
legal_joint = true;
mJointNames[skin_idx].push_back(legal_name);
}
else
{
mJointNames[skin_idx].emplace_back();
}

// Compute bind matrices
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -1299,6 +1368,18 @@ S32 LLGLTFLoader::findParentNode(S32 node) const
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
{
glm::mat4 new_lefover(1.f);
Expand Down
17 changes: 16 additions & 1 deletion indra/newview/gltf/llgltfloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,20 @@ class LLGLTFLoader : public LLModelLoader

// 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<std::vector<std::string> > joint_names_t;
bind_matrices_t mInverseBindMatrices;
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.
std::vector<S32> mValidJointsCount;
Expand All @@ -122,13 +134,16 @@ class LLGLTFLoader : public LLModelLoader
bool parseMeshes();
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);
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);
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);
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 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;
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;
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;
Expand Down
Loading