summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Payne (Vir Linden) <vir@lindenlab.com>2016-11-30 14:03:54 -0500
committerBrad Payne (Vir Linden) <vir@lindenlab.com>2016-11-30 14:03:54 -0500
commit93db7eacbd1e46c78f8f5d0071578b9bed3202ac (patch)
treee0394c9a47876759aafc92461d3226b0184340e1
parent4c2144e1153fb71544140bb51630b13e17ead6d3 (diff)
SL-540 - fix for regression in handling of out-of-range joint indices in skin weights
-rw-r--r--indra/llmath/llvolume.cpp3
-rw-r--r--indra/llmath/llvolume.h2
-rw-r--r--indra/newview/lldrawpoolavatar.cpp14
-rw-r--r--indra/newview/llskinningutil.cpp19
-rw-r--r--indra/newview/llskinningutil.h1
5 files changed, 35 insertions, 4 deletions
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index bd24a46e8d..6f0b4b2410 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -4575,6 +4575,7 @@ LLVolumeFace::LLVolumeFace() :
mTexCoords(NULL),
mIndices(NULL),
mWeights(NULL),
+ mWeightsScrubbed(FALSE),
mOctree(NULL),
mOptimized(FALSE)
{
@@ -4600,6 +4601,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
mTexCoords(NULL),
mIndices(NULL),
mWeights(NULL),
+ mWeightsScrubbed(FALSE),
mOctree(NULL)
{
mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
@@ -4671,6 +4673,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
ll_aligned_free_16(mWeights);
mWeights = NULL;
}
+ mWeightsScrubbed = src.mWeightsScrubbed;
}
if (mNumIndices)
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 1da2d0c6b1..d66004cdad 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -953,6 +953,8 @@ public:
// mWeights.size() should be empty or match mVertices.size()
LLVector4a* mWeights;
+ mutable BOOL mWeightsScrubbed;
+
LLOctreeNode<LLVolumeTriangle>* mOctree;
//whether or not face has been cache optimized
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 10311044d2..499cf76bff 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1544,8 +1544,8 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
LLVolume* volume,
const LLVolumeFace& vol_face)
{
- LLVector4a* weight = vol_face.mWeights;
- if (!weight)
+ LLVector4a* weights = vol_face.mWeights;
+ if (!weights)
{
return;
}
@@ -1556,6 +1556,12 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
LLDrawable* drawable = face->getDrawable();
U32 data_mask = face->getRiggedVertexBufferDataMask();
+
+ if (!vol_face.mWeightsScrubbed)
+ {
+ LLSkinningUtil::scrubSkinWeights(weights, vol_face.mNumVertices, skin);
+ vol_face.mWeightsScrubbed = TRUE;
+ }
if (buffer.isNull() ||
buffer->getTypeMask() != data_mask ||
@@ -1610,7 +1616,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
U32 count = LLSkinningUtil::getMeshJointCount(skin);
LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar);
- LLSkinningUtil::checkSkinWeights(weight, buffer->getNumVerts(), skin);
+ LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin);
LLMatrix4a bind_shape_matrix;
bind_shape_matrix.loadu(skin->mBindShapeMatrix);
@@ -1619,7 +1625,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(
for (U32 j = 0; j < buffer->getNumVerts(); ++j)
{
LLMatrix4a final_mat;
- LLSkinningUtil::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints);
+ LLSkinningUtil::getPerVertexSkinMatrix(weights[j].getF32ptr(), mat, false, final_mat, max_joints);
LLVector4a& v = vol_face.mPositions[j];
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index b2fd1744bc..cf09f6f978 100644
--- a/indra/newview/llskinningutil.cpp
+++ b/indra/newview/llskinningutil.cpp
@@ -64,6 +64,7 @@ void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin
// needed for handling of any legacy bad data.
if (!avatar->getJoint(skin->mJointNames[j]))
{
+ LL_DEBUGS("Avatar") << "Mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL;
skin->mJointNames[j] = "mPelvis";
}
}
@@ -140,6 +141,24 @@ void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, con
#endif
}
+void LLSkinningUtil::scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin)
+{
+ const S32 max_joints = skin->mJointNames.size();
+ for (U32 j=0; j<num_vertices; j++)
+ {
+ F32 *w = weights[j].getF32ptr();
+
+ for (U32 k=0; k<4; ++k)
+ {
+ S32 i = llfloor(w[k]);
+ F32 f = w[k]-i;
+ i = llclamp(i,0,max_joints-1);
+ w[k] = i + f;
+ }
+ }
+ checkSkinWeights(weights, num_vertices, skin);
+}
+
// static
void LLSkinningUtil::getPerVertexSkinMatrix(
F32* weights,
diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h
index 6a6091114c..135b25d4d2 100644
--- a/indra/newview/llskinningutil.h
+++ b/indra/newview/llskinningutil.h
@@ -40,6 +40,7 @@ public:
static void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin);
static void initSkinningMatrixPalette(LLMatrix4* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar);
static void checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
+ static void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin);
static void getPerVertexSkinMatrix(F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints);
};