diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 46bb29c7f5891343b3e7dec6400b3cf54d9aba07..aa2afc5a28335423287e462f97fec5547ef390a5 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -728,7 +728,7 @@ BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info) LL_ERRS() << "Can't allocate " << info->mNumBones << " joints" << LL_ENDL; return FALSE; } - + // allocate volumes if (info->mNumCollisionVolumes) { diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp index 360f17508fdba828c8431a7dc23789d19f95a1f7..8db212231a711387e6d113b5b5170af011fde01e 100644 --- a/indra/llappearance/llpolyskeletaldistortion.cpp +++ b/indra/llappearance/llpolyskeletaldistortion.cpp @@ -233,7 +233,7 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex ) if (mLastWeight != effective_weight && !mIsAnimating) { - mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1); + mAvatar->bumpSkeletonSerialNum(); } mLastWeight = effective_weight; } diff --git a/indra/llcharacter/CMakeLists.txt b/indra/llcharacter/CMakeLists.txt index 2001259f10399f289abc426de0070bb552fea63a..e386a1ae66b73aa702ab3809ec2f129a53abb585 100644 --- a/indra/llcharacter/CMakeLists.txt +++ b/indra/llcharacter/CMakeLists.txt @@ -104,6 +104,11 @@ if (LL_TESTS) PROPERTIES LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_THREAD_LIBRARY}" ) + set_source_files_properties( + llik.cpp + PROPERTIES + LL_TEST_ADDITIONAL_SOURCE_FILES lljoint.cpp + ) LL_ADD_PROJECT_UNIT_TESTS(llcharacter "${llcharacter_TEST_SOURCE_FILES}") endif (LL_TESTS) diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index 90affcc637a7fb5f43f64b9637584783fa223bed..1f2456ef6643cba8d81526583ed9d62123d17120 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -254,9 +254,9 @@ class LLCharacter U32 getAppearanceSerialNum() const { return mAppearanceSerialNum; } void setAppearanceSerialNum( U32 num ) { mAppearanceSerialNum = num; } - + U32 getSkeletonSerialNum() const { return mSkeletonSerialNum; } - void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; } + void bumpSkeletonSerialNum() { ++mSkeletonSerialNum; } static std::vector< LLCharacter* > sInstances; static BOOL sAllowInstancesChange ; //debug use diff --git a/indra/llcharacter/llik.cpp b/indra/llcharacter/llik.cpp index 91116949e81aa6b5f0ddd48cb3dcc80df6ec39ab..7263bbdc89e02b3cc49eea09d1d8a9b63e6eba59 100644 --- a/indra/llcharacter/llik.cpp +++ b/indra/llcharacter/llik.cpp @@ -35,6 +35,7 @@ #include "llik.h" +#include "lljoint.h" #include "llmath.h" #include "v3math.h" #include "llquaternion.h" @@ -147,27 +148,33 @@ F32 compute_clamped_angle(F32 angle, F32 min_angle, F32 max_angle) void LLIK::Joint::Config::setLocalPos(const LLVector3& pos) { mLocalPos = pos; - mFlags |= FLAG_LOCAL_POS; + mFlags |= CONFIG_FLAG_LOCAL_POS; } void LLIK::Joint::Config::setLocalRot(const LLQuaternion& rot) { mLocalRot = rot; mLocalRot.normalize(); - mFlags |= FLAG_LOCAL_ROT; + mFlags |= CONFIG_FLAG_LOCAL_ROT; +} + +void LLIK::Joint::Config::setLocalScale(const LLVector3& scale) +{ + mLocalScale = scale; + mFlags |= CONFIG_FLAG_LOCAL_SCALE; } void LLIK::Joint::Config::setTargetPos(const LLVector3& pos) { mTargetPos = pos; - mFlags |= FLAG_TARGET_POS; + mFlags |= CONFIG_FLAG_TARGET_POS; } void LLIK::Joint::Config::setTargetRot(const LLQuaternion& rot) { mTargetRot = rot; mTargetRot.normalize(); - mFlags |= FLAG_TARGET_ROT; + mFlags |= CONFIG_FLAG_TARGET_ROT; } void LLIK::Joint::Config::updateFrom(const Config& other_config) @@ -182,19 +189,23 @@ void LLIK::Joint::Config::updateFrom(const Config& other_config) // find and apply all parameters in other_config if (other_config.hasLocalPos()) { - setLocalPos(other_config.getLocalPos()); + setLocalPos(other_config.mLocalPos); } if (other_config.hasLocalRot()) { - setLocalRot(other_config.getLocalRot()); + setLocalRot(other_config.mLocalRot); } if (other_config.hasTargetPos()) { - setTargetPos(other_config.getTargetPos()); + setTargetPos(other_config.mTargetPos); } if (other_config.hasTargetRot()) { - setTargetRot(other_config.getTargetRot()); + setTargetRot(other_config.mTargetRot); + } + if (other_config.hasLocalScale()) + { + setLocalScale(other_config.mLocalScale); } if (other_config.constraintIsDisabled()) { @@ -856,11 +867,22 @@ void LLIK::DoubleLimitedHinge::dumpConfig() const } #endif -LLIK::Joint::Joint(S16 id, const LLVector3& local_pos, const LLVector3& bone) - : mDefaultLocalPos(local_pos), mBone(bone), mID(id) +LLIK::Joint::Joint(LLJoint* info_ptr) : mInfoPtr(info_ptr) { - mLocalPos = mDefaultLocalPos; + assert(info_ptr != nullptr); + mID = mInfoPtr->getJointNum(); + resetFromInfo(); +} + +void LLIK::Joint::resetFromInfo() +{ + LLVector3 scale = mInfoPtr->getScale(); + mLocalPos = mInfoPtr->getPosition().scaledVec(scale); + mBone = mInfoPtr->getEnd().scaledVec(scale); mLocalPosLength = mLocalPos.length(); + // This is Correct: we do NOT store info scale in mLocalScale. + // mLocalScale represents Puppetry's tweak on top of whatever is set in the info. + mLocalScale.set(1.0f, 1.0f, 1.0f); } void LLIK::Joint::addChild(const ptr_t& child) @@ -890,14 +912,14 @@ void LLIK::Joint::setParent(const ptr_t& parent) // Whatever orientation it has at the start of IK will be its final, // which is why we flag it as "locked". This also simplifies logic // elsewhere: in a few places we assume any non-locked Joint has a parent. - mConfigFlags = FLAG_LOCAL_ROT; + mIkFlags = IK_FLAG_LOCAL_ROT_LOCKED; } reset(); } void LLIK::Joint::reset() { - mLocalPos = mDefaultLocalPos; + resetFromInfo(); // Note: we don't bother to enforce localRotLocked() here because any call // to reset() is expected to be outside the Solver IK iterations. mLocalRot = LLQuaternion::DEFAULT; @@ -977,14 +999,6 @@ F32 LLIK::Joint::recursiveComputeLongestChainLength(F32 length) const return longest_length; } -void LLIK::Joint::reconfigure(const LLVector3& local_pos, const LLVector3& bone) -{ - mDefaultLocalPos = local_pos; - mLocalPos = local_pos; - mBone = bone; - mLocalPosLength = mLocalPos.length(); -} - LLVector3 LLIK::Joint::computeEndTargetPos() const { // Note: we expect this Joint has either: a target, @@ -1299,6 +1313,8 @@ void LLIK::Joint::shiftPos(const LLVector3& shift) void LLIK::Joint::setConfig(const Config& config) { + // we only remember the config here + // it gets applied later when we build the chains mConfig = &config; mConfigFlags = mConfig ? mConfig->getFlags() : 0; } @@ -1306,13 +1322,15 @@ void LLIK::Joint::setConfig(const Config& config) void LLIK::Joint::resetFlags() { mConfig = nullptr; - // root Joint always has FLAG_LOCAL_ROT bit set - mConfigFlags = mParent ? 0 : FLAG_LOCAL_ROT; + mConfigFlags = 0; + // root Joint always has IK_FLAG_LOCAL_ROT_LOCKED set + mIkFlags = mParent ? 0 : IK_FLAG_LOCAL_ROT_LOCKED; } void LLIK::Joint::lockLocalRot(const LLQuaternion& local_rot) { mLocalRot = local_rot; + mIkFlags |= IK_FLAG_LOCAL_ROT_LOCKED; activate(); if (!mParent) { @@ -1384,7 +1402,8 @@ void LLIK::Joint::setWorldPos(const LLVector3& pos) // this should only be called once before starting IK algorithm iterations void LLIK::Joint::setLocalPos(const LLVector3& pos) { - mLocalPos = pos; + mLocalPos = pos.scaledVec(mLocalScale); + mLocalPosLength = mLocalPos.length(); if (!mParent) { mPos = mLocalPos; @@ -1407,6 +1426,46 @@ void LLIK::Joint::setLocalRot(const LLQuaternion& new_local_rot) } } +// only call this if you know what you're doing +// this should only be called once before starting IK algorithm iterations +void LLIK::Joint::setLocalScale(const LLVector3& scale) +{ + // compute final scale adustment to applly to mLocalPos and mBone + constexpr F32 MIN_INVERTABLE_SCALE = 1.0e-15f; + LLVector3 re_scale; + for (S32 i = 0; i < 3; ++i) + { + // verify mLocalScale component to avoid introducing NaN + re_scale[i] = (mLocalScale[i] > MIN_INVERTABLE_SCALE) ? scale[i] / mLocalScale[i] : 0.0f; + } + // We remember the final scale adjustment for later... + mLocalScale = scale; + // ...and apply it immediately onto mLocalPos and mBone. + mBone.scaleVec(re_scale); + mLocalPos.scaleVec(re_scale); + mLocalPosLength = mLocalPos.length(); +} + +// returns local_pos with any non-uniform scale from the "info" removed. +LLVector3 LLIK::Joint::getPreScaledLocalPos() const +{ + LLVector3 pos = mLocalPos; + // We inverse-scale mLocalPos because we already applied the info's scale + // to mLocalPos so we could perform IK without constantly recomputing it, + // and now we're being asked for mLocalPos in the info's pre-scaled frame. + + // Note: mInfoPtr will not be nullptr as per assert() in LLIK::Joint::ctor + LLVector3 inv_scale = mInfoPtr->getScale(); + constexpr F32 MIN_INVERTABLE_SCALE = 1.0e-15f; + for (S32 i = 0; i < 3; ++i) + { + // verify scale component to avoid introducing NaN + inv_scale[i] = (inv_scale[i] > MIN_INVERTABLE_SCALE) ? 1.0f / inv_scale[i] : 0.0f; + } + pos.scaleVec(inv_scale); + return pos; +} + void LLIK::Joint::adjustWorldRot(const LLQuaternion& adjustment) { mRot = mRot * adjustment; @@ -1861,10 +1920,10 @@ LLVector3 LLIK::Solver::computeReach(S16 to_id, S16 from_id) const void LLIK::Solver::addJoint( S16 joint_id, S16 parent_id, - const LLVector3& local_pos, - const LLVector3& bone, + LLJoint* joint_info, const Constraint::ptr_t& constraint) { + llassert(joint_info); // Note: parent Joints must be added BEFORE their children. if (joint_id < 0) { @@ -1892,7 +1951,7 @@ void LLIK::Solver::addJoint( { parent = itr->second; } - Joint::ptr_t joint = std::make_shared<Joint>(joint_id, local_pos, bone); + Joint::ptr_t joint = std::make_shared<Joint>(joint_info); joint->setParent(parent); if (parent) { @@ -2046,25 +2105,25 @@ bool LLIK::Solver::updateJointConfigs(const joint_config_map_t& configs) something_changed = true; break; } - if ((mask & FLAG_TARGET_POS) > 0 + if ((mask & CONFIG_FLAG_TARGET_POS) > 0 && std::abs(dist_vec(old_target.getTargetPos(), new_target.getTargetPos())) > mAcceptableError) { something_changed = true; break; } - if ((mask & FLAG_TARGET_ROT) > 0 + if ((mask & CONFIG_FLAG_TARGET_ROT) > 0 && !LLQuaternion::almost_equal(old_target.getTargetRot(), new_target.getTargetRot())) { something_changed = true; break; } - if ((mask & FLAG_LOCAL_POS) > 0 + if ((mask & CONFIG_FLAG_LOCAL_POS) > 0 && std::abs(dist_vec(old_target.getLocalPos(), new_target.getLocalPos())) > mAcceptableError) { something_changed = true; break; } - if ((mask & FLAG_LOCAL_ROT) > 0 + if ((mask & CONFIG_FLAG_LOCAL_ROT) > 0 && !LLQuaternion::almost_equal(old_target.getLocalRot(), new_target.getLocalRot())) { something_changed = true; @@ -2187,7 +2246,7 @@ void LLIK::Solver::rebuildAllChains() if (flags & MASK_ROT) { LLQuaternion q; - if (flags & FLAG_LOCAL_ROT) + if (flags & CONFIG_FLAG_LOCAL_ROT) { q = config.getLocalRot(); } @@ -2202,7 +2261,7 @@ void LLIK::Solver::rebuildAllChains() if (flags & MASK_POS) { LLVector3 p; - if (flags & FLAG_LOCAL_POS) + if (flags & CONFIG_FLAG_LOCAL_POS) { p = config.getLocalPos(); } @@ -2213,6 +2272,10 @@ void LLIK::Solver::rebuildAllChains() joint->setLocalPos(p); joint->activate(); } + if (flags & CONFIG_FLAG_LOCAL_SCALE) + { + joint->setLocalScale(config.getLocalScale()); + } continue; } @@ -2257,6 +2320,11 @@ void LLIK::Solver::rebuildAllChains() joint->setLocalPos(config.getLocalPos()); joint->activate(); } + if (config.hasLocalScale()) + { + joint->setLocalScale(config.getLocalScale()); + joint->activate(); + } } // each sub_base gets its own Chain @@ -2368,6 +2436,7 @@ void LLIK::Solver::rebuildAllChains() if (data_pair.second->isActive()) { mActiveJoints.push_back(data_pair.second); + data_pair.second->flagForHarvest(); } } } @@ -2524,18 +2593,18 @@ LLQuaternion LLIK::Solver::getJointWorldRot(S16 joint_id) const return rot; } -void LLIK::Solver::reconfigureJoint(S16 joint_id, const LLVector3& local_pos, const LLVector3& bone, const Constraint::ptr_t& constraint) +void LLIK::Solver::resetJointGeometry(S16 joint_id, const Constraint::ptr_t& constraint) { joint_map_t::iterator itr = mSkeleton.find(joint_id); if (itr == mSkeleton.end()) { - LL_WARNS("Puppet") << "failed reconfigure unknown joint_id=" << joint_id << LL_ENDL; + LL_WARNS("Puppet") << "failed update unknown joint_id=" << joint_id << LL_ENDL; return; } const Joint::ptr_t& joint = itr->second; - joint->reconfigure(local_pos, bone); + joint->resetFromInfo(); joint->setConstraint(constraint); - // Note: will need to call computeEffectorNormal() after all Joints are reconfigured. + // Note: will need to call computeReach() after all Joint geometries are reset. } void LLIK::Solver::buildChain(Joint::ptr_t joint, joint_list_t& chain, std::set<S16>& sub_bases) diff --git a/indra/llcharacter/llik.h b/indra/llcharacter/llik.h index 1d0778de91667402276bd3b2d0d68e7ee1ea371f..17bcba71f5ba59b1e619d8cdd9948634ea8cb81f 100644 --- a/indra/llcharacter/llik.h +++ b/indra/llcharacter/llik.h @@ -38,6 +38,8 @@ #include "v4math.h" #include "xform.h" +class LLJoint; + //#define DEBUG_LLIK_UNIT_TESTS namespace LLIK @@ -55,22 +57,27 @@ namespace LLIK class Solver; class Joint; -// local flags -constexpr U8 FLAG_LOCAL_POS = 1 << 0; -constexpr U8 FLAG_LOCAL_ROT = 1 << 1; -constexpr U8 FLAG_LOCAL_SCALE = 1 << 2; -constexpr U8 FLAG_DISABLE_CONSTRAINT = 1 << 3; - -// target flags -constexpr U8 FLAG_TARGET_POS = 1 << 4; -constexpr U8 FLAG_TARGET_ROT = 1 << 5; -constexpr U8 FLAG_HAS_DELEGATED = 1 << 6; // EXPERIMENTAL - -constexpr U8 MASK_POS = FLAG_TARGET_POS | FLAG_LOCAL_POS; -constexpr U8 MASK_ROT = FLAG_TARGET_ROT | FLAG_LOCAL_ROT; +// config flags +constexpr U8 CONFIG_FLAG_LOCAL_POS = 1 << 0; +constexpr U8 CONFIG_FLAG_LOCAL_ROT = 1 << 1; +constexpr U8 CONFIG_FLAG_LOCAL_SCALE = 1 << 2; +constexpr U8 CONFIG_FLAG_DISABLE_CONSTRAINT = 1 << 3; +constexpr U8 CONFIG_FLAG_TARGET_POS = 1 << 4; +constexpr U8 CONFIG_FLAG_TARGET_ROT = 1 << 5; +constexpr U8 CONFIG_FLAG_HAS_DELEGATED = 1 << 6; // EXPERIMENTAL + +constexpr U8 IK_FLAG_LOCAL_ROT = 1 << 1; // IK has adjusted local_rot +constexpr U8 IK_FLAG_ACTIVE = 1 << 5; +constexpr U8 IK_FLAG_LOCAL_ROT_LOCKED = 1 << 7; // local_rot is locked during IK + +constexpr U8 MASK_POS = CONFIG_FLAG_TARGET_POS | CONFIG_FLAG_LOCAL_POS; +constexpr U8 MASK_ROT = CONFIG_FLAG_TARGET_ROT | CONFIG_FLAG_LOCAL_ROT; constexpr U8 MASK_TRANSFORM = MASK_POS | MASK_ROT; -constexpr U8 MASK_LOCAL = FLAG_LOCAL_POS | FLAG_LOCAL_ROT | FLAG_DISABLE_CONSTRAINT; -constexpr U8 MASK_TARGET = FLAG_TARGET_POS | FLAG_TARGET_ROT; +constexpr U8 MASK_LOCAL = CONFIG_FLAG_LOCAL_POS | CONFIG_FLAG_LOCAL_ROT | CONFIG_FLAG_DISABLE_CONSTRAINT; +constexpr U8 MASK_TARGET = CONFIG_FLAG_TARGET_POS | CONFIG_FLAG_TARGET_ROT; + +// this mask relates to LLJointState::Usage enum +constexpr U8 MASK_JOINT_STATE_USAGE = CONFIG_FLAG_LOCAL_POS | CONFIG_FLAG_LOCAL_ROT | CONFIG_FLAG_LOCAL_SCALE; constexpr F32 IK_DEFAULT_ACCEPTABLE_ERROR = 5.0e-4f; // half millimeter @@ -349,25 +356,28 @@ class Joint { public: // local info is in parent-frame - bool hasLocalPos() const { return (mFlags & FLAG_LOCAL_POS) > 0; } - bool hasLocalRot() const { return (mFlags & FLAG_LOCAL_ROT) > 0; } - bool constraintIsDisabled() const { return (mFlags & FLAG_DISABLE_CONSTRAINT) > 0; } + bool hasLocalPos() const { return (mFlags & CONFIG_FLAG_LOCAL_POS) > 0; } + bool hasLocalRot() const { return (mFlags & CONFIG_FLAG_LOCAL_ROT) > 0; } + bool hasLocalScale() const { return (mFlags & CONFIG_FLAG_LOCAL_SCALE) > 0; } + bool constraintIsDisabled() const { return (mFlags & CONFIG_FLAG_DISABLE_CONSTRAINT) > 0; } void setLocalPos(const LLVector3& pos); void setLocalRot(const LLQuaternion& rot); - void disableConstraint() { mFlags |= FLAG_DISABLE_CONSTRAINT; } + void setLocalScale(const LLVector3& scale); + void disableConstraint() { mFlags |= CONFIG_FLAG_DISABLE_CONSTRAINT; } const LLVector3& getLocalPos() const { return mLocalPos; } const LLQuaternion& getLocalRot() const { return mLocalRot; } + const LLVector3& getLocalScale() const { return mLocalScale; } // target info is in skeleton root-frame - bool hasTargetPos() const { return (mFlags & FLAG_TARGET_POS) > 0; } - bool hasTargetRot() const { return (mFlags & FLAG_TARGET_ROT) > 0; } + bool hasTargetPos() const { return (mFlags & CONFIG_FLAG_TARGET_POS) > 0; } + bool hasTargetRot() const { return (mFlags & CONFIG_FLAG_TARGET_ROT) > 0; } void setTargetPos(const LLVector3& pos); void setTargetRot(const LLQuaternion& rot); const LLVector3& getTargetPos() const { return mTargetPos; } const LLQuaternion& getTargetRot() const { return mTargetRot; } - void delegate() { mFlags |= FLAG_HAS_DELEGATED; } // EXPERIMENTAL - bool hasDelegated() const { return (mFlags & FLAG_HAS_DELEGATED) > 0; } // EXPERIMENTAL + void delegate() { mFlags |= CONFIG_FLAG_HAS_DELEGATED; } // EXPERIMENTAL + bool hasDelegated() const { return (mFlags & CONFIG_FLAG_HAS_DELEGATED) > 0; } // EXPERIMENTAL U8 getFlags() const { return mFlags; } @@ -376,6 +386,7 @@ class Joint private: LLVector3 mLocalPos; LLQuaternion mLocalRot; + LLVector3 mLocalScale; LLVector3 mTargetPos; LLQuaternion mTargetRot; U8 mFlags = 0; // per-feature bits @@ -384,7 +395,8 @@ class Joint using ptr_t = std::shared_ptr<Joint>; using child_vec_t = std::vector<ptr_t>; - Joint(S16 id, const LLVector3& local_pos, const LLVector3& bone); + Joint(LLJoint* info); + void resetFromInfo(); void addChild(const ptr_t& child); void setParent(const ptr_t& parent); @@ -392,7 +404,7 @@ class Joint void relaxRotationsRecursively(F32 blend_factor); F32 recursiveComputeLongestChainLength(F32 length) const; - void reconfigure(const LLVector3& local_pos, const LLVector3& bone); + void updateGeometry(const LLVector3& local_pos, const LLVector3& bone); LLVector3 computeEndTargetPos() const; LLVector3 computeWorldTipOffset() const; @@ -415,6 +427,8 @@ class Joint void setLocalPos(const LLVector3& pos); void setWorldRot(const LLQuaternion& rot); void setLocalRot(const LLQuaternion& new_local_rot); + void setLocalScale(const LLVector3& scale); + LLVector3 getPreScaledLocalPos() const; void adjustWorldRot(const LLQuaternion& adjustment); void shiftPos(const LLVector3& shift); @@ -424,9 +438,10 @@ class Joint LLVector3 getTargetPos() const { return mConfig->getTargetPos(); } const Config* getConfig() const { return mConfig; } - bool hasPosTarget() const { return (mConfigFlags & FLAG_TARGET_POS) > 0; } - bool hasRotTarget() const { return (mConfigFlags & FLAG_TARGET_ROT) > 0; } + bool hasPosTarget() const { return (mConfigFlags & CONFIG_FLAG_TARGET_POS) > 0; } + bool hasRotTarget() const { return (mConfigFlags & CONFIG_FLAG_TARGET_ROT) > 0; } U8 getConfigFlags() const { return mConfigFlags; } + U8 getHarvestFlags() const { return (mConfigFlags | mIkFlags) & MASK_LOCAL; } void resetFlags(); void lockLocalRot(const LLQuaternion& local_rot); @@ -439,16 +454,17 @@ class Joint ptr_t getSingleActiveChild(); const LLVector3& getBone() const { return mBone; } const LLVector3& getLocalPos() const { return mLocalPos; } + const LLVector3& getLocalScale() const { return mLocalScale; } F32 getBoneLength() const { return mBone.length(); } F32 getLocalPosLength() const { return mLocalPosLength; } ptr_t getParent() { return mParent; } - void activate() { mIsActive = true; } - bool isActive() const { return mIsActive; } - bool hasDisabledConstraint() const { return (mConfigFlags & FLAG_DISABLE_CONSTRAINT) > 0; } + void activate() { mIkFlags |= IK_FLAG_ACTIVE; } + bool isActive() const { return mIkFlags & IK_FLAG_ACTIVE; } + bool hasDisabledConstraint() const { return (mConfigFlags & CONFIG_FLAG_DISABLE_CONSTRAINT) > 0; } // Joint::mLocalRot is considered "locked" when its mConfigFlag's FLAG_LOCAL_ROT bit is set - bool localRotLocked() const { return (mConfigFlags & FLAG_LOCAL_ROT) > 0; } + bool localRotLocked() const { return (mIkFlags & IK_FLAG_LOCAL_ROT_LOCKED) > 0; } size_t getNumChildren() const { return mChildren.size(); } @@ -457,6 +473,10 @@ class Joint void twistTowardTargets(const std::vector<LLVector3>& local_targets, const std::vector<LLVector3>& world_targets); void untwist(); + // We call flagForHarvest() when we expect the joint to be updated by IK + // so we know to harvest its mLocalRot later. + void flagForHarvest() { mIkFlags |= IK_FLAG_LOCAL_ROT; } + #ifdef DEBUG_LLIK_UNIT_TESTS void dumpConfig() const; void dumpState() const; @@ -471,7 +491,6 @@ class Joint protected: std::vector<ptr_t> mChildren; //List of joint_ids attached to this one. - LLVector3 mDefaultLocalPos; // default pos in parent-frame LLVector3 mLocalPos; // current pos in parent-frame LLVector3 mPos; // pos in world-frame // The fundamental position formula is: @@ -483,6 +502,8 @@ class Joint // The fundamental orientations formula is: // mRot = mLocalRot * mParent->mRot + LLVector3 mLocalScale; + LLVector3 mBone; // There is another fundamental formula: // world_end_pos = mPos + mBone * mRot @@ -492,10 +513,17 @@ class Joint F32 mLocalPosLength = 0.0f; // cached copy of mLocalPos.length() S16 mID = -1; + // From LLIK::Joint's prespective the LLJoint stores the default + // non-animated geometry of the Joint, which occasionally needs to + // be known during IK calculations. LLJoint was implemented way back, + // when we were adding raw pointers and we haven't rewritten that logic + // yet, so to make its raw-pointer nature more clear we call it mInfoPtr. + const LLJoint* mInfoPtr; + const Config* mConfig = nullptr; // pointer into Solver::mJointConfigs U8 mConfigFlags = 0; // cache of mConfig->mFlags - bool mIsActive; + U8 mIkFlags = 0; // flags for IK calculations }; @@ -523,7 +551,11 @@ class Solver LLVector3 computeReach(S16 to_id, S16 from_id) const; // Add a Joint to the skeleton. - void addJoint(S16 joint_id, S16 parent_id, const LLVector3& local_pos, const LLVector3& bone, const Constraint::ptr_t& constraint); + void addJoint( + S16 joint_id, + S16 parent_id, + LLJoint* info_ptr, + const Constraint::ptr_t& constraint); // apply configs and return 'true' if something changed bool updateJointConfigs(const joint_config_map_t& configs); @@ -560,7 +592,7 @@ class Solver LLVector3 getJointWorldEndPos(S16 joint_id) const; LLQuaternion getJointWorldRot(S16 joint_id) const; - void reconfigureJoint(S16 joint_id, const LLVector3& local_pos, const LLVector3& bone, const Constraint::ptr_t& constraint); + void resetJointGeometry(S16 joint_id, const Constraint::ptr_t& constraint); void enableDebugIfPossible(); // will be possible when DEBUG_LLIK_UNIT_TESTS defined diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index c4c47744775148c917d9e0bf422fe6b1cde9538a..dfb7e021fa8593ceedf919036ece5a33b430609f 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -261,7 +261,7 @@ LLJoint *LLJoint::findJoint( const std::string &name ) if (name == getName()) return this; - for (joints_t::iterator iter = mChildren.begin(); + for (joints_t::const_iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { LLJoint* joint = *iter; @@ -329,7 +329,7 @@ void LLJoint::removeAllChildren() //-------------------------------------------------------------------- // getNumChildren() //-------------------------------------------------------------------- -U32 LLJoint::getNumChildren() +U32 LLJoint::getNumChildren() const { //return of 0 indicates an end effector, > 1 a leaf and 1 a normal joint. return mChildren.size(); @@ -338,7 +338,7 @@ U32 LLJoint::getNumChildren() //-------------------------------------------------------------------- // getPosition() //-------------------------------------------------------------------- -const LLVector3& LLJoint::getPosition() +const LLVector3& LLJoint::getPosition() const { return mXform.getPosition(); } @@ -786,7 +786,7 @@ LLVector3 LLJoint::getWorldPosition() //----------------------------------------------------------------------------- // getLastWorldPosition() //----------------------------------------------------------------------------- -LLVector3 LLJoint::getLastWorldPosition() +LLVector3 LLJoint::getLastWorldPosition() const { return mXform.getWorldPosition(); } @@ -822,7 +822,7 @@ void LLJoint::setWorldPosition( const LLVector3& pos ) //-------------------------------------------------------------------- // getRotation() //-------------------------------------------------------------------- -const LLQuaternion& LLJoint::getRotation() +const LLQuaternion& LLJoint::getRotation() const { return mXform.getRotation(); } @@ -891,7 +891,7 @@ void LLJoint::setWorldRotation( const LLQuaternion& rot ) //-------------------------------------------------------------------- // getScale() //-------------------------------------------------------------------- -const LLVector3& LLJoint::getScale() +const LLVector3& LLJoint::getScale() const { return mXform.getScale(); } @@ -1036,7 +1036,7 @@ void LLJoint::updateWorldMatrix() //-------------------------------------------------------------------- // getSkinOffset() //-------------------------------------------------------------------- -const LLVector3 &LLJoint::getSkinOffset() +const LLVector3 &LLJoint::getSkinOffset() const { return mSkinOffset; } @@ -1050,27 +1050,5 @@ void LLJoint::setSkinOffset( const LLVector3& offset ) mSkinOffset = offset; } - -//----------------------------------------------------------------------------- -// clampRotation() -//----------------------------------------------------------------------------- -void LLJoint::clampRotation(LLQuaternion old_rot, LLQuaternion new_rot) -{ - LLVector3 main_axis(1.f, 0.f, 0.f); - - for (joints_t::iterator iter = mChildren.begin(); - iter != mChildren.end(); ++iter) - { - LLJoint* joint = *iter; - if (joint->isAnimatable()) - { - main_axis = joint->getPosition(); - main_axis.normVec(); - // only care about first animatable child - break; - } - } -} - // End diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 3b452e0476aba3f079a9074b5a1146828aeec4ac..5d6c2b3ba7c8f625a0d9f84fe3ce71b8c24d7c04 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -236,10 +236,10 @@ class LLJoint void removeAllChildren(); //Tells us if this is a normal joint, leaf, or end effector - U32 getNumChildren(); + U32 getNumChildren() const; // get/set local position - const LLVector3& getPosition(); + const LLVector3& getPosition() const; void setPosition( const LLVector3& pos, bool apply_attachment_overrides = false ); // Tracks the default position defined by the skeleton @@ -252,11 +252,11 @@ class LLJoint // get/set world position LLVector3 getWorldPosition(); - LLVector3 getLastWorldPosition(); + LLVector3 getLastWorldPosition() const; void setWorldPosition( const LLVector3& pos ); // get/set local rotation - const LLQuaternion& getRotation(); + const LLQuaternion& getRotation() const; void setRotation( const LLQuaternion& rot ); // get/set world rotation @@ -265,7 +265,7 @@ class LLJoint void setWorldRotation( const LLQuaternion& rot ); // get/set local scale - const LLVector3& getScale(); + const LLVector3& getScale() const; void setScale( const LLVector3& scale, bool apply_attachment_overrides = false ); // get/set world matrix @@ -282,13 +282,11 @@ class LLJoint void updateWorldMatrix(); // get/set skin offset - const LLVector3 &getSkinOffset(); + const LLVector3 &getSkinOffset() const; void setSkinOffset( const LLVector3 &offset); LLXformMatrix *getXform() { return &mXform; } - void clampRotation(LLQuaternion old_rot, LLQuaternion new_rot); - virtual BOOL isAnimatable() const { return TRUE; } void addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ); diff --git a/indra/llcharacter/tests/llik_test.cpp b/indra/llcharacter/tests/llik_test.cpp index 58c782224e7ffec9beacb07ec410eb633c6edb69..5a4ecafdd85456698fab591135391144b3b5c902 100644 --- a/indra/llcharacter/tests/llik_test.cpp +++ b/indra/llcharacter/tests/llik_test.cpp @@ -27,6 +27,7 @@ */ #include "../llik.h" +#include "../lljoint.h" #include "../test/lltut.h" #include <iostream> #include <cmath> @@ -762,14 +763,6 @@ namespace tut template<> template<> void llik_object::test<7>() { - LLIKConstraintFactory factory; - S16 root_joint_id = 7; - LLIK::Solver solver; - constexpr F32 ACCEPTABLE_ERROR = 1.0e-3f; // one mm - solver.setAcceptableError(ACCEPTABLE_ERROR); - solver.setRootID(root_joint_id); - ensure_equals("LLIK::Solver::getRootID", solver.getRootID(), root_joint_id); - // Make a simple skeleton along the y-axis, where each child joint's local_pos // is a unit-vector from it's parent's origin. // @@ -782,26 +775,60 @@ namespace tut // x // - LLIK::Constraint::Info info; - LLIK::Constraint::ptr_t null_constraint = factory.getConstraint(info); - constexpr F32 BONE_LENGTH = 1.234f; constexpr F32 POS_LENGTH = 2.345f; S32 num_joints = 3; LLVector3 local_pos = POS_LENGTH * LLVector3::y_axis; LLVector3 bone = BONE_LENGTH * LLVector3::y_axis; - // Note: root joint should always have zero bone length, - // because IK will target its "end" not its "tip". - solver.addJoint(root_joint_id, root_joint_id-1, LLVector3::zero, LLVector3::zero, null_constraint); - S16 joint_id = root_joint_id + 1; - - for (S32 i = 0; i < num_joints; ++i) + // build LLJoint skeleton + std::vector<LLVector3> local_positions; + local_positions.push_back(LLVector3()); + local_positions.push_back(local_pos); + local_positions.push_back(local_pos); + local_positions.push_back(local_pos); + + std::vector<LLVector3> local_ends; + local_ends.push_back(LLVector3()); + local_ends.push_back(bone); + local_ends.push_back(bone); + local_ends.push_back(bone); + + std::vector<LLJoint*> joints; + LLJoint* parent_joint = nullptr; + S32 joint_id = 7; + for (S32 i = 0; i < S32(local_positions.size()); ++i) { - solver.addJoint(joint_id, joint_id-1, local_pos, bone, null_constraint); + LLJoint* joint = new LLJoint("foo", parent_joint); + joints.push_back(joint); + joints[i]->setIsBone(true); + joints[i]->setJointNum(joint_id); + joints[i]->setPosition(local_positions[i]); + joints[i]->setEnd(local_ends[i]); + parent_joint = joints[i]; ++joint_id; } - S16 last_joint_id = joint_id - 1; + + LLIKConstraintFactory factory; + S16 root_joint_id = 7; + LLIK::Solver solver; + constexpr F32 ACCEPTABLE_ERROR = 1.0e-3f; // one mm + solver.setAcceptableError(ACCEPTABLE_ERROR); + solver.setRootID(root_joint_id); + ensure_equals("LLIK::Solver::getRootID", solver.getRootID(), root_joint_id); + + // build solver skeleton + LLIK::Constraint::Info info; + LLIK::Constraint::ptr_t null_constraint = factory.getConstraint(info); + S16 ik_joint_id = root_joint_id; + S16 parent_ik_joint_id = -1; + for (S16 i = 0; i < S16(joints.size()); ++i) + { + solver.addJoint(ik_joint_id, parent_ik_joint_id, joints[i], null_constraint); + parent_ik_joint_id = ik_joint_id; + ++ik_joint_id; + } + S16 last_joint_id = ik_joint_id - 1; F32 reach = solver.computeReach(root_joint_id, last_joint_id).length(); F32 expected_reach = num_joints * POS_LENGTH + BONE_LENGTH; @@ -856,6 +883,11 @@ namespace tut F32 max_error = solver.solve(); ensure("LLIK::Solver reachable target sans-constraints after moving root", max_error < ACCEPTABLE_ERROR); } + // cleanup LLJoints + for (auto joint: joints) + { + delete joint; + } } // LLIK::Solver : unconstrained vs constrained @@ -863,7 +895,6 @@ namespace tut void llik_object::test<8>() { LLIKConstraintFactory factory; - S16 joint_id = 0; constexpr F32 ACCEPTABLE_ERROR = 3.0e-3f; // Consider the following chain of Joints: @@ -899,36 +930,54 @@ namespace tut // 3--. Z // We will test each case. + // build LLJoint skeleton + std::vector<LLVector3> local_positions; + local_positions.push_back(LLVector3()); + local_positions.push_back(LLVector3::y_axis); + local_positions.push_back(2.0f * LLVector3::y_axis); + local_positions.push_back(2.0f * LLVector3::y_axis); + + std::vector<LLVector3> local_ends; + local_ends.push_back(LLVector3()); + local_ends.push_back(2.0f * LLVector3::y_axis); + local_ends.push_back(2.0f * LLVector3::y_axis); + local_ends.push_back(LLVector3::y_axis); + + std::vector<LLJoint*> joints; + LLJoint* parent_joint = nullptr; + for (S32 i = 0; i < S32(local_positions.size()); ++i) + { + LLJoint* joint = new LLJoint("foo", parent_joint); + joint->setIsBone(true); + joint->setJointNum(i); + joint->setPosition(local_positions[i]); + joint->setEnd(local_ends[i]); + parent_joint = joint; + joints.push_back(joint); + } + { // unconstrained LLIK::Solver solver; solver.setAcceptableError(ACCEPTABLE_ERROR); - solver.setRootID(joint_id); + solver.setRootID(0); + // build solver skeleton LLIK::Constraint::Info info; LLIK::Constraint::ptr_t null_constraint = factory.getConstraint(info); + for (S16 i = 0; i < S16(joints.size()); ++i) + { + solver.addJoint(i, i-1, joints[i], null_constraint); + } + S16 last_joint_id = joints.size() - 1; - // Note: addJoint() API is: - // Solver::addJoint(joint_id, parent_id, local_pos, bone, constraint) - - // root joint has zero local_pos - solver.addJoint(joint_id, joint_id-1, 0.0f * LLVector3::y_axis, 1.0f * LLVector3::y_axis, null_constraint); - ++joint_id; - - solver.addJoint(joint_id, joint_id-1, 1.0f * LLVector3::y_axis, 2.0f * LLVector3::y_axis, null_constraint); - ++joint_id; - solver.addJoint(joint_id, joint_id-1, 2.0f * LLVector3::y_axis, 2.0f * LLVector3::y_axis, null_constraint); - ++joint_id; - solver.addJoint(joint_id, joint_id-1, 2.0f * LLVector3::y_axis, 1.0f * LLVector3::y_axis, null_constraint); - ++joint_id; - - S16 last_joint_id = joint_id - 1; - + // configure a target for end-effector LLIK::Joint::Config config; config.setTargetPos(3.0f * LLVector3::x_axis - 1.0f * LLVector3::y_axis); LLIK::Solver::joint_config_map_t configs; configs.insert({last_joint_id, config}); - solver.updateJointConfigs(configs); + + // solve F32 max_error = solver.solve(); ensure("LLIK::Solver reachable target sans-constraints should have low error", max_error < ACCEPTABLE_ERROR); } @@ -941,15 +990,16 @@ namespace tut // Z LLIK::Solver solver; solver.setAcceptableError(ACCEPTABLE_ERROR); - solver.setRootID(joint_id); + solver.setRootID(0); LLIK::Constraint::Info info; F32 del = 0.2f; - // root joint doesn't move + // build solver skeleton LLIK::Constraint::Info info_A; LLIK::Constraint::ptr_t null_constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, 0.0f * LLVector3::y_axis, 1.0f * LLVector3::y_axis, null_constraint); + S16 joint_id = 0; + solver.addJoint(joint_id, joint_id-1, joints[joint_id], null_constraint); ++joint_id; LLIK::Constraint::Info info_CW; @@ -959,11 +1009,10 @@ namespace tut info_CW.mFloats.push_back(-0.5f * F_PI - del); // min_bend info_CW.mFloats.push_back(-0.5f * F_PI + del); // max_bend LLIK::Constraint::ptr_t right_turn_CW = factory.getConstraint(info_CW); - solver.addJoint(joint_id, joint_id-1, 1.0f * LLVector3::y_axis, 2.0f * LLVector3::y_axis, right_turn_CW); + solver.addJoint(joint_id, joint_id-1, joints[joint_id], right_turn_CW); ++joint_id; - LLIK::Constraint::Info info_C; - solver.addJoint(joint_id, joint_id-1, 2.0f * LLVector3::y_axis, 2.0f * LLVector3::y_axis, right_turn_CW); + solver.addJoint(joint_id, joint_id-1, joints[joint_id], right_turn_CW); ++joint_id; LLIK::Constraint::Info info_CCW; @@ -973,20 +1022,25 @@ namespace tut info_CCW.mFloats.push_back(0.5f * F_PI - del); // min_bend info_CCW.mFloats.push_back(0.5f * F_PI + del); // max_bend LLIK::Constraint::ptr_t right_turn_CCW = factory.getConstraint(info_CCW); - solver.addJoint(joint_id, joint_id-1, 2.0f * LLVector3::y_axis, 1.0f * LLVector3::y_axis, right_turn_CCW); - ++joint_id; - - S16 last_joint_id = joint_id - 1; + solver.addJoint(joint_id, joint_id-1, joints[joint_id], right_turn_CCW); + // configure a target for end-effector LLIK::Joint::Config config; config.setTargetPos(3.0f * LLVector3::x_axis - 1.0f * LLVector3::y_axis); LLIK::Solver::joint_config_map_t configs; - configs.insert({last_joint_id, config}); - + configs.insert({joint_id, config}); //solver.enableDebugIfPossible(); solver.updateJointConfigs(configs); + + // solve F32 max_error = solver.solve(); ensure("LLIK::Solver reachable target with constraints should have low error", max_error < ACCEPTABLE_ERROR); + + } + // cleanup LLJoints + for (auto joint: joints) + { + delete joint; } } @@ -994,19 +1048,9 @@ namespace tut template<> template<> void llik_object::test<9>() { - LLIKConstraintFactory factory; - LLIK::Constraint::Info info; - LLIK::Constraint::ptr_t null_constraint = factory.getConstraint(info); - - S16 joint_id = 0; - LLIK::Solver solver; - constexpr F32 ACCEPTABLE_ERROR = 1.0e-3f; // one mm - solver.setAcceptableError(ACCEPTABLE_ERROR); - solver.setRootID(joint_id); - // We'll start with a simple skeleton like this: two "arms" // joined at a "neck" and a "spine" to the "root", - // where each joint local_pos/bone is equal length... + // where each joint local_pos/bone is of equal length... // // <---(9)<--(8)<--(7,4)-->(5)-->(6)---> // ^ @@ -1025,56 +1069,109 @@ namespace tut // ... and we'll specify reachable endpoints for (3), (6) and (9) // to see if it can reach a solution. + S32 num_spine_joints = 4; + S32 num_arm_joints = 3; + + // build LLJoint skeleton F32 bone_length = 1.0f; + std::vector<LLVector3> local_positions; + local_positions.push_back(LLVector3()); + local_positions.push_back(bone_length * LLVector3::y_axis); // 1 + local_positions.push_back(bone_length * LLVector3::y_axis); + local_positions.push_back(bone_length * LLVector3::y_axis); + local_positions.push_back(bone_length * LLVector3::y_axis); // 4 + local_positions.push_back(bone_length * LLVector3::x_axis); + local_positions.push_back(bone_length * LLVector3::x_axis); // 6 + local_positions.push_back(bone_length * LLVector3::y_axis); // 7 + local_positions.push_back(-bone_length * LLVector3::x_axis); + local_positions.push_back(-bone_length * LLVector3::x_axis); // 9 + + std::vector<LLVector3> local_ends; + local_ends.push_back(LLVector3()); + local_ends.push_back(bone_length * LLVector3::y_axis); // 1 + local_ends.push_back(bone_length * LLVector3::y_axis); + local_ends.push_back(bone_length * LLVector3::y_axis); // 3 + local_ends.push_back(bone_length * LLVector3::x_axis); // 4 + local_ends.push_back(bone_length * LLVector3::x_axis); + local_ends.push_back(bone_length * LLVector3::x_axis); // 6 + local_ends.push_back(-bone_length * LLVector3::x_axis); // 7 + local_ends.push_back(-bone_length * LLVector3::x_axis); + local_ends.push_back(-bone_length * LLVector3::x_axis); // 9 + S16 joint_id = 0; + std::vector<LLJoint*> joints; + LLJoint* parent_joint = nullptr; // spine - S32 num_spine_joints = 4; for (S32 i = 0; i < num_spine_joints; ++i) { - LLVector3 local_pos = bone_length * LLVector3::y_axis; - LLVector3 bone = local_pos; - solver.addJoint(joint_id, joint_id-1, local_pos, bone, null_constraint); + LLJoint* joint = new LLJoint("foo", parent_joint); + joint->setIsBone(true); + joint->setJointNum(joint_id); + joint->setPosition(local_positions[joint_id]); + joint->setEnd(local_ends[joint_id]); + parent_joint = joint; + joints.push_back(joint); ++joint_id; } - - S16 neck_id = joint_id - 1; - S16 parent_joint_id = neck_id; - // right arm - S32 num_arm_joints = 3; + LLJoint* neck_joint = parent_joint; + for (S32 i = 0; i < num_arm_joints; ++i) { - // first joint is special - LLVector3 local_pos = bone_length * LLVector3::y_axis; - LLVector3 bone = bone_length * LLVector3::x_axis; - solver.addJoint(joint_id, parent_joint_id, local_pos, bone, null_constraint); - parent_joint_id = joint_id; + LLJoint* joint = new LLJoint("foo", parent_joint); + joint->setIsBone(true); + joint->setJointNum(joint_id); + joint->setPosition(local_positions[joint_id]); + joint->setEnd(local_ends[joint_id]); + parent_joint = joint; + joints.push_back(joint); ++joint_id; } - for (S32 i = 1; i < num_arm_joints; ++i) + // left arm + parent_joint = neck_joint; + for (S32 i = 0; i < num_arm_joints; ++i) { - LLVector3 local_pos = bone_length * LLVector3::x_axis; - LLVector3 bone = local_pos; - solver.addJoint(joint_id, parent_joint_id, local_pos, bone, null_constraint); - parent_joint_id = joint_id; + LLJoint* joint = new LLJoint("foo", parent_joint); + joint->setIsBone(true); + joint->setJointNum(joint_id); + joint->setPosition(local_positions[joint_id]); + joint->setEnd(local_ends[joint_id]); + parent_joint = joint; + joints.push_back(joint); ++joint_id; } - S16 right_hand_id = joint_id - 1; - // left-arm - parent_joint_id = neck_id; + LLIKConstraintFactory factory; + LLIK::Constraint::Info info; + LLIK::Constraint::ptr_t null_constraint = factory.getConstraint(info); + + LLIK::Solver solver; + constexpr F32 ACCEPTABLE_ERROR = 1.0e-3f; // one mm + solver.setAcceptableError(ACCEPTABLE_ERROR); + solver.setRootID(joint_id); + + // build solver skeleton + // spine + joint_id = 0; + for (S32 i = 0; i < num_spine_joints; ++i) + { + solver.addJoint(joint_id, joint_id-1, joints[joint_id], null_constraint); + ++joint_id; + } + S16 neck_id = joint_id - 1; + // right arm + S16 parent_joint_id = neck_id; + for (S32 i = 0; i < num_arm_joints; ++i) { - // first joint is special - LLVector3 local_pos = bone_length * LLVector3::y_axis; - LLVector3 bone = - bone_length * LLVector3::x_axis; - solver.addJoint(joint_id, parent_joint_id, local_pos, bone, null_constraint); + solver.addJoint(joint_id, parent_joint_id, joints[joint_id], null_constraint); parent_joint_id = joint_id; ++joint_id; } - for (S32 i = 1; i < num_arm_joints; ++i) + S16 right_hand_id = joint_id - 1; + // left-arm + parent_joint_id = neck_id; + for (S32 i = 0; i < num_arm_joints; ++i) { - LLVector3 local_pos = - bone_length * LLVector3::x_axis; - LLVector3 bone = local_pos; - solver.addJoint(joint_id, parent_joint_id, local_pos, bone, null_constraint); + solver.addJoint(joint_id, parent_joint_id, joints[joint_id], null_constraint); parent_joint_id = joint_id; ++joint_id; } @@ -1135,6 +1232,11 @@ namespace tut error = dist_vec(solver.getJointWorldEndPos(left_hand_id), left_hand_pos); ensure("LLIK::Solver LeftHand should reach target", error < allowable_error); } + // cleanup LLJoints + for (auto joint: joints) + { + delete joint; + } } #ifdef ENABLE_FAILING_UNIT_TESTS @@ -1405,7 +1507,7 @@ namespace tut } #endif // ENABLE_FAILING_UNIT_TESTS - void build_skeleton_arm(LLIKConstraintFactory& factory, LLIK::Solver& solver, bool with_fingers=true) + void build_skeleton_arm(std::vector<LLJoint*>& joints, LLIKConstraintFactory& factory, LLIK::Solver& solver, bool with_fingers=true) { // This builds arm+hand+fingers skeleton based on the default SL avatar. @@ -1428,8 +1530,17 @@ namespace tut { LLVector3 local_position = LLVector3::zero; LLVector3 bone(0.0f,0.0f,0.08757f); + + LLJoint* joint = new LLJoint("Pelvis", nullptr); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::ptr_t null_constraint = factory.getConstraint(LLIK::Constraint::Info()); - solver.addJoint(joint_id, -1, local_position, bone, null_constraint); + + solver.addJoint(joint_id, -1, joint, null_constraint); } ++joint_id; @@ -1437,6 +1548,14 @@ namespace tut { LLVector3 local_position(0.0f,0.0f,0.08757f); LLVector3 bone(-0.014445f,0.0f,0.213712f); + + LLJoint* joint = new LLJoint("Torso", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::TWIST_LIMITED_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1444,7 +1563,8 @@ namespace tut info.mFloats.push_back(-0.0628319f); // min_twist info.mFloats.push_back(0.0628319f); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1452,6 +1572,14 @@ namespace tut { LLVector3 local_position(-0.015318f,0.0f,0.213712f); LLVector3 bone(-0.01f,0.0f,0.2151); + + LLJoint* joint = new LLJoint("Chest", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::TWIST_LIMITED_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1459,7 +1587,8 @@ namespace tut info.mFloats.push_back(-0.0628319f); // min_twist info.mFloats.push_back(0.0628319f); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1467,12 +1596,21 @@ namespace tut { LLVector3 local_position(-0.021f,0.123583f,0.165f); LLVector3 bone(0.0f,0.10349f,0.0f); + + LLJoint* joint = new LLJoint("Collar", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::SIMPLE_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis info.mFloats.push_back(0.15708f); // cone_angle LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1480,6 +1618,14 @@ namespace tut { LLVector3 local_position(0.0f,0.10349f,0.0f); LLVector3 bone(0.0f,0.260152f,0.0f); + + LLJoint* joint = new LLJoint("Shoulder", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::TWIST_LIMITED_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1488,7 +1634,8 @@ namespace tut info.mFloats.push_back(-1.25664f); // min_twist info.mFloats.push_back(1.7952f); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1496,6 +1643,14 @@ namespace tut { LLVector3 local_position(0.0f,0.260152f,0.0f); LLVector3 bone(0.0f,0.2009f,0.0f); + + LLJoint* joint = new LLJoint("Elbow", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::ELBOW_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1505,7 +1660,8 @@ namespace tut info.mFloats.push_back(-0.785398f); // min_twist info.mFloats.push_back(2.35619f); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } //S16 ELBOW_INDEX = joint_id; ++joint_id; @@ -1514,6 +1670,14 @@ namespace tut { LLVector3 local_position(0.0f,0.2009f,0.0f); LLVector3 bone(0.01274f,0.09898f,0.0147f); + + LLJoint* joint = new LLJoint("Wrist", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::TWIST_LIMITED_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1521,9 +1685,10 @@ namespace tut info.mFloats.push_back(-0.05f); // min_twist info.mFloats.push_back(0.05f); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } - S16 WRIST_INDEX = joint_id; + //S16 WRIST_INDEX = joint_id; ++joint_id; if (!with_fingers) @@ -1535,6 +1700,14 @@ namespace tut { LLVector3 local_position(0.01274f,0.09898f,0.0147f); LLVector3 bone(-0.00098f,0.0392f,-0.00588f); + + LLJoint* joint = new LLJoint("Middle1", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::DOUBLE_LIMITED_HINGE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1544,7 +1717,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_pitch info.mFloats.push_back(0.942478f); // max_pitch LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, WRIST_INDEX, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1552,6 +1726,14 @@ namespace tut { LLVector3 local_position(-0.00098f,0.0392f,-0.00588f); LLVector3 bone(-0.00098,0.04802,-0.00784); + + LLJoint* joint = new LLJoint("Middle2", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::KNEE_CONSTRAINT; LLVector3 forward_axis = local_position; @@ -1561,7 +1743,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_bend info.mFloats.push_back(1.5708f); // max_bend LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1569,6 +1752,14 @@ namespace tut { LLVector3 local_position(-0.00098f,0.04802f,-0.00784f); LLVector3 bone(-0.00196f,0.03234f,-0.00588f); + + LLJoint* joint = new LLJoint("Middle3", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::KNEE_CONSTRAINT; LLVector3 forward_axis = local_position; @@ -1578,7 +1769,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_bend info.mFloats.push_back(1.25664f); // max_bend LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } //S16 MIDDLE_END_INDEX = joint_id; ++joint_id; @@ -1587,6 +1779,14 @@ namespace tut { LLVector3 local_position(0.03724f,0.09506f,0.0147f); LLVector3 bone(0.01666f,0.03528f,-0.00588f); + + LLJoint* joint = new LLJoint("Index1", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::DOUBLE_LIMITED_HINGE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1596,7 +1796,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_pitch info.mFloats.push_back(1.39626f); // max_pitch LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, WRIST_INDEX, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1604,6 +1805,14 @@ namespace tut { LLVector3 local_position(0.01666f,0.03528f,-0.00588f); LLVector3 bone(0.01372f,0.03136f,-0.00588f); + + LLJoint* joint = new LLJoint("Index2", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::KNEE_CONSTRAINT; LLVector3 forward_axis = local_position; @@ -1613,7 +1822,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_bend info.mFloats.push_back(1.5708f); // max_bend LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1621,6 +1831,14 @@ namespace tut { LLVector3 local_position(0.01372f,0.03136f,-0.00588f); LLVector3 bone(0.01078f,0.0245f,-0.00392f); + + LLJoint* joint = new LLJoint("Index3", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::KNEE_CONSTRAINT; LLVector3 forward_axis = local_position; @@ -1630,7 +1848,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_bend info.mFloats.push_back(1.25664f); // max_bend LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } //S16 INDEX_END_INDEX = joint_id; ++joint_id; @@ -1639,6 +1858,14 @@ namespace tut { LLVector3 local_position(-0.0098f,0.09702f,0.00882f); LLVector3 bone(-0.01274f,0.03724f,-0.00784f); + + LLJoint* joint = new LLJoint("Ring1", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::DOUBLE_LIMITED_HINGE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1648,7 +1875,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_pitch info.mFloats.push_back(1.39626f); // max_pitch LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, WRIST_INDEX, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1656,6 +1884,14 @@ namespace tut { LLVector3 local_position(-0.01274f,0.03724f,-0.00784f); LLVector3 bone(-0.01274f,0.0392f,-0.00882f); + + LLJoint* joint = new LLJoint("Ring2", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::KNEE_CONSTRAINT; LLVector3 forward_axis = local_position; @@ -1665,7 +1901,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_bend info.mFloats.push_back(1.5708f); // max_bend LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1673,6 +1910,14 @@ namespace tut { LLVector3 local_position(-0.01274f,0.0392f,-0.00882f); LLVector3 bone(-0.0098f,0.02744f,-0.00588f); + + LLJoint* joint = new LLJoint("Ring3", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::KNEE_CONSTRAINT; LLVector3 forward_axis = local_position; @@ -1682,7 +1927,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_bend info.mFloats.push_back(1.25664f); // max_bend LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } //S16 RING_END_INDEX = joint_id; ++joint_id; @@ -1691,6 +1937,14 @@ namespace tut { LLVector3 local_position(-0.03038f,0.0931f,0.00294f); LLVector3 bone(-0.02352f,0.0245f,-0.00588f); + + LLJoint* joint = new LLJoint("Pinky1", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::DOUBLE_LIMITED_HINGE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1700,7 +1954,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_pitch info.mFloats.push_back(1.39626f); // max_pitch LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, WRIST_INDEX, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1708,6 +1963,14 @@ namespace tut { LLVector3 local_position(-0.02352f,0.0245f,-0.00588f); LLVector3 bone(-0.0147f,0.01764f,-0.00392f); + + LLJoint* joint = new LLJoint("Pinky2", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::KNEE_CONSTRAINT; LLVector3 forward_axis = local_position; @@ -1717,7 +1980,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_bend info.mFloats.push_back(1.5708f); // max_bend LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1725,6 +1989,14 @@ namespace tut { LLVector3 local_position(-0.0147f,0.01764f,-0.00392f); LLVector3 bone(-0.01274f,0.01568f,-0.00392f); + + LLJoint* joint = new LLJoint("Pinky3", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::KNEE_CONSTRAINT; LLVector3 forward_axis = local_position; @@ -1734,7 +2006,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_bend info.mFloats.push_back(1.25664f); // max_bend LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } //S16 PINKY_END_INDEX = joint_id; ++joint_id; @@ -1743,6 +2016,14 @@ namespace tut { LLVector3 local_position(0.03038f,0.02548f,0.00392f); LLVector3 bone(0.02744f,0.03136f,-0.00098f); + + LLJoint* joint = new LLJoint("Thumb1", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::DOUBLE_LIMITED_HINGE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1752,7 +2033,8 @@ namespace tut info.mFloats.push_back(-0.1f); // min_pitch info.mFloats.push_back(0.785398f); // max_pitch LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, WRIST_INDEX, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1760,6 +2042,14 @@ namespace tut { LLVector3 local_position(0.02744f,0.03136f,-0.00098f); LLVector3 bone(0.02254f,0.03038f,-0.00098f); + + LLJoint* joint = new LLJoint("Thumb2", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::KNEE_CONSTRAINT; LLVector3 forward_axis = local_position; @@ -1770,7 +2060,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_bend info.mFloats.push_back(0.942478f); // max_bend LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1778,6 +2069,14 @@ namespace tut { LLVector3 local_position(0.02254f,0.03038f,-0.00098f); LLVector3 bone(0.0147f,0.0245f,0.0f); + + LLJoint* joint = new LLJoint("Thumb3", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::KNEE_CONSTRAINT; LLVector3 forward_axis = local_position; @@ -1788,7 +2087,8 @@ namespace tut info.mFloats.push_back(0.0f); // min_bend info.mFloats.push_back(1.25664f); // max_bend LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } //S16 THUMB_END_INDEX = joint_id; } @@ -1805,7 +2105,8 @@ namespace tut solver.setAcceptableError(ACCEPTABLE_ERROR); bool with_fingers = false; - build_skeleton_arm(factory, solver, with_fingers); + std::vector<LLJoint*> joints; + build_skeleton_arm(joints, factory, solver, with_fingers); constexpr S16 WRIST_INDEX = 6; solver.addWristID(WRIST_INDEX); @@ -1835,8 +2136,15 @@ namespace tut solver.solve(); F32 error = dist_vec(solver.getJointWorldEndPos(ELBOW_INDEX), target_position); ensure("LLIK::Solver elbow should reach target", error < ACCEPTABLE_ERROR); + + // cleanup LLJoints + for (auto joint: joints) + { + delete joint; + } } + #ifdef ENABLE_FAILING_UNIT_TESTS // LLIK::Solver : wrist position and fingers // DISABLED: we're not trying to handle fingers yet @@ -1898,7 +2206,7 @@ namespace tut } #endif // ENABLE_FAILING_UNIT_TESTS - void build_skeleton_with_head_and_arm(LLIKConstraintFactory& factory, LLIK::Solver& solver) + void build_skeleton_with_head_and_arm(std::vector<LLJoint*>& joints, LLIKConstraintFactory& factory, LLIK::Solver& solver) { // This builds spine, head, and left arm based on the default SL avatar. // @@ -1920,8 +2228,17 @@ namespace tut { LLVector3 local_position = LLVector3::zero; LLVector3 bone(0.0f,0.0f,0.08757f); + + LLJoint* joint = new LLJoint("Pelvis", nullptr); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::ptr_t null_constraint = factory.getConstraint(LLIK::Constraint::Info()); - solver.addJoint(joint_id, -1, local_position, bone, null_constraint); + + solver.addJoint(joint_id, joint_id-1, joint, null_constraint); } ++joint_id; @@ -1929,6 +2246,14 @@ namespace tut { LLVector3 local_position(0.0f,0.0f,0.08757f); LLVector3 bone(-0.014445f,0.0f,0.213712f); + + LLJoint* joint = new LLJoint("Torso", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::TWIST_LIMITED_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1936,7 +2261,8 @@ namespace tut info.mFloats.push_back(-0.0628319f); // min_twist info.mFloats.push_back(0.0628319f); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1944,6 +2270,14 @@ namespace tut { LLVector3 local_position(-0.015318f,0.0f,0.213712f); LLVector3 bone(-0.01f,0.0f,0.2151); + + LLJoint* joint = new LLJoint("Chest", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::TWIST_LIMITED_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1951,7 +2285,8 @@ namespace tut info.mFloats.push_back(-0.0628319f); // min_twist info.mFloats.push_back(0.0628319f); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } S16 CHEST_ID = joint_id; ++joint_id; @@ -1960,6 +2295,14 @@ namespace tut { LLVector3 local_position(-0.01f, 0.0, 0.251f); LLVector3 bone(0.0f, 0.0f, 0.077f); + + LLJoint* joint = new LLJoint("Neck", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::TWIST_LIMITED_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1967,7 +2310,8 @@ namespace tut info.mFloats.push_back(-0.0628319f); // min_twist info.mFloats.push_back(0.0628319f); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1975,6 +2319,14 @@ namespace tut { LLVector3 local_position(0.0f, 0.0f, 0.076); LLVector3 bone(0.0f, 0.0f,0.079f); + + LLJoint* joint = new LLJoint("Head", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::TWIST_LIMITED_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -1982,7 +2334,8 @@ namespace tut info.mFloats.push_back(-0.0628319f); // min_twist info.mFloats.push_back(0.0628319f); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -1990,12 +2343,21 @@ namespace tut { LLVector3 local_position(-0.021f,0.123583f,0.165f); LLVector3 bone(0.0f,0.10349f,0.0f); + + LLJoint* joint = new LLJoint("Collar", joints[CHEST_ID]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::SIMPLE_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis info.mFloats.push_back(0.15708f); // cone_angle LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, CHEST_ID, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -2003,6 +2365,14 @@ namespace tut { LLVector3 local_position(0.0f,0.10349f,0.0f); LLVector3 bone(0.0f,0.260152f,0.0f); + + LLJoint* joint = new LLJoint("Shoulder", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::TWIST_LIMITED_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -2011,7 +2381,8 @@ namespace tut info.mFloats.push_back(-0.5f * F_PI); // min_twist info.mFloats.push_back(0.5f * F_PI); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } ++joint_id; @@ -2019,6 +2390,14 @@ namespace tut { LLVector3 local_position(0.0f,0.260152f,0.0f); LLVector3 bone(0.0f,0.2009f,0.0f); + + LLJoint* joint = new LLJoint("Elbow", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::ELBOW_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -2028,7 +2407,8 @@ namespace tut info.mFloats.push_back(-0.785398f); // min_twist info.mFloats.push_back(2.35619f); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } //S16 ELBOW_INDEX = joint_id; ++joint_id; @@ -2037,6 +2417,14 @@ namespace tut { LLVector3 local_position(0.0f,0.2009f,0.0f); LLVector3 bone(0.01274f,0.09898f,0.0147f); + + LLJoint* joint = new LLJoint("Wrist", joints[joint_id-1]); + joint->setIsBone(true); + joint->setJointNum(S32(joint_id)); + joint->setPosition(local_position); + joint->setEnd(bone); + joints.push_back(joint); + LLIK::Constraint::Info info; info.mType = LLIK::Constraint::Info::TWIST_LIMITED_CONE_CONSTRAINT; info.mVectors.push_back(local_position); // forward_axis @@ -2044,7 +2432,8 @@ namespace tut info.mFloats.push_back(-0.05f); // min_twist info.mFloats.push_back(0.05f); // max_twist LLIK::Constraint::ptr_t constraint = factory.getConstraint(info); - solver.addJoint(joint_id, joint_id-1, local_position, bone, constraint); + + solver.addJoint(joint_id, joint_id-1, joint, constraint); } S16 WRIST_ID = joint_id; @@ -2066,7 +2455,8 @@ namespace tut constexpr F32 ACCEPTABLE_ERROR = 2.0e-2f; solver.setAcceptableError(ACCEPTABLE_ERROR); - build_skeleton_with_head_and_arm(factory, solver); + std::vector<LLJoint*> joints; + build_skeleton_with_head_and_arm(joints, factory, solver); constexpr U16 WRIST_INDEX = 8; solver.addWristID(WRIST_INDEX); @@ -2095,5 +2485,11 @@ namespace tut ensure("LLIK::Solver wrist should reach target position", position_error < ACCEPTABLE_ERROR); constexpr F32 MIN_ANGLE_ERROR = 0.005f * F_PI; ensure("LLIK::Solver wrist should reach target orientation", LLQuaternion::almost_equal(target_orientation, actual_orientation, MIN_ANGLE_ERROR)); + + // cleanup LLJoints + for (auto joint: joints) + { + delete joint; + } } } diff --git a/indra/llcharacter/tests/lljoint_test.cpp b/indra/llcharacter/tests/lljoint_test.cpp index 617f31b0e46e5877198f25ce8263606ac93a9422..ba227d34550ba5618b06bf9e78817965dca039da 100644 --- a/indra/llcharacter/tests/lljoint_test.cpp +++ b/indra/llcharacter/tests/lljoint_test.cpp @@ -234,9 +234,6 @@ namespace tut 3) void updateWorldPRSParent(); 4) void updateWorldMatrix(); 5) LLXformMatrix *getXform() { return &mXform; } - 6) void setConstraintSilhouette(LLDynamicArray<LLVector3>& silhouette); - 7) void clampRotation(LLQuaternion old_rot, LLQuaternion new_rot); - */ } diff --git a/indra/newview/llpuppetevent.cpp b/indra/newview/llpuppetevent.cpp index d1a78e2297681e3246864a07f15a595612219050..066d59c69bc6d5e3bccb3188a6658bb125b704d5 100644 --- a/indra/newview/llpuppetevent.cpp +++ b/indra/newview/llpuppetevent.cpp @@ -177,7 +177,7 @@ void LLPuppetJointEvent::interpolate(F32 del, const LLPuppetJointEvent& A, const { mPosition = (1.0f - del) * A.mPosition + del * B.mPosition; } - if ((mMask & LLIK::FLAG_LOCAL_SCALE) && (B.mMask & LLIK::FLAG_LOCAL_SCALE)) + if ((mMask & LLIK::CONFIG_FLAG_LOCAL_SCALE) && (B.mMask & LLIK::CONFIG_FLAG_LOCAL_SCALE)) { mScale = (1.0f - del) * A.mScale + del * B.mScale; } @@ -187,19 +187,19 @@ void LLPuppetJointEvent::setRotation(const LLQuaternion& rotation) { mRotation = rotation; mRotation.normalize(); - mMask |= (mRefFrame == PARENT_FRAME ? LLIK::FLAG_LOCAL_ROT : LLIK::FLAG_TARGET_ROT); + mMask |= (mRefFrame == PARENT_FRAME ? LLIK::CONFIG_FLAG_LOCAL_ROT : LLIK::CONFIG_FLAG_TARGET_ROT); } void LLPuppetJointEvent::setPosition(const LLVector3& position) { mPosition = position; - mMask |= (mRefFrame == PARENT_FRAME ? LLIK::FLAG_LOCAL_POS : LLIK::FLAG_TARGET_POS); + mMask |= (mRefFrame == PARENT_FRAME ? LLIK::CONFIG_FLAG_LOCAL_POS : LLIK::CONFIG_FLAG_TARGET_POS); } void LLPuppetJointEvent::setScale(const LLVector3& scale) { mScale = scale; - mMask |= LLIK::FLAG_LOCAL_SCALE; + mMask |= LLIK::CONFIG_FLAG_LOCAL_SCALE; } void LLPuppetJointEvent::setJointID(S32 id) @@ -214,7 +214,7 @@ size_t LLPuppetJointEvent::getSize() const num_bytes += sizeof(S16) + sizeof(S8); // mJointID, mMask num_bytes += (mMask & LLIK::MASK_ROT) ? BYTES_PER_VEC_3 : 0; num_bytes += (mMask & LLIK::MASK_POS) ? BYTES_PER_VEC_3 : 0; - num_bytes += (mMask & LLIK::FLAG_LOCAL_SCALE) ? BYTES_PER_VEC_3 : 0; + num_bytes += (mMask & LLIK::CONFIG_FLAG_LOCAL_SCALE) ? BYTES_PER_VEC_3 : 0; return num_bytes; } @@ -238,7 +238,7 @@ size_t LLPuppetJointEvent::pack(U8* wptr) { offset += pack_vec3(wptr+offset, mPosition); } - if (mMask & LLIK::FLAG_LOCAL_SCALE) + if (mMask & LLIK::CONFIG_FLAG_LOCAL_SCALE) { offset += pack_vec3(wptr+offset, mScale); } @@ -248,7 +248,7 @@ size_t LLPuppetJointEvent::pack(U8* wptr) LL_CONT << " rot=" << mRotation; if (mMask & LLIK::MASK_POS) LL_CONT << " pos=" << mPosition; - if (mMask & LLIK::FLAG_LOCAL_SCALE) + if (mMask & LLIK::CONFIG_FLAG_LOCAL_SCALE) LL_CONT << " scale=" << mScale; LL_CONT << " raw=" << LLError::arraylogger(wptr, offset) << " in frame " << (S32)gFrameCount << LL_ENDL; @@ -272,7 +272,7 @@ size_t LLPuppetJointEvent::unpack(U8* wptr) { offset += unpack_vec3(wptr+offset, mPosition); } - if (mMask & LLIK::FLAG_LOCAL_SCALE) + if (mMask & LLIK::CONFIG_FLAG_LOCAL_SCALE) { offset += unpack_vec3(wptr+offset, mScale); } @@ -282,7 +282,7 @@ size_t LLPuppetJointEvent::unpack(U8* wptr) LL_CONT << " rot=" << mRotation; if (mMask & LLIK::MASK_POS) LL_CONT << " pos=" << mPosition; - if (mMask & LLIK::FLAG_LOCAL_SCALE) + if (mMask & LLIK::CONFIG_FLAG_LOCAL_SCALE) LL_CONT << " scale=" << mScale; LL_CONT << " raw=" << LLError::arraylogger(wptr, offset) << " in frame " << (S32)gFrameCount << LL_ENDL; diff --git a/indra/newview/llpuppetevent.h b/indra/newview/llpuppetevent.h index 62b0fdd686e8193b61fd9b78856f811b963dee1f..c2f7b2ebcbea80260bcae58d92651dc42f7fc640 100644 --- a/indra/newview/llpuppetevent.h +++ b/indra/newview/llpuppetevent.h @@ -59,7 +59,7 @@ class LLPuppetJointEvent void setPosition(const LLVector3& position); void setScale(const LLVector3& scale); void setJointID(S32 id); - void disableConstraint() { mMask |= LLIK::FLAG_DISABLE_CONSTRAINT; } + void disableConstraint() { mMask |= LLIK::CONFIG_FLAG_DISABLE_CONSTRAINT; } S16 getJointID() const { return mJointID; } LLQuaternion getRotation() const { return mRotation; } diff --git a/indra/newview/llpuppetmodule.cpp b/indra/newview/llpuppetmodule.cpp index 56c2f937b78996863032d9c314af3f3e4f9b7337..531bc9d795b472f82db5fc65f96dfbacd1dfdbba 100644 --- a/indra/newview/llpuppetmodule.cpp +++ b/indra/newview/llpuppetmodule.cpp @@ -193,17 +193,30 @@ void processJointData(const std::string& key, const LLSD& data) v.mV[VY] = value.get(1).asReal(); v.mV[VZ] = value.get(2).asReal(); + // sanity check Puppetry input + constexpr F32 MAX_PUPPETRY_INPUT = 10.0f; + constexpr F32 MIN_PUPPETRY_INPUT = -MAX_PUPPETRY_INPUT; + v.clamp(MIN_PUPPETRY_INPUT, MAX_PUPPETRY_INPUT); + + // Note: LLVector3::clamp() doesn't protect against NaN input + // so we explicitly check it here + F32 v_length_squared = v.lengthSquared(); + if (llisnan(v_length_squared)) + { + continue; + } + if ( param_name == "r" || param_name == "rotation" ) { LLQuaternion q; // Packed quaternions have the imaginary part (xyz) // copy the imaginary part memcpy(q.mQ, v.mV, 3 * sizeof(F32)); + // compute the real part - F32 imaginary_length_squared = q.mQ[VX] * q.mQ[VX] + q.mQ[VY] * q.mQ[VY] + q.mQ[VZ] * q.mQ[VZ]; - if (imaginary_length_squared > 1.0f) + if (v_length_squared > 1.0f) { - F32 imaginary_length = sqrtf(imaginary_length_squared); + F32 imaginary_length = sqrtf(v_length_squared); q.mQ[VX] /= imaginary_length; q.mQ[VY] /= imaginary_length; q.mQ[VZ] /= imaginary_length; @@ -211,7 +224,7 @@ void processJointData(const std::string& key, const LLSD& data) } else { - q.mQ[VW] = sqrtf(1.0f - imaginary_length_squared); + q.mQ[VW] = sqrtf(1.0f - v_length_squared); } joint_event.setRotation(q); } diff --git a/indra/newview/llpuppetmotion.cpp b/indra/newview/llpuppetmotion.cpp index bae5e948467867c77bc424e1b77c12f8dee9c678..46bd53f604bfcda98fe423d8e72a9c12e04ea2eb 100755 --- a/indra/newview/llpuppetmotion.cpp +++ b/indra/newview/llpuppetmotion.cpp @@ -713,19 +713,13 @@ LLSD LLPuppetMotion::getSkeletonData() return skeleton_sd; } -void LLPuppetMotion::reconfigureJoints() +void LLPuppetMotion::updateSkeletonGeometry() { - LLSD skeleton_sd; for (state_map_t::iterator iter=mJointStates.begin(); iter!=mJointStates.end(); ++iter) { S16 joint_id = iter->first; - LLPointer<LLJointState> joint_state = iter->second; - LLJoint* joint = joint_state->getJoint(); - LLVector3 local_pos_in_parent_frame = joint->getPosition().scaledVec(joint->getScale()); - LLVector3 bone_in_local_frame = joint->getEnd().scaledVec(joint->getScale()); LLIK::Constraint::ptr_t constraint = get_constraint_by_joint_id(joint_id); - mIKSolver.reconfigureJoint(joint_id, local_pos_in_parent_frame, bone_in_local_frame, constraint); - addJointToSkeletonData(skeleton_sd, joint, local_pos_in_parent_frame, bone_in_local_frame); + mIKSolver.resetJointGeometry(joint_id, constraint); } measureArmSpan(); } @@ -803,24 +797,26 @@ void LLPuppetMotion::solveIKAndHarvestResults(const LLIK::Solver::joint_config_m LLPuppetEvent broadcast_event; const LLIK::Solver::joint_list_t& active_joints = mIKSolver.getActiveJoints(); - LLVector3 pos; - LLQuaternion rot; for (auto joint: active_joints) { S16 id = joint->getID(); - U8 flags = joint->getConfigFlags(); - pos = joint->getLocalPos(); - rot = joint->getLocalRot(); + U8 flags = joint->getHarvestFlags(); if (local_puppetry) { LLPointer<LLJointState> joint_state = mJointStates[id]; - if (flags | LLIK::FLAG_LOCAL_POS) + U32 usage = U32(flags & LLIK::MASK_JOINT_STATE_USAGE); + joint_state->setUsage(usage); + if (flags & LLIK::CONFIG_FLAG_LOCAL_POS) + { + joint_state->setPosition(joint->getPreScaledLocalPos()); + } + if (flags & LLIK::CONFIG_FLAG_LOCAL_ROT) { - joint_state->setPosition(pos); + joint_state->setRotation(joint->getLocalRot()); } - if (flags | LLIK::FLAG_LOCAL_ROT) + if (flags & LLIK::CONFIG_FLAG_LOCAL_SCALE) { - joint_state->setRotation(rot); + joint_state->setScale(joint->getLocalScale()); } rememberPosedJoint(id, joint_state, now); } @@ -829,15 +825,21 @@ void LLPuppetMotion::solveIKAndHarvestResults(const LLIK::Solver::joint_config_m LLPuppetJointEvent joint_event; joint_event.setJointID(id); joint_event.setReferenceFrame(LLPuppetJointEvent::PARENT_FRAME); - if (flags | LLIK::FLAG_LOCAL_POS) + if (flags & LLIK::CONFIG_FLAG_LOCAL_POS) { - joint_event.setPosition(pos); + // we send positions with correct scale + // so they can be applied on the receiving end without modification + joint_event.setPosition(joint->getPreScaledLocalPos()); } - if (flags | LLIK::FLAG_LOCAL_ROT) + if (flags & LLIK::CONFIG_FLAG_LOCAL_ROT) { - joint_event.setRotation(rot); + joint_event.setRotation(joint->getLocalRot()); } - if (flags | LLIK::FLAG_DISABLE_CONSTRAINT) + if (flags & LLIK::CONFIG_FLAG_LOCAL_SCALE) + { + joint_event.setScale(joint->getLocalScale()); + } + if (flags & LLIK::CONFIG_FLAG_DISABLE_CONSTRAINT) { joint_event.disableConstraint(); } @@ -861,7 +863,7 @@ void LLPuppetMotion::applyEvent(const LLPuppetJointEvent& event, U64 now, LLIK:: LLIK::Joint::Config config; bool something_changed = false; U8 mask = event.getMask(); - bool local = (bool)(mask & LLIK::FLAG_LOCAL_ROT); + bool local = (bool)(mask & LLIK::CONFIG_FLAG_LOCAL_ROT); if (mask & LLIK::MASK_ROT) { if (local) @@ -876,19 +878,18 @@ void LLPuppetMotion::applyEvent(const LLPuppetJointEvent& event, U64 now, LLIK:: } if (mask & LLIK::MASK_POS) { - // don't forget to scale by 0.5*mArmSpan if (local) { - // TODO: figure out what to do about scale of local positions config.setLocalPos(event.getPosition()); } else { - config.setTargetPos(event.getPosition() * 0.5f * mArmSpan); + // don't forget to scale by 0.5*mArmSpan + config.setTargetPos(event.getPosition() * (0.5f * mArmSpan)); } something_changed = true; } - if (mask & LLIK::FLAG_DISABLE_CONSTRAINT) + if (mask & LLIK::CONFIG_FLAG_DISABLE_CONSTRAINT) { config.disableConstraint(); something_changed = true; @@ -902,7 +903,7 @@ void LLPuppetMotion::applyEvent(const LLPuppetJointEvent& event, U64 now, LLIK:: void LLPuppetMotion::updateFromExpression(Timestamp now) { - // Note: if we get here: mIsSelf must be true + // Note: if we get here mIsSelf must be true LLIK::Solver::joint_config_map_t configs; for(const auto& event: mExpressionEvents) { @@ -918,7 +919,7 @@ void LLPuppetMotion::updateFromExpression(Timestamp now) U8 mask = event.getMask(); if (mask & LLIK::MASK_ROT) { - if (mask & LLIK::FLAG_LOCAL_ROT) + if (mask & LLIK::CONFIG_FLAG_LOCAL_ROT) { config.setLocalRot(event.getRotation()); } @@ -930,19 +931,18 @@ void LLPuppetMotion::updateFromExpression(Timestamp now) } if (mask & LLIK::MASK_POS) { - // don't forget to scale by 0.5*mArmSpan - if (mask & LLIK::FLAG_LOCAL_POS) + if (mask & LLIK::CONFIG_FLAG_LOCAL_POS) { - // TODO: figure out what to do about scale of local positions config.setLocalPos(event.getPosition()); } else { - config.setTargetPos(event.getPosition() * 0.5f * mArmSpan); + // don't forget to scale by 0.5*mArmSpan + config.setTargetPos(event.getPosition() * (0.5f * mArmSpan)); } something_changed = true; } - if (mask & LLIK::FLAG_DISABLE_CONSTRAINT) + if (mask & LLIK::CONFIG_FLAG_DISABLE_CONSTRAINT) { config.disableConstraint(); something_changed = true; @@ -973,18 +973,26 @@ void LLPuppetMotion::applyBroadcastEvent(const LLPuppetJointEvent& event, Timest state_map_t::iterator state_iter = mJointStates.find(joint_id); if (state_iter != mJointStates.end()) { - U8 mask = event.getMask(); - llassert((mask & LLIK::MASK_TARGET) == 0); // broadcast event always in parent-frame - if (mask & LLIK::MASK_ROT) + LLPointer<LLJointState> joint_state = state_iter->second; + U8 flags = event.getMask(); + // Note: we assume broadcast event always in parent-frame + // e.g. (flags & LLIK::MASK_TARGET) == 0 + if (flags & LLIK::CONFIG_FLAG_LOCAL_POS) { - state_iter->second->setRotation(event.getRotation()); + // we expect received position to be scaled correctly + // so it can be applied without modification + joint_state->setPosition(event.getPosition()); } - if (mask & LLIK::MASK_POS) + if (flags & LLIK::CONFIG_FLAG_LOCAL_ROT) + { + joint_state->setRotation(event.getRotation()); + } + if (flags & LLIK::CONFIG_FLAG_LOCAL_SCALE) { - // Note: scale already set by broadcaster (e.g. 1.0 = 0.5*mArmSpan) - state_iter->second->setPosition(event.getPosition()); + joint_state->setScale(event.getScale()); } - rememberPosedJoint(joint_id, state_iter->second, now); + joint_state->setUsage((U32)(flags & LLIK::MASK_JOINT_STATE_USAGE)); + rememberPosedJoint(joint_id, joint_state, now); } } @@ -1280,15 +1288,12 @@ void LLPuppetMotion::collectJoints(LLJoint* joint) } // END HACK - LLPointer<LLJointState> joint_state = new LLJointState; - joint_state->setJoint(joint); - joint_state->setUsage(LLJointState::ROT | LLJointState::POS); + LLPointer<LLJointState> joint_state = new LLJointState(joint); S16 joint_id = joint->getJointNum(); mJointStates[joint_id] = joint_state; - LLVector3 local_pos_in_parent_frame = joint->getPosition().scaledVec(joint->getScale()); - LLVector3 bone_in_local_frame = joint->getEnd().scaledVec(joint->getScale()); + LLIK::Constraint::ptr_t constraint = get_constraint_by_joint_id(joint_id); - mIKSolver.addJoint(joint_id, parent_id, local_pos_in_parent_frame, bone_in_local_frame, constraint); + mIKSolver.addJoint(joint_id, parent_id, joint, constraint); // Recurse through the children of this joint and add them to our joint control list for (LLJoint::joints_t::iterator itr = joint->mChildren.begin(); diff --git a/indra/newview/llpuppetmotion.h b/indra/newview/llpuppetmotion.h index 8baffd2963d0a7f0870f5a1c20526bceb2385d76..1285f119a901be32402840beaaafb7d48b95ce1d 100755 --- a/indra/newview/llpuppetmotion.h +++ b/indra/newview/llpuppetmotion.h @@ -159,7 +159,7 @@ class LLPuppetMotion : BOOL canDeprecate() override { return FALSE; } void addJointToSkeletonData(LLSD& skeleton_sd, LLJoint* joint, const LLVector3& parent_rel_pos, const LLVector3& tip_rel_end_pos); LLSD getSkeletonData(); - void reconfigureJoints(); + void updateSkeletonGeometry(); private: void measureArmSpan(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 6237dd8f8ff4741a4728fa80f5127cf7489908f6..d3e43d06f486ba71ff06f8c56740b853330df16b 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2034,7 +2034,7 @@ void LLVOAvatar::buildCharacter() // Currently disabled for control avatars (animated objects), enabled for all others. if (mEnableDefaultMotions) { - startDefaultMotions(); + startDefaultMotions(); } //------------------------------------------------------------------------- @@ -8273,7 +8273,7 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) LLPuppetMotion::ptr_t puppet_motion = getPuppetMotion(); if (puppet_motion) { - puppet_motion->reconfigureJoints(); + puppet_motion->updateSkeletonGeometry(); LLEventPumps::instance().obtain("SkeletonUpdate").post(LLSD()); } } @@ -8289,7 +8289,7 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) // Fix for jellydoll initially invisible mNeedsImpostorUpdate = TRUE; mLastImpostorUpdateReason = 6; - } + } return changed; } @@ -10996,28 +10996,27 @@ void LLVOAvatar::setOverallAppearanceNormal() void LLVOAvatar::setOverallAppearanceJellyDoll() { if (isControlAvatar()) + { return; + } // stop current animations + for ( LLVOAvatar::AnimIterator anim_it= mPlayingAnimations.begin(); + anim_it != mPlayingAnimations.end(); + ++anim_it) { - for ( LLVOAvatar::AnimIterator anim_it= mPlayingAnimations.begin(); - anim_it != mPlayingAnimations.end(); - ++anim_it) { - { - stopMotion(anim_it->first, TRUE); - } + stopMotion(anim_it->first, TRUE); } } processAnimationStateChanges(); // Start any needed anims for jellydoll updateOverallAppearanceAnimations(); - + LLVector3 pelvis_pos = getJoint("mPelvis")->getPosition(); resetSkeleton(false); getJoint("mPelvis")->setPosition(pelvis_pos); - } void LLVOAvatar::setOverallAppearanceInvisible()