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
87 changes: 0 additions & 87 deletions indra/llprimitive/llmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,93 +112,6 @@ void LLModel::remapVolumeFaces()
}
}

void LLModel::remapSkinWeightsAndJoints()
{
if (mSkinWeights.empty())
{
return;
}

mPosition.clear();

// Make a list of positions
std::set<LLVector3> positions;
for (S32 i = 0; i < getNumVolumeFaces(); ++i)
{
for (S32 j = 0; j < mVolumeFaces[i].mNumVertices; ++j)
{
positions.emplace(mVolumeFaces[i].mPositions[j].getF32ptr());
}
}

// Build new list of weights and record used joints
weight_map replacement_weights;
std::vector<S32> joint_index_use_count;
size_t joint_count = mSkinInfo.mJointNames.size();
joint_index_use_count.resize(joint_count, 0);
for (const LLVector3& pos : positions)
{
mPosition.push_back(pos);
auto found = mSkinWeights.find(pos);
if (found != mSkinWeights.end())
{
replacement_weights[pos] = found->second;

for (auto& weight : found->second)
{
if (joint_count > weight.mJointIdx)
{
joint_index_use_count[weight.mJointIdx]++;
}
}
}
}

// go over joint data and remap joints
// prepare joint map
std::vector<std::string> replacement_joint_names;
std::vector<S32> replacement_joint_nums;
LLMeshSkinInfo::matrix_list_t replacement_inv_bind;
LLMeshSkinInfo::matrix_list_t replacement_alt_bind;
std::vector<S32> index_map;
index_map.resize(joint_count);
S32 replacement_index = 0;

for (S32 i = 0; i < joint_count; i++)
{
if (joint_index_use_count[i] > 0)
{
replacement_joint_names.push_back(mSkinInfo.mJointNames[i]);
replacement_joint_nums.push_back(mSkinInfo.mJointNums[i]);
replacement_inv_bind.push_back(mSkinInfo.mInvBindMatrix[i]);
replacement_alt_bind.push_back(mSkinInfo.mAlternateBindMatrix[i]);
index_map[i] = replacement_index++;
}
}

// Apply new data
mSkinInfo.mJointNames.clear();
mSkinInfo.mJointNames = replacement_joint_names;
mSkinInfo.mJointNums.clear();
mSkinInfo.mJointNums = replacement_joint_nums;
mSkinInfo.mInvBindMatrix.clear();
mSkinInfo.mInvBindMatrix = replacement_inv_bind;
mSkinInfo.mAlternateBindMatrix.clear();
mSkinInfo.mAlternateBindMatrix = replacement_alt_bind;

// remap weights
for (auto& weights : replacement_weights)
{
for (auto& weight : weights.second)
{
weight.mJointIdx = index_map[weight.mJointIdx];
}
}

mSkinWeights.clear();
mSkinWeights = replacement_weights;
}

void LLModel::optimizeVolumeFaces()
{
for (S32 i = 0; i < getNumVolumeFaces(); ++i)
Expand Down
1 change: 0 additions & 1 deletion indra/llprimitive/llmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ class LLModel : public LLVolume
void normalizeVolumeFacesAndWeights();
void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);
void remapVolumeFaces();
void remapSkinWeightsAndJoints();
void optimizeVolumeFaces();
void offsetMesh( const LLVector3& pivotPoint );
void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out) const;
Expand Down
79 changes: 73 additions & 6 deletions indra/newview/gltf/llgltfloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,6 @@ void LLGLTFLoader::addModelToScene(
{
// remove unused/redundant vertices
model->remapVolumeFaces();
// remove unused/redundant weights and joints
model->remapSkinWeightsAndJoints();

mModelList.push_back(model);

Expand Down Expand Up @@ -821,21 +819,25 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
&& vertices[i].weights.x > 0.f)
{
weight_list.push_back(LLModel::JointWeight(vertices[i].joints.x, vertices[i].weights.x));
gltf_joint_index_use[vertices[i].joints.x]++;
}
if (gltf_joint_index_use[vertices[i].joints.y] >= 0
&& vertices[i].weights.y > 0.f)
{
weight_list.push_back(LLModel::JointWeight(vertices[i].joints.y, vertices[i].weights.y));
gltf_joint_index_use[vertices[i].joints.y]++;
}
if (gltf_joint_index_use[vertices[i].joints.z] >= 0
&& vertices[i].weights.z > 0.f)
{
weight_list.push_back(LLModel::JointWeight(vertices[i].joints.z, vertices[i].weights.z));
gltf_joint_index_use[vertices[i].joints.z]++;
}
if (gltf_joint_index_use[vertices[i].joints.w] >= 0
&& vertices[i].weights.w > 0.f)
{
weight_list.push_back(LLModel::JointWeight(vertices[i].joints.w, vertices[i].weights.w));
gltf_joint_index_use[vertices[i].joints.w]++;
}

std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater());
Expand Down Expand Up @@ -1022,25 +1024,52 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
{
LL::GLTF::Skin& gltf_skin = mGLTFAsset.mSkins[skinIdx];
LLMeshSkinInfo& skin_info = pModel->mSkinInfo;
S32 valid_joints_count = mValidJointsCount[skinIdx];

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)
{
// Process joint name and idnex
S32 joint = gltf_skin.mJoints[i];
if (gltf_joint_index_use[i] < 0)
{
// unsupported (-1) joint, drop it
continue;
}
LL::GLTF::Node& jointNode = mGLTFAsset.mNodes[joint];

std::string legal_name(jointNode.mName);
if (mJointMap.find(legal_name) != mJointMap.end())
{
legal_name = mJointMap[legal_name];
}
// else thanks to gltf_joint_index_usage any illegal
// joint should have zero uses.
// Add them anyway to preserve order, remapSkinWeightsAndJoints
// will sort them out later
else
{
llassert(false); // should have been stopped by gltf_joint_index_use[i] == -1
continue;
}

if (valid_joints_count > LL_MAX_JOINTS_PER_MESH_OBJECT
&& gltf_joint_index_use[i] == 0
&& legal_name != "mPelvis")
{
// 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;
}

gltfindex_to_joitindex_map[i] = replacement_index++;

skin_info.mJointNames.push_back(legal_name);
skin_info.mJointNums.push_back(-1);
Expand All @@ -1050,6 +1079,28 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&

skin_info.mAlternateBindMatrix.push_back(mAlternateBindMatrices[skinIdx][i]);
}

