#4214 Revert and remake "weights remap"

This reverts commits fe10a83f69
and 08f6f5c697fce4ccbfba357ab9ce5af915dd0574..
master
Andrey Kleshchev 2025-06-19 19:20:35 +03:00 committed by Andrey Kleshchev
parent 5bc92322e9
commit f5320302d4
5 changed files with 78 additions and 94 deletions

View File

@ -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)

View File

@ -205,7 +205,6 @@ public:
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;

View File

@ -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);
@ -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());
@ -1022,14 +1024,23 @@ 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);
@ -1037,10 +1048,28 @@ bool LLGLTFLoader::populateModelFromMesh(LLModel* pModel, const LL::GLTF::Mesh&
{
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);
@ -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;
@ -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
@ -1095,6 +1147,7 @@ void LLGLTFLoader::populateJointFromSkin(S32 skin_idx)
{
data.mName = mJointMap[jointNode.mName];
data.mIsValidViewerJoint = true;
mValidJointsCount[skin_idx]++;
}
else
{
@ -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)

View File

@ -207,6 +207,9 @@ protected:
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();

View File

@ -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"