summaryrefslogtreecommitdiff
path: root/indra/newview/llskinningutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llskinningutil.cpp')
-rw-r--r--indra/newview/llskinningutil.cpp234
1 files changed, 212 insertions, 22 deletions
diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp
index dba690242a..0fa4c2b114 100644
--- a/indra/newview/llskinningutil.cpp
+++ b/indra/newview/llskinningutil.cpp
@@ -31,26 +31,73 @@
#include "llvoavatar.h"
#include "llviewercontrol.h"
#include "llmeshrepository.h"
+#include "llvolume.h"
+#include "llrigginginfo.h"
+
+void dump_avatar_and_skin_state(const std::string& reason, LLVOAvatar *avatar, const LLMeshSkinInfo *skin)
+{
+ static S32 dump_count = 0;
+ const S32 max_dump = 10;
+
+ if (dump_count < max_dump)
+ {
+ LL_WARNS("Avatar") << avatar->getFullname() << " dumping, reason " << reason
+ << " avatar build state: isBuilt() " << avatar->isBuilt()
+ << " mInitFlags " << avatar->mInitFlags << LL_ENDL;
+ LL_WARNS("Avatar") << "Skin num joints " << skin->mJointNames.size() << " " << skin->mJointNums.size() << LL_ENDL;
+ LL_WARNS("Avatar") << "Skin scrubbed " << skin->mInvalidJointsScrubbed
+ << " nums init " << skin->mJointNumsInitialized << LL_ENDL;
+ for (S32 j=0; j<skin->mJointNames.size(); j++)
+ {
+ LL_WARNS("Avatar") << "skin joint idx " << j << " name [" << skin->mJointNames[j]
+ << "] num " << skin->mJointNums[j] << LL_ENDL;
+ const std::string& name = skin->mJointNames[j];
+ S32 joint_num = skin->mJointNums[j];
+
+ LLJoint *name_joint = avatar->getJoint(name);
+ LLJoint *num_joint = avatar->getJoint(joint_num);
+ if (!name_joint)
+ {
+ LL_WARNS("Avatar") << "failed to find joint by name" << LL_ENDL;
+ }
+ if (!num_joint)
+ {
+ LL_WARNS("Avatar") << "failed to find joint by num" << LL_ENDL;
+ }
+ if (num_joint != name_joint)
+ {
+ LL_WARNS("Avatar") << "joint pointers don't match" << LL_ENDL;
+ }
+ if (num_joint && num_joint->getJointNum() != joint_num)
+ {
+ LL_WARNS("Avatar") << "joint found by num has wrong num " << joint_num << "!=" << num_joint->getJointNum() << LL_ENDL;
+ }
+ if (name_joint && name_joint->getJointNum() != joint_num)
+ {
+ LL_WARNS("Avatar") << "joint found by name has wrong num " << joint_num << "!=" << name_joint->getJointNum() << LL_ENDL;
+ }
+ }
+ LL_WARNS("Avatar") << LL_ENDL;
+
+ dump_count++;
+ }
+}
-// static
void LLSkinningUtil::initClass()
{
}
-// static
U32 LLSkinningUtil::getMaxJointCount()
{
U32 result = LL_MAX_JOINTS_PER_MESH_OBJECT;
return result;
}
-// static
U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin)
{
return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size());
}
-// static
void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin)
{
if (skin->mInvalidJointsScrubbed)
@@ -64,35 +111,25 @@ 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;
+ LL_DEBUGS("Avatar") << avatar->getFullname() << " mesh rigged to invalid joint " << skin->mJointNames[j] << LL_ENDL;
+ LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL;
skin->mJointNames[j] = "mPelvis";
+ skin->mJointNumsInitialized = false; // force update after names change.
}
}
skin->mInvalidJointsScrubbed = true;
}
-// static
void LLSkinningUtil::initSkinningMatrixPalette(
LLMatrix4* mat,
S32 count,
const LLMeshSkinInfo* skin,
LLVOAvatar *avatar)
{
+ initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar);
for (U32 j = 0; j < count; ++j)
{
- LLJoint *joint = NULL;
- if (skin->mJointNums[j] == -1)
- {
- joint = avatar->getJoint(skin->mJointNames[j]);
- if (joint)
- {
- skin->mJointNums[j] = joint->getJointNum();
- }
- }
- else
- {
- joint = avatar->getJoint(skin->mJointNums[j]);
- }
+ LLJoint *joint = avatar->getJoint(skin->mJointNums[j]);
if (joint)
{
#define MAT_USE_SSE
@@ -114,12 +151,19 @@ void LLSkinningUtil::initSkinningMatrixPalette(
// rendering should be disabled unless all joints are
// valid. In other cases of skinned rendering, invalid
// joints should already have been removed during scrubInvalidJoints().
- LL_WARNS_ONCE("Avatar") << "Rigged to invalid joint name " << skin->mJointNames[j] << LL_ENDL;
+ LL_WARNS_ONCE("Avatar") << avatar->getFullname()
+ << " rigged to invalid joint name " << skin->mJointNames[j]
+ << " num " << skin->mJointNums[j] << LL_ENDL;
+ LL_WARNS_ONCE("Avatar") << avatar->getFullname()
+ << " avatar build state: isBuilt() " << avatar->isBuilt()
+ << " mInitFlags " << avatar->mInitFlags << LL_ENDL;
+#if 0
+ dump_avatar_and_skin_state("initSkinningMatrixPalette joint not found", avatar, skin);
+#endif
}
}
}
-// static
void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin)
{
#ifdef SHOW_ASSERT // same condition that controls llassert()
@@ -159,7 +203,6 @@ void LLSkinningUtil::scrubSkinWeights(LLVector4a* weights, U32 num_vertices, con
checkSkinWeights(weights, num_vertices, skin);
}
-// static
void LLSkinningUtil::getPerVertexSkinMatrix(
F32* weights,
LLMatrix4a* mat,
@@ -216,3 +259,150 @@ void LLSkinningUtil::getPerVertexSkinMatrix(
llassert(valid_weights);
}
+void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar)
+{
+ if (!skin->mJointNumsInitialized)
+ {
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ LLJoint *joint = NULL;
+ if (skin->mJointNums[j] == -1)
+ {
+ joint = avatar->getJoint(skin->mJointNames[j]);
+ if (joint)
+ {
+ skin->mJointNums[j] = joint->getJointNum();
+ if (skin->mJointNums[j] < 0)
+ {
+ LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " joint has unusual number " << skin->mJointNames[j] << ": " << skin->mJointNums[j] << LL_ENDL;
+ LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " avatar build state: isBuilt() " << avatar->isBuilt() << " mInitFlags " << avatar->mInitFlags << LL_ENDL;
+ }
+ }
+ else
+ {
+ LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " unable to find joint " << skin->mJointNames[j] << LL_ENDL;
+ LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " avatar build state: isBuilt() " << avatar->isBuilt() << " mInitFlags " << avatar->mInitFlags << LL_ENDL;
+#if 0
+ dump_avatar_and_skin_state("initJointNums joint not found", avatar, skin);
+#endif
+ }
+ }
+ }
+ skin->mJointNumsInitialized = true;
+ }
+}
+
+static LLTrace::BlockTimerStatHandle FTM_FACE_RIGGING_INFO("Face Rigging Info");
+
+void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *avatar, LLVolumeFace& vol_face)
+{
+ LL_RECORD_BLOCK_TIME(FTM_FACE_RIGGING_INFO);
+
+ if (vol_face.mJointRiggingInfoTab.needsUpdate())
+ {
+ S32 num_verts = vol_face.mNumVertices;
+ if (num_verts>0 && vol_face.mWeights && (skin->mJointNames.size()>0))
+ {
+ initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar);
+ if (vol_face.mJointRiggingInfoTab.size()==0)
+ {
+ //std::set<S32> active_joints;
+ //S32 active_verts = 0;
+ vol_face.mJointRiggingInfoTab.resize(LL_CHARACTER_MAX_ANIMATED_JOINTS);
+ LLJointRiggingInfoTab &rig_info_tab = vol_face.mJointRiggingInfoTab;
+ for (S32 i=0; i<vol_face.mNumVertices; i++)
+ {
+ LLVector4a& pos = vol_face.mPositions[i];
+ F32 *weights = vol_face.mWeights[i].getF32ptr();
+ LLVector4 wght;
+ S32 idx[4];
+ F32 scale = 0.0f;
+ // FIXME unpacking of weights should be pulled into a common function and optimized if possible.
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = weights[k];
+ idx[k] = llclamp((S32) floorf(w), (S32)0, (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS-1);
+ wght[k] = w - idx[k];
+ scale += wght[k];
+ }
+ if (scale > 0.0f)
+ {
+ for (U32 k=0; k<4; ++k)
+ {
+ wght[k] /= scale;
+ }
+ }
+ for (U32 k=0; k<4; ++k)
+ {
+ S32 joint_index = idx[k];
+ if (wght[k] > 0.0f)
+ {
+ S32 joint_num = skin->mJointNums[joint_index];
+ if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS)
+ {
+ rig_info_tab[joint_num].setIsRiggedTo(true);
+
+ // FIXME could precompute these matMuls.
+ LLMatrix4a bind_shape;
+ bind_shape.loadu(skin->mBindShapeMatrix);
+ LLMatrix4a inv_bind;
+ inv_bind.loadu(skin->mInvBindMatrix[joint_index]);
+ LLMatrix4a mat;
+ matMul(bind_shape, inv_bind, mat);
+ LLVector4a pos_joint_space;
+ mat.affineTransform(pos, pos_joint_space);
+ pos_joint_space.mul(wght[k]);
+ LLVector4a *extents = rig_info_tab[joint_num].getRiggedExtents();
+ update_min_max(extents[0], extents[1], pos_joint_space);
+ }
+ }
+ }
+ }
+ //LL_DEBUGS("RigSpammish") << "built rigging info for vf " << &vol_face
+ // << " num_verts " << vol_face.mNumVertices
+ // << " active joints " << active_joints.size()
+ // << " active verts " << active_verts
+ // << LL_ENDL;
+ vol_face.mJointRiggingInfoTab.setNeedsUpdate(false);
+ }
+ }
+ if (vol_face.mJointRiggingInfoTab.size()!=0)
+ {
+ LL_DEBUGS("RigSpammish") << "we have rigging info for vf " << &vol_face
+ << " num_verts " << vol_face.mNumVertices << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("RigSpammish") << "no rigging info for vf " << &vol_face
+ << " num_verts " << vol_face.mNumVertices << LL_ENDL;
+ }
+
+ }
+}
+
+// This is used for extracting rotation from a bind shape matrix that
+// already has scales baked in
+LLQuaternion LLSkinningUtil::getUnscaledQuaternion(const LLMatrix4& mat4)
+{
+ LLMatrix3 bind_mat = mat4.getMat3();
+ for (auto i = 0; i < 3; i++)
+ {
+ F32 len = 0.0f;
+ for (auto j = 0; j < 3; j++)
+ {
+ len += bind_mat.mMatrix[i][j] * bind_mat.mMatrix[i][j];
+ }
+ if (len > 0.0f)
+ {
+ len = sqrt(len);
+ for (auto j = 0; j < 3; j++)
+ {
+ bind_mat.mMatrix[i][j] /= len;
+ }
+ }
+ }
+ bind_mat.invert();
+ LLQuaternion bind_rot = bind_mat.quaternion();
+ bind_rot.normalize();
+ return bind_rot;
+}