if (skin_info.mInvBindMatrix.size() > LL_MAX_JOINTS_PER_MESH_OBJECT)
{
LL_WARNS("GLTF_IMPORT") << "Too many jonts in " << pModel->mLabel
<< " Count: " << (S32)skin_info.mInvBindMatrix.size()
<< " Limit:" << (S32)LL_MAX_JOINTS_PER_MESH_OBJECT << LL_ENDL;
LLSD args;
args["Message"] = "ModelTooManyJoint";
args["MODEL_NAME"] = pModel->mLabel;
args["JOINT_COUNT"] = (S32)skin_info.mInvBindMatrix.size();
args["MAX"] = (S32)LL_MAX_JOINTS_PER_MESH_OBJECT;
mWarningsArray.append(args);
}

// Remap indices for pModel->mSkinWeights
for (auto& weights : pModel->mSkinWeights)
{
for (auto& weight : weights.second)
{
weight.mJointIdx = gltfindex_to_joitindex_map[weight.mJointIdx];
}
}
}

return true;
Expand All @@ -1075,6 +1126,7 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
{
mInverseBindMatrices.resize(skin_idx + 1);
mAlternateBindMatrices.resize(skin_idx + 1);
mValidJointsCount.resize(skin_idx + 1, 0);
}

// fill up joints related data
Expand All @@ -1095,6 +1147,7 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
{
data.mName = mJointMap[jointNode.mName];
data.mIsValidViewerJoint = true;
mValidJointsCount[skin_idx]++;
}
else
{
Expand All @@ -1111,6 +1164,20 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
}
}

if (mValidJointsCount[skin_idx] > LL_MAX_JOINTS_PER_MESH_OBJECT)
{
LL_WARNS("GLTF_IMPORT") << "Too many jonts, will strip unused joints"
<< " Count: " << mValidJointsCount[skin_idx]
<< " Limit:" << (S32)LL_MAX_JOINTS_PER_MESH_OBJECT << LL_ENDL;

LLSD args;
args["Message"] = "SkinJointsOverLimit";
args["SKIN_INDEX"] = (S32)skin_idx;
args["JOINT_COUNT"] = mValidJointsCount[skin_idx];
args["MAX"] = (S32)LL_MAX_JOINTS_PER_MESH_OBJECT;
mWarningsArray.append(args);
}

// Go over viewer joints and build overrides
glm::mat4 ident(1.0);
for (auto &viewer_data : mViewerJointData)
Expand Down
3 changes: 3 additions & 0 deletions indra/newview/gltf/llgltfloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ class LLGLTFLoader : public LLModelLoader
bind_matrices_t mInverseBindMatrices;
bind_matrices_t mAlternateBindMatrices;

// per skin joint count, needs to be tracked for the sake of limits check.
std::vector<S32> mValidJointsCount;

private:
bool parseMeshes();
void uploadMeshes();
Expand Down
2 changes: 2 additions & 0 deletions indra/newview/skins/default/xui/en/floater_model_preview.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@
<string name="UnsupportedExtension">Unable to load model, unsupported extension: [EXT]</string>
<string name="TooManyMeshParts">Model contains [PART_COUNT] mesh parts. Maximum allowed: [LIMIT]</string>
<string name="FailedToCreateTempFile">Failed to create temporary file for embedded texture [TEXTURE_INDEX]: [TEMP_FILE]</string>
<string name="SkinJointsOverLimit">Skin [SKIN_INDEX] defines [JOINT_COUNT] compatible joints, maximum is: [MAX]. Unused joints will be stripped on per model basis.</string>
<string name="ModelTooManyJoint">Model [MODEL_NAME] uses [JOINT_COUNT], maximum: [MAX], upload might fail</string>

<panel
follows="top|left"
Expand Down