Newer
Older
/**
* @file llkeyframemotion.cpp
* @brief Implementation of LLKeyframeMotion class.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
*/
//-----------------------------------------------------------------------------
// Header Files
//-----------------------------------------------------------------------------
#include "linden_common.h"
#include "llmath.h"
#include "llanimationstates.h"
#include "llassetstorage.h"
#include "lldatapacker.h"
#include "llcharacter.h"
#include "llcriticaldamp.h"
#include "lldir.h"
#include "llendianswizzle.h"
#include "llkeyframemotion.h"
#include "llquantize.h"
#include "m3math.h"
#include "message.h"
Callum Prentice
committed
#include "llfilesystem.h"
//-----------------------------------------------------------------------------
// Static Definitions
//-----------------------------------------------------------------------------
Josh Bell
committed
LLKeyframeDataCache::keyframe_data_map_t LLKeyframeDataCache::sKeyframeDataMap;
//-----------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------
static F32 JOINT_LENGTH_K = 0.7f;
static S32 MAX_ITERATIONS = 20;
static S32 MIN_ITERATIONS = 1;
static S32 MIN_ITERATION_COUNT = 2;
static F32 MAX_PIXEL_AREA_CONSTRAINTS = 80000.f;
static F32 MIN_PIXEL_AREA_CONSTRAINTS = 1000.f;
static F32 MIN_ACCELERATION_SQUARED = 0.0005f * 0.0005f;
static F32 MAX_CONSTRAINTS = 10;
//-----------------------------------------------------------------------------
Josh Bell
committed
// JointMotionList
//-----------------------------------------------------------------------------
Josh Bell
committed
LLKeyframeMotion::JointMotionList::JointMotionList()
: mDuration(0.f),
mLoop(FALSE),
mLoopInPoint(0.f),
mLoopOutPoint(0.f),
mEaseInDuration(0.f),
mEaseOutDuration(0.f),
mBasePriority(LLJoint::LOW_PRIORITY),
mHandPose(LLHandMotion::HAND_POSE_SPREAD),
mMaxPriority(LLJoint::LOW_PRIORITY)
Josh Bell
committed
{
}
LLKeyframeMotion::JointMotionList::~JointMotionList()
{
for_each(mConstraints.begin(), mConstraints.end(), DeletePointer());
mConstraints.clear();
Steven Bennetts
committed
for_each(mJointMotionArray.begin(), mJointMotionArray.end(), DeletePointer());
mJointMotionArray.clear();
Josh Bell
committed
}
U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo()
{
S32 total_size = sizeof(JointMotionList);
Steven Bennetts
committed
for (U32 i = 0; i < getNumJointMotions(); i++)
Steven Bennetts
committed
LLKeyframeMotion::JointMotion* joint_motion_p = mJointMotionArray[i];
LL_INFOS() << "\tJoint " << joint_motion_p->mJointName << LL_ENDL;
if (joint_motion_p->mUsage & LLJointState::SCALE)
{
LL_INFOS() << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at "
<< joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << LL_ENDL;
total_size += joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey);
}
if (joint_motion_p->mUsage & LLJointState::ROT)
{
LL_INFOS() << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at "
<< joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << LL_ENDL;
total_size += joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey);
}
if (joint_motion_p->mUsage & LLJointState::POS)
{
LL_INFOS() << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at "
<< joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << LL_ENDL;
total_size += joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey);
}
}
LL_INFOS() << "Size: " << total_size << " bytes" << LL_ENDL;
return total_size;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// JointMotion class
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// JointMotion::update()
//-----------------------------------------------------------------------------
void LLKeyframeMotion::JointMotion::update(LLJointState* joint_state, F32 time, F32 duration)
{
// this value being 0 is the cause of https://jira.lindenlab.com/browse/SL-22678 but I haven't
// managed to get a stack to see how it got here. Testing for 0 here will stop the crash.
Steven Bennetts
committed
if ( joint_state == NULL )
Steven Bennetts
committed
}
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
U32 usage = joint_state->getUsage();
//-------------------------------------------------------------------------
// update scale component of joint state
//-------------------------------------------------------------------------
if ((usage & LLJointState::SCALE) && mScaleCurve.mNumKeys)
{
joint_state->setScale( mScaleCurve.getValue( time, duration ) );
}
//-------------------------------------------------------------------------
// update rotation component of joint state
//-------------------------------------------------------------------------
if ((usage & LLJointState::ROT) && mRotationCurve.mNumKeys)
{
joint_state->setRotation( mRotationCurve.getValue( time, duration ) );
}
//-------------------------------------------------------------------------
// update position component of joint state
//-------------------------------------------------------------------------
if ((usage & LLJointState::POS) && mPositionCurve.mNumKeys)
{
joint_state->setPosition( mPositionCurve.getValue( time, duration ) );
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LLKeyframeMotion class
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// LLKeyframeMotion()
// Class Constructor
//-----------------------------------------------------------------------------
LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id)
: LLMotion(id),
mJointMotionList(NULL),
mPelvisp(NULL),
mLastSkeletonSerialNum(0),
mLastUpdateTime(0.f),
mLastLoopedTime(0.f),
mAssetStatus(ASSET_UNDEFINED)
}
//-----------------------------------------------------------------------------
// ~LLKeyframeMotion()
// Class Destructor
//-----------------------------------------------------------------------------
LLKeyframeMotion::~LLKeyframeMotion()
{
Josh Bell
committed
for_each(mConstraints.begin(), mConstraints.end(), DeletePointer());
mConstraints.clear();
}
//-----------------------------------------------------------------------------
// create()
//-----------------------------------------------------------------------------
LLMotion *LLKeyframeMotion::create(const LLUUID &id)
{
return new LLKeyframeMotion(id);
}
Steven Bennetts
committed
//-----------------------------------------------------------------------------
// getJointState()
//-----------------------------------------------------------------------------
LLPointer<LLJointState>& LLKeyframeMotion::getJointState(U32 index)
{
Steven Bennetts
committed
return mJointStates[index];
}
//-----------------------------------------------------------------------------
Steven Bennetts
committed
//-----------------------------------------------------------------------------
LLJoint* LLKeyframeMotion::getJoint(U32 index)
{
Steven Bennetts
committed
LLJoint* joint = mJointStates[index]->getJoint();
//Commented out 06-28-11 by Aura.
//llassert_always (joint);
Steven Bennetts
committed
return joint;
}
//-----------------------------------------------------------------------------
// LLKeyframeMotion::onInitialize(LLCharacter *character)
//-----------------------------------------------------------------------------
LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *character)
{
mCharacter = character;
LLUUID* character_id;
// asset already loaded?
switch(mAssetStatus)
{
case ASSET_NEEDS_FETCH:
// request asset
mAssetStatus = ASSET_FETCHED;
#ifdef SHOW_DEBUG
LL_DEBUGS("Animation") << "Requesting data fetch for: " << mID << LL_ENDL;
character_id = new LLUUID(mCharacter->getID());
gAssetStorage->getAssetData(mID,
LLAssetType::AT_ANIMATION,
onLoadComplete,
(void *)character_id,
FALSE);
return STATUS_HOLD;
case ASSET_FETCHED:
return STATUS_HOLD;
case ASSET_FETCH_FAILED:
return STATUS_FAILURE;
case ASSET_LOADED:
return STATUS_SUCCESS;
default:
// we don't know what state the asset is in yet, so keep going
Callum Prentice
committed
// check keyframe cache first then file cache then asset request
break;
}
LLKeyframeMotion::JointMotionList* joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID());
if(joint_motion_list)
{
// motion already existed in cache, so grab it
mJointMotionList = joint_motion_list;
Steven Bennetts
committed
mJointStates.reserve(mJointMotionList->getNumJointMotions());
// don't forget to allocate joint states
// set up joint states to point to character joints
Steven Bennetts
committed
for(U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++)
Steven Bennetts
committed
JointMotion* joint_motion = mJointMotionList->getJointMotion(i);
if (LLJoint *joint = mCharacter->getJoint(joint_motion->mJointName))
Steven Bennetts
committed
LLPointer<LLJointState> joint_state = new LLJointState;
mJointStates.push_back(joint_state);
joint_state->setJoint(joint);
joint_state->setUsage(joint_motion->mUsage);
joint_state->setPriority(joint_motion->mPriority);
else
{
// add dummy joint state with no associated joint
mJointStates.push_back(new LLJointState);
}
}
mAssetStatus = ASSET_LOADED;
setupPose();
return STATUS_SUCCESS;
}
//-------------------------------------------------------------------------
// Load named file by concatenating the character prefix with the motion name.
// Load data into a buffer to be parsed.
//-------------------------------------------------------------------------
BOOL success = FALSE;
U8* anim_data = nullptr;
S32 anim_file_size = 0;
{

Rye Mutt
committed
LLFileSystem anim_file(mID, LLAssetType::AT_ANIMATION);
if (!anim_file.open() || !anim_file.getSize())
{
// request asset over network on next call to load
mAssetStatus = ASSET_NEEDS_FETCH;
return STATUS_HOLD;
}
else
{

Rye Mutt
committed
anim_file_size = anim_file.getSize();
anim_data = new(std::nothrow) U8[anim_file_size];
if (anim_data)
{
if (!success)
{
delete[] anim_data;
anim_data = nullptr;
LL_WARNS() << "Failed to read animation from cache. ID: " << mID << LL_ENDL;
LL_WARNS() << "Failed to allocate buffer: " << anim_file_size << " " << mID << LL_ENDL;
LL_WARNS() << "Can't open animation file " << mID << LL_ENDL;
mAssetStatus = ASSET_FETCH_FAILED;
return STATUS_FAILURE;
}
#ifdef SHOW_DEBUG
LL_DEBUGS() << "Loading keyframe data for: " << getName() << ":" << getID() << " (" << anim_file_size << " bytes)" << LL_ENDL;
LLDataPackerBinaryBuffer dp(anim_data, anim_file_size);
Brad Payne (Vir Linden)
committed
if (!deserialize(dp, getID()))
LL_WARNS() << "Failed to decode asset for animation " << getName() << ":" << getID() << LL_ENDL;
mAssetStatus = ASSET_FETCH_FAILED;
return STATUS_FAILURE;
}
delete []anim_data;
mAssetStatus = ASSET_LOADED;
return STATUS_SUCCESS;
}
//-----------------------------------------------------------------------------
// setupPose()
//-----------------------------------------------------------------------------
BOOL LLKeyframeMotion::setupPose()
{
// add all valid joint states to the pose
Steven Bennetts
committed
for (U32 jm=0; jm<mJointMotionList->getNumJointMotions(); jm++)
Steven Bennetts
committed
LLPointer<LLJointState> joint_state = getJointState(jm);
if ( joint_state->getJoint() )
Steven Bennetts
committed
addJointState( joint_state );
Josh Bell
committed
for (JointMotionList::constraint_list_t::iterator iter = mJointMotionList->mConstraints.begin();
iter != mJointMotionList->mConstraints.end(); ++iter)
{
JointConstraintSharedData* shared_constraintp = *iter;
JointConstraint* constraintp = new JointConstraint(shared_constraintp);
initializeConstraint(constraintp);
mConstraints.push_front(constraintp);
}
Josh Bell
committed
if (mJointMotionList->mConstraints.size())
{
mPelvisp = mCharacter->getJoint("mPelvis");
if (!mPelvisp)
{
return FALSE;
}
}
// setup loop keys
setLoopIn(mJointMotionList->mLoopInPoint);
setLoopOut(mJointMotionList->mLoopOutPoint);
return TRUE;
}
//-----------------------------------------------------------------------------
// LLKeyframeMotion::onActivate()
//-----------------------------------------------------------------------------
BOOL LLKeyframeMotion::onActivate()
{
// If the keyframe anim has an associated emote, trigger it.
if( mJointMotionList->mEmoteName.length() > 0 )
LLUUID emote_anim_id = gAnimLibrary.stringToAnimState(mJointMotionList->mEmoteName);
// don't start emote if already active to avoid recursion
if (!mCharacter->isMotionActive(emote_anim_id))
{
mCharacter->startMotion( emote_anim_id );
}
}
mLastLoopedTime = 0.f;
return TRUE;
}
//-----------------------------------------------------------------------------
// LLKeyframeMotion::onUpdate()
//-----------------------------------------------------------------------------
BOOL LLKeyframeMotion::onUpdate(F32 time, U8* joint_mask)
{
// llassert(time >= 0.f); // This will fire
time = llmax(0.f, time);
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
if (mJointMotionList->mLoop)
{
if (mJointMotionList->mDuration == 0.0f)
{
time = 0.f;
mLastLoopedTime = 0.0f;
}
else if (mStopped)
{
mLastLoopedTime = llmin(mJointMotionList->mDuration, mLastLoopedTime + time - mLastUpdateTime);
}
else if (time > mJointMotionList->mLoopOutPoint)
{
if ((mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint) == 0.f)
{
mLastLoopedTime = mJointMotionList->mLoopOutPoint;
}
else
{
mLastLoopedTime = mJointMotionList->mLoopInPoint +
fmod(time - mJointMotionList->mLoopOutPoint,
mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint);
}
}
else
{
mLastLoopedTime = time;
}
}
else
{
mLastLoopedTime = time;
}
applyKeyframes(mLastLoopedTime);
applyConstraints(mLastLoopedTime, joint_mask);
mLastUpdateTime = time;
return mLastLoopedTime <= mJointMotionList->mDuration;
}
//-----------------------------------------------------------------------------
// applyKeyframes()
//-----------------------------------------------------------------------------
void LLKeyframeMotion::applyKeyframes(F32 time)
{
Steven Bennetts
committed
llassert_always (mJointMotionList->getNumJointMotions() <= mJointStates.size());
for (U32 i=0; i<mJointMotionList->getNumJointMotions(); i++)
Steven Bennetts
committed
mJointMotionList->getJointMotion(i)->update(mJointStates[i],
time,
mJointMotionList->mDuration );
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
}
LLJoint::JointPriority* pose_priority = (LLJoint::JointPriority* )mCharacter->getAnimationData("Hand Pose Priority");
if (pose_priority)
{
if (mJointMotionList->mMaxPriority >= *pose_priority)
{
mCharacter->setAnimationData("Hand Pose", &mJointMotionList->mHandPose);
mCharacter->setAnimationData("Hand Pose Priority", &mJointMotionList->mMaxPriority);
}
}
else
{
mCharacter->setAnimationData("Hand Pose", &mJointMotionList->mHandPose);
mCharacter->setAnimationData("Hand Pose Priority", &mJointMotionList->mMaxPriority);
}
}
//-----------------------------------------------------------------------------
// applyConstraints()
//-----------------------------------------------------------------------------
void LLKeyframeMotion::applyConstraints(F32 time, U8* joint_mask)
{
//TODO: investigate replacing spring simulation with critically damped motion
// re-init constraints if skeleton has changed
if (mCharacter->getSkeletonSerialNum() != mLastSkeletonSerialNum)
{
mLastSkeletonSerialNum = mCharacter->getSkeletonSerialNum();
Josh Bell
committed
for (constraint_list_t::iterator iter = mConstraints.begin();
iter != mConstraints.end(); ++iter)
{
JointConstraint* constraintp = *iter;
initializeConstraint(constraintp);
}
Josh Bell
committed
for (constraint_list_t::iterator iter = mConstraints.begin();
iter != mConstraints.end(); ++iter)
{
JointConstraint* constraintp = *iter;
applyConstraint(constraintp, time, joint_mask);
}
}
//-----------------------------------------------------------------------------
// LLKeyframeMotion::onDeactivate()
//-----------------------------------------------------------------------------
void LLKeyframeMotion::onDeactivate()
{
Josh Bell
committed
for (constraint_list_t::iterator iter = mConstraints.begin();
iter != mConstraints.end(); ++iter)
{
JointConstraint* constraintp = *iter;
deactivateConstraint(constraintp);
}
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
}
//-----------------------------------------------------------------------------
// setStopTime()
//-----------------------------------------------------------------------------
// time is in seconds since character creation
void LLKeyframeMotion::setStopTime(F32 time)
{
LLMotion::setStopTime(time);
if (mJointMotionList->mLoop && mJointMotionList->mLoopOutPoint != mJointMotionList->mDuration)
{
F32 start_loop_time = mActivationTimestamp + mJointMotionList->mLoopInPoint;
F32 loop_fraction_time;
if (mJointMotionList->mLoopOutPoint == mJointMotionList->mLoopInPoint)
{
loop_fraction_time = 0.f;
}
else
{
loop_fraction_time = fmod(time - start_loop_time,
mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint);
}
mStopTimestamp = llmax(time,
(time - loop_fraction_time) + (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint) - getEaseOutDuration());
}
}
//-----------------------------------------------------------------------------
// initializeConstraint()
//-----------------------------------------------------------------------------
void LLKeyframeMotion::initializeConstraint(JointConstraint* constraint)
{
JointConstraintSharedData *shared_data = constraint->mSharedData;
S32 joint_num;
LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
Steven Bennetts
committed
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[0]);
F32 source_pos_offset = dist_vec(source_pos, cur_joint->getWorldPosition());
constraint->mTotalLength = constraint->mJointLengths[0] = dist_vec(cur_joint->getParent()->getWorldPosition(), source_pos);
// grab joint lengths
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
{
Steven Bennetts
committed
cur_joint = getJointState(shared_data->mJointStateIndices[joint_num])->getJoint();
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
if (!cur_joint)
{
return;
}
constraint->mJointLengths[joint_num] = dist_vec(cur_joint->getWorldPosition(), cur_joint->getParent()->getWorldPosition());
constraint->mTotalLength += constraint->mJointLengths[joint_num];
}
// store fraction of total chain length so we know how to shear the entire chain towards the goal position
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
{
constraint->mJointLengthFractions[joint_num] = constraint->mJointLengths[joint_num] / constraint->mTotalLength;
}
// add last step in chain, from final joint to constraint position
constraint->mTotalLength += source_pos_offset;
constraint->mSourceVolume = mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume);
constraint->mTargetVolume = mCharacter->findCollisionVolume(shared_data->mTargetConstraintVolume);
}
//-----------------------------------------------------------------------------
// activateConstraint()
//-----------------------------------------------------------------------------
void LLKeyframeMotion::activateConstraint(JointConstraint* constraint)
{
JointConstraintSharedData *shared_data = constraint->mSharedData;
constraint->mActive = TRUE;
S32 joint_num;
// grab ground position if we need to
if (shared_data->mConstraintTargetType == CONSTRAINT_TARGET_TYPE_GROUND)
{
LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
LLVector3 ground_pos_agent;
mCharacter->getGround(source_pos, ground_pos_agent, constraint->mGroundNorm);
constraint->mGroundPos = mCharacter->getPosGlobalFromAgent(ground_pos_agent + shared_data->mTargetConstraintOffset);
}
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
{
Steven Bennetts
committed
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
constraint->mPositions[joint_num] = (cur_joint->getWorldPosition() - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation();
}
constraint->mWeight = 1.f;
}
//-----------------------------------------------------------------------------
// deactivateConstraint()
//-----------------------------------------------------------------------------
void LLKeyframeMotion::deactivateConstraint(JointConstraint *constraintp)
{
if (constraintp->mSourceVolume)
{
constraintp->mSourceVolume->mUpdateXform = FALSE;
}
callum_linden
committed
if (constraintp->mSharedData->mConstraintTargetType != CONSTRAINT_TARGET_TYPE_GROUND)
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
{
if (constraintp->mTargetVolume)
{
constraintp->mTargetVolume->mUpdateXform = FALSE;
}
}
constraintp->mActive = FALSE;
}
//-----------------------------------------------------------------------------
// applyConstraint()
//-----------------------------------------------------------------------------
void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8* joint_mask)
{
JointConstraintSharedData *shared_data = constraint->mSharedData;
if (!shared_data) return;
LLVector3 positions[MAX_CHAIN_LENGTH];
const F32* joint_lengths = constraint->mJointLengths;
LLVector3 velocities[MAX_CHAIN_LENGTH - 1];
LLQuaternion old_rots[MAX_CHAIN_LENGTH];
S32 joint_num;
if (time < shared_data->mEaseInStartTime)
{
return;
}
if (time > shared_data->mEaseOutStopTime)
{
if (constraint->mActive)
{
deactivateConstraint(constraint);
}
return;
}
if (!constraint->mActive || time < shared_data->mEaseInStopTime)
{
activateConstraint(constraint);
}
Steven Bennetts
committed
LLJoint* root_joint = getJoint(shared_data->mJointStateIndices[shared_data->mChainLength]);
LLVector3 root_pos = root_joint->getWorldPosition();
// LLQuaternion root_rot =
root_joint->getParent()->getWorldRotation();
// LLQuaternion inv_root_rot = ~root_rot;
// LLVector3 current_source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
//apply underlying keyframe animation to get nominal "kinematic" joint positions
for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
{
Steven Bennetts
committed
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if (joint_mask[cur_joint->getJointNum()] >= (0xff >> (7 - getPriority())))
{
// skip constraint
return;
}
old_rots[joint_num] = cur_joint->getRotation();
Steven Bennetts
committed
cur_joint->setRotation(getJointState(shared_data->mJointStateIndices[joint_num])->getRotation());
}
LLVector3 keyframe_source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
LLVector3 target_pos;
switch(shared_data->mConstraintTargetType)
{
case CONSTRAINT_TARGET_TYPE_GROUND:
target_pos = mCharacter->getPosAgentFromGlobal(constraint->mGroundPos);
// LL_INFOS() << "Target Pos " << constraint->mGroundPos << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL;
case CONSTRAINT_TARGET_TYPE_BODY:
target_pos = mCharacter->getVolumePos(shared_data->mTargetConstraintVolume, shared_data->mTargetConstraintOffset);
break;
default:
break;
}
LLVector3 norm;
LLJoint *source_jointp = NULL;
LLJoint *target_jointp = NULL;
if (shared_data->mConstraintType == CONSTRAINT_TYPE_PLANE)
{
switch(shared_data->mConstraintTargetType)
{
case CONSTRAINT_TARGET_TYPE_GROUND:
case CONSTRAINT_TARGET_TYPE_BODY:
target_jointp = mCharacter->findCollisionVolume(shared_data->mTargetConstraintVolume);
if (target_jointp)
{
Aaron Brashears
committed
// *FIX: do proper normal calculation for stretched
// spheres (inverse transpose)
norm = target_pos - target_jointp->getWorldPosition();
}
if (norm.isExactlyZero())
{
source_jointp = mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume);
norm = -1.f * shared_data->mSourceConstraintOffset;
if (source_jointp)
{
norm = norm * source_jointp->getWorldRotation();
}
}
norm.normVec();
break;
default:
norm.clearVec();
break;
}
target_pos = keyframe_source_pos + (norm * ((target_pos - keyframe_source_pos) * norm));
}
if (constraint->mSharedData->mChainLength != 0 &&
dist_vec_squared(root_pos, target_pos) * 0.95f > constraint->mTotalLength * constraint->mTotalLength)
{
constraint->mWeight = LLSmoothInterpolation::lerp(constraint->mWeight, 0.f, 0.1f);
constraint->mWeight = LLSmoothInterpolation::lerp(constraint->mWeight, 1.f, 0.3f);
}
F32 weight = constraint->mWeight * ((shared_data->mEaseOutStopTime == 0.f) ? 1.f :
llmin(clamp_rescale(time, shared_data->mEaseInStartTime, shared_data->mEaseInStopTime, 0.f, 1.f),
clamp_rescale(time, shared_data->mEaseOutStartTime, shared_data->mEaseOutStopTime, 1.f, 0.f)));
LLVector3 source_to_target = target_pos - keyframe_source_pos;
callum_linden
committed
S32 max_iteration_count = ll_round(clamp_rescale(
mCharacter->getPixelArea(),
MAX_PIXEL_AREA_CONSTRAINTS,
MIN_PIXEL_AREA_CONSTRAINTS,
(F32)MAX_ITERATIONS,
(F32)MIN_ITERATIONS));
if (shared_data->mChainLength)
{
LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
if (!end_joint)
{
return;
}
LLQuaternion end_rot = end_joint->getWorldRotation();
// slam start and end of chain to the proper positions (rest of chain stays put)
positions[0] = lerp(keyframe_source_pos, target_pos, weight);
positions[shared_data->mChainLength] = root_pos;
// grab keyframe-specified positions of joints
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
{
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if (!cur_joint)
{
return;
}
LLVector3 kinematic_position = cur_joint->getWorldPosition() +
(source_to_target * constraint->mJointLengthFractions[joint_num]);
// convert intermediate joint positions to world coordinates
positions[joint_num] = ( constraint->mPositions[joint_num] * mPelvisp->getWorldRotation()) + mPelvisp->getWorldPosition();
F32 time_constant = 1.f / clamp_rescale(constraint->mFixupDistanceRMS, 0.f, 0.5f, 0.2f, 8.f);
// LL_INFOS() << "Interpolant " << LLSmoothInterpolation::getInterpolant(time_constant, FALSE) << " and fixup distance " << constraint->mFixupDistanceRMS << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL;
positions[joint_num] = lerp(positions[joint_num], kinematic_position,
LLSmoothInterpolation::getInterpolant(time_constant, FALSE));
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
}
S32 iteration_count;
for (iteration_count = 0; iteration_count < max_iteration_count; iteration_count++)
{
S32 num_joints_finished = 0;
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
{
// constraint to child
LLVector3 acceleration = (positions[joint_num - 1] - positions[joint_num]) *
(dist_vec(positions[joint_num], positions[joint_num - 1]) - joint_lengths[joint_num - 1]) * JOINT_LENGTH_K;
// constraint to parent
acceleration += (positions[joint_num + 1] - positions[joint_num]) *
(dist_vec(positions[joint_num + 1], positions[joint_num]) - joint_lengths[joint_num]) * JOINT_LENGTH_K;
if (acceleration.magVecSquared() < MIN_ACCELERATION_SQUARED)
{
num_joints_finished++;
}
velocities[joint_num - 1] = velocities[joint_num - 1] * 0.7f;
positions[joint_num] += velocities[joint_num - 1] + (acceleration * 0.5f);
velocities[joint_num - 1] += acceleration;
}
if ((iteration_count >= MIN_ITERATION_COUNT) &&
(num_joints_finished == shared_data->mChainLength - 1))
{
// LL_INFOS() << iteration_count << " iterations on " <<
// mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL;
break;
}
}
for (joint_num = shared_data->mChainLength; joint_num > 0; joint_num--)
{
Steven Bennetts
committed
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
Steven Bennetts
committed
LLJoint* child_joint = getJoint(shared_data->mJointStateIndices[joint_num - 1]);
Steven Bennetts
committed
LLQuaternion parent_rot = cur_joint->getParent()->getWorldRotation();
LLQuaternion cur_rot = cur_joint->getWorldRotation();
LLQuaternion fixup_rot;
LLVector3 target_at = positions[joint_num - 1] - positions[joint_num];
LLVector3 current_at;
// at bottom of chain, use point on collision volume, not joint position
if (joint_num == 1)
{
current_at = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset) -
cur_joint->getWorldPosition();
}
else
{
current_at = child_joint->getPosition() * cur_rot;
}
fixup_rot.shortestArc(current_at, target_at);
LLQuaternion target_rot = cur_rot * fixup_rot;
target_rot = target_rot * ~parent_rot;
if (weight != 1.f)
{
Steven Bennetts
committed
LLQuaternion cur_rot = getJointState(shared_data->mJointStateIndices[joint_num])->getRotation();
target_rot = nlerp(weight, cur_rot, target_rot);
}
Steven Bennetts
committed
getJointState(shared_data->mJointStateIndices[joint_num])->setRotation(target_rot);
cur_joint->setRotation(target_rot);
}
LLQuaternion end_local_rot = end_rot * ~end_joint->getParent()->getWorldRotation();
if (weight == 1.f)
{
Steven Bennetts
committed
getJointState(shared_data->mJointStateIndices[0])->setRotation(end_local_rot);
Steven Bennetts
committed
LLQuaternion cur_rot = getJointState(shared_data->mJointStateIndices[0])->getRotation();
getJointState(shared_data->mJointStateIndices[0])->setRotation(nlerp(weight, cur_rot, end_local_rot));
}
// save simulated positions in pelvis-space and calculate total fixup distance
constraint->mFixupDistanceRMS = 0.f;
F32 delta_time = llmax(0.02f, llabs(time - mLastUpdateTime));
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
{
LLVector3 new_pos = (positions[joint_num] - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation();
constraint->mFixupDistanceRMS += dist_vec_squared(new_pos, constraint->mPositions[joint_num]) / delta_time;
constraint->mPositions[joint_num] = new_pos;
}
constraint->mFixupDistanceRMS *= 1.f / (constraint->mTotalLength * (F32)(shared_data->mChainLength - 1));
constraint->mFixupDistanceRMS = (F32) sqrt(constraint->mFixupDistanceRMS);
//reset old joint rots
for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
{
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if (!cur_joint)
{
return;
}
cur_joint->setRotation(old_rots[joint_num]);
}
}
// simple positional constraint (pelvis only)
Steven Bennetts
committed
else if (getJointState(shared_data->mJointStateIndices[0])->getUsage() & LLJointState::POS)
Steven Bennetts
committed
LLPointer<LLJointState> current_joint_state = getJointState(shared_data->mJointStateIndices[0]);
LLQuaternion parent_rot = current_joint_state->getJoint()->getParent()->getWorldRotation();
Steven Bennetts
committed
current_joint_state->setPosition(current_joint_state->getJoint()->getPosition() + delta);
}
}
//-----------------------------------------------------------------------------
// deserialize()
//-----------------------------------------------------------------------------
Brad Payne (Vir Linden)
committed
BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id)
auto joint_motion_list = std::make_unique<LLKeyframeMotion::JointMotionList>();
//-------------------------------------------------------------------------
// get base priority
//-------------------------------------------------------------------------
S32 temp_priority;
U16 version;
U16 sub_version;
if (!dp.unpackU16(version, "version"))
{
Brad Payne (Vir Linden)
committed
LL_WARNS() << "can't read version number for animation " << asset_id << LL_ENDL;
return FALSE;
}
if (!dp.unpackU16(sub_version, "sub_version"))