diff options
Diffstat (limited to 'indra/newview/llskinningutil.cpp')
-rw-r--r-- | indra/newview/llskinningutil.cpp | 234 |
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; +} |