summaryrefslogtreecommitdiff
path: root/indra/llcharacter/llkeyframewalkmotion.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcharacter/llkeyframewalkmotion.cpp')
-rw-r--r--indra/llcharacter/llkeyframewalkmotion.cpp319
1 files changed, 189 insertions, 130 deletions
diff --git a/indra/llcharacter/llkeyframewalkmotion.cpp b/indra/llcharacter/llkeyframewalkmotion.cpp
index d52eb89a5c..f814618fc1 100644
--- a/indra/llcharacter/llkeyframewalkmotion.cpp
+++ b/indra/llcharacter/llkeyframewalkmotion.cpp
@@ -2,25 +2,31 @@
* @file llkeyframewalkmotion.cpp
* @brief Implementation of LLKeyframeWalkMotion class.
*
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, 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.
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
- * 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.
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
- * 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
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
*
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
@@ -38,31 +44,32 @@
//-----------------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------------
-const F32 MAX_WALK_PLAYBACK_SPEED = 8.f; // max m/s for which we adjust walk cycle speed
+const F32 MAX_WALK_PLAYBACK_SPEED = 8.f; // max m/s for which we adjust walk cycle speed
-const F32 MIN_WALK_SPEED = 0.1f; // minimum speed at which we use velocity for down foot detection
-const F32 TIME_EPSILON = 0.001f; // minumum frame time
-const F32 MAX_TIME_DELTA = 2.f; // max two seconds a frame for calculating interpolation
-F32 SPEED_ADJUST_MAX_SEC = 2.f; // maximum adjustment to walk animation playback speed for a second
-F32 ANIM_SPEED_MAX = 1.5f; // absolute upper limit on animation speed
-const F32 DRIFT_COMP_MAX_TOTAL = 0.1f; // maximum drift compensation overall, in any direction
-const F32 DRIFT_COMP_MAX_SPEED = 4.f; // speed at which drift compensation total maxes out
+const F32 MIN_WALK_SPEED = 0.1f; // minimum speed at which we use velocity for down foot detection
+const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation
+F32 SPEED_ADJUST_MAX = 2.5f; // maximum adjustment of walk animation playback speed
+F32 SPEED_ADJUST_MAX_SEC = 3.f; // maximum adjustment to walk animation playback speed for a second
+F32 ANIM_SPEED_MAX = 10.0f; // absolute upper limit on animation speed
+F32 ANIM_SPEED_MIN = 0.0f; // absolute lower limit on animation speed
+const F32 DRIFT_COMP_MAX_TOTAL = 0.07f;//0.55f; // maximum drift compensation overall, in any direction
+const F32 DRIFT_COMP_MAX_SPEED = 4.f; // speed at which drift compensation total maxes out
const F32 MAX_ROLL = 0.6f;
-const F32 PELVIS_COMPENSATION_WIEGHT = 0.7f; // proportion of foot drift that is compensated by moving the avatar directly
-const F32 SPEED_ADJUST_TIME_CONSTANT = 0.1f; // time constant for speed adjustment interpolation
//-----------------------------------------------------------------------------
// LLKeyframeWalkMotion()
// Class Constructor
//-----------------------------------------------------------------------------
LLKeyframeWalkMotion::LLKeyframeWalkMotion(const LLUUID &id)
-: LLKeyframeMotion(id),
+ : LLKeyframeMotion(id),
+
mCharacter(NULL),
mCyclePhase(0.0f),
mRealTimeLast(0.0f),
mAdjTimeLast(0.0f),
mDownFoot(0)
-{}
+{
+}
//-----------------------------------------------------------------------------
@@ -70,7 +77,8 @@ LLKeyframeWalkMotion::LLKeyframeWalkMotion(const LLUUID &id)
// Class Destructor
//-----------------------------------------------------------------------------
LLKeyframeWalkMotion::~LLKeyframeWalkMotion()
-{}
+{
+}
//-----------------------------------------------------------------------------
@@ -141,12 +149,15 @@ BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask)
LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) :
LLMotion(id),
mLastTime(0.f),
+ mAvgCorrection(0.f),
+ mSpeedAdjust(0.f),
mAnimSpeed(0.f),
- mAdjustedSpeed(0.f),
+ mAvgSpeed(0.f),
mRelativeDir(0.f),
mAnkleOffset(0.f)
{
mName = "walk_adjust";
+
mPelvisState = new LLJointState;
}
@@ -178,16 +189,15 @@ LLMotion::LLMotionInitStatus LLWalkAdjustMotion::onInitialize(LLCharacter *chara
//-----------------------------------------------------------------------------
BOOL LLWalkAdjustMotion::onActivate()
{
+ mAvgCorrection = 0.f;
+ mSpeedAdjust = 0.f;
mAnimSpeed = 0.f;
- mAdjustedSpeed = 0.f;
+ mAvgSpeed = 0.f;
mRelativeDir = 1.f;
mPelvisState->setPosition(LLVector3::zero);
// store ankle positions for next frame
- mLastLeftFootGlobalPos = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition());
- mLastLeftFootGlobalPos.mdV[VZ] = 0.0;
-
- mLastRightFootGlobalPos = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition());
- mLastRightFootGlobalPos.mdV[VZ] = 0.0;
+ mLastLeftAnklePos = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition());
+ mLastRightAnklePos = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition());
F32 leftAnkleOffset = (mLeftAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
F32 rightAnkleOffset = (mRightAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
@@ -201,121 +211,164 @@ BOOL LLWalkAdjustMotion::onActivate()
//-----------------------------------------------------------------------------
BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
{
- // delta_time is guaranteed to be non zero
- F32 delta_time = llclamp(time - mLastTime, TIME_EPSILON, MAX_TIME_DELTA);
+ LLVector3 footCorrection;
+ LLVector3 vel = mCharacter->getCharacterVelocity() * mCharacter->getTimeDilation();
+ F32 deltaTime = llclamp(time - mLastTime, 0.f, MAX_TIME_DELTA);
mLastTime = time;
- // find the avatar motion vector in the XY plane
- LLVector3 avatar_velocity = mCharacter->getCharacterVelocity() * mCharacter->getTimeDilation();
- avatar_velocity.mV[VZ] = 0.f;
+ LLQuaternion inv_rotation = ~mPelvisJoint->getWorldRotation();
- F32 speed = llclamp(avatar_velocity.magVec(), 0.f, MAX_WALK_PLAYBACK_SPEED);
+ // get speed and normalize velocity vector
+ LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
+ F32 speed = llmin(vel.normVec(), MAX_WALK_PLAYBACK_SPEED);
+ mAvgSpeed = lerp(mAvgSpeed, speed, LLCriticalDamp::getInterpolant(0.2f));
- // grab avatar->world transforms
- LLQuaternion avatar_to_world_rot = mCharacter->getRootJoint()->getWorldRotation();
+ // calculate facing vector in pelvis-local space
+ // (either straight forward or back, depending on velocity)
+ LLVector3 localVel = vel * inv_rotation;
+ if (localVel.mV[VX] > 0.f)
+ {
+ mRelativeDir = 1.f;
+ }
+ else if (localVel.mV[VX] < 0.f)
+ {
+ mRelativeDir = -1.f;
+ }
- LLQuaternion world_to_avatar_rot(avatar_to_world_rot);
- world_to_avatar_rot.conjugate();
+ // calculate world-space foot drift
+ LLVector3 leftFootDelta;
+ LLVector3 leftFootWorldPosition = mLeftAnkleJoint->getWorldPosition();
+ LLVector3d leftFootGlobalPosition = mCharacter->getPosGlobalFromAgent(leftFootWorldPosition);
+ leftFootDelta.setVec(mLastLeftAnklePos - leftFootGlobalPosition);
+ mLastLeftAnklePos = leftFootGlobalPosition;
- LLVector3 foot_slip_vector;
+ LLVector3 rightFootDelta;
+ LLVector3 rightFootWorldPosition = mRightAnkleJoint->getWorldPosition();
+ LLVector3d rightFootGlobalPosition = mCharacter->getPosGlobalFromAgent(rightFootWorldPosition);
+ rightFootDelta.setVec(mLastRightAnklePos - rightFootGlobalPosition);
+ mLastRightAnklePos = rightFootGlobalPosition;
// find foot drift along velocity vector
- if (speed > MIN_WALK_SPEED)
- { // walking/running
-
- // calculate world-space foot drift
- // use global coordinates to seamlessly handle region crossings
- LLVector3d leftFootGlobalPosition = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition());
- leftFootGlobalPosition.mdV[VZ] = 0.0;
- LLVector3 leftFootDelta(leftFootGlobalPosition - mLastLeftFootGlobalPos);
- mLastLeftFootGlobalPos = leftFootGlobalPosition;
-
- LLVector3d rightFootGlobalPosition = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition());
- rightFootGlobalPosition.mdV[VZ] = 0.0;
- LLVector3 rightFootDelta(rightFootGlobalPosition - mLastRightFootGlobalPos);
- mLastRightFootGlobalPos = rightFootGlobalPosition;
-
- // get foot drift along avatar direction of motion
- F32 left_foot_slip_amt = leftFootDelta * avatar_velocity;
- F32 right_foot_slip_amt = rightFootDelta * avatar_velocity;
-
- // if right foot is pushing back faster than left foot...
- if (right_foot_slip_amt < left_foot_slip_amt)
- { //...use it to calculate optimal animation speed
- foot_slip_vector = rightFootDelta;
- }
+ if (mAvgSpeed > 0.1)
+ {
+ // walking/running
+ F32 leftFootDriftAmt = leftFootDelta * vel;
+ F32 rightFootDriftAmt = rightFootDelta * vel;
+
+ if (rightFootDriftAmt > leftFootDriftAmt)
+ {
+ footCorrection = rightFootDelta;
+ } else
+ {
+ footCorrection = leftFootDelta;
+ }
+ }
+ else
+ {
+ mAvgSpeed = ang_vel.magVec() * mAnkleOffset;
+ mRelativeDir = 1.f;
+
+ // standing/turning
+ // find the lower foot
+ if (leftFootWorldPosition.mV[VZ] < rightFootWorldPosition.mV[VZ])
+ {
+ // pivot on left foot
+ footCorrection = leftFootDelta;
+ }
else
- { // otherwise use the left foot
- foot_slip_vector = leftFootDelta;
+ {
+ // pivot on right foot
+ footCorrection = rightFootDelta;
}
+ }
+
+ // rotate into avatar coordinates
+ footCorrection = footCorrection * inv_rotation;
- // calculate ideal pelvis offset so that foot is glued to ground and damp towards it
- // this will soak up transient slippage
- //
- // FIXME: this interacts poorly with speed adjustment
- // mPelvisOffset compensates for foot drift by moving the avatar pelvis in the opposite
- // direction of the drift, up to a certain limited distance
- // but this will cause the animation playback rate calculation below to
- // kick in too slowly and sometimes start playing the animation in reverse.
-
- //mPelvisOffset -= PELVIS_COMPENSATION_WIEGHT * (foot_slip_vector * world_to_avatar_rot);//lerp(LLVector3::zero, -1.f * (foot_slip_vector * world_to_avatar_rot), LLCriticalDamp::getInterpolant(0.1f));
-
- ////F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL * (llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED);
- //F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL;
-
- //// clamp pelvis offset to a 90 degree arc behind the nominal position
- //// NB: this is an ADDITIVE amount that is accumulated every frame, so clamping it alone won't do the trick
- //// must clamp with absolute position of pelvis in mind
- //LLVector3 currentPelvisPos = mPelvisState->getJoint()->getPosition();
- //mPelvisOffset.mV[VX] = llclamp( mPelvisOffset.mV[VX], -drift_comp_max, drift_comp_max );
- //mPelvisOffset.mV[VY] = llclamp( mPelvisOffset.mV[VY], -drift_comp_max, drift_comp_max );
- //mPelvisOffset.mV[VZ] = 0.f;
- //
- //mLastRightFootGlobalPos += LLVector3d(mPelvisOffset * avatar_to_world_rot);
- //mLastLeftFootGlobalPos += LLVector3d(mPelvisOffset * avatar_to_world_rot);
-
- //foot_slip_vector -= mPelvisOffset;
-
- LLVector3 avatar_movement_dir = avatar_velocity;
- avatar_movement_dir.normalize();
-
- // planted foot speed is avatar velocity - foot slip amount along avatar movement direction
- F32 foot_speed = speed - ((foot_slip_vector * avatar_movement_dir) / delta_time);
-
- // multiply animation playback rate so that foot speed matches avatar speed
- F32 min_speed_multiplier = clamp_rescale(speed, 0.f, 1.f, 0.f, 0.1f);
- F32 desired_speed_multiplier = llclamp(speed / foot_speed, min_speed_multiplier, ANIM_SPEED_MAX);
-
- // blend towards new speed adjustment value
- F32 new_speed_adjust = lerp(mAdjustedSpeed, desired_speed_multiplier, LLCriticalDamp::getInterpolant(SPEED_ADJUST_TIME_CONSTANT));
-
- // limit that rate at which the speed adjustment changes
- F32 speedDelta = llclamp(new_speed_adjust - mAdjustedSpeed, -SPEED_ADJUST_MAX_SEC * delta_time, SPEED_ADJUST_MAX_SEC * delta_time);
- mAdjustedSpeed += speedDelta;
-
- // modulate speed by dot products of facing and velocity
- // so that if we are moving sideways, we slow down the animation
- // and if we're moving backward, we walk backward
- // do this at the end to be more responsive to direction changes instead of in the above speed calculations
- F32 directional_factor = (avatar_movement_dir * world_to_avatar_rot).mV[VX];
-
- mAnimSpeed = mAdjustedSpeed * directional_factor;
+ // calculate ideal pelvis offset so that foot is glued to ground and damp towards it
+ // the amount of foot slippage this frame + the offset applied last frame
+ mPelvisOffset = mPelvisState->getPosition() + lerp(LLVector3::zero, footCorrection, LLCriticalDamp::getInterpolant(0.2f));
+
+ // pelvis drift (along walk direction)
+ mAvgCorrection = lerp(mAvgCorrection, footCorrection.mV[VX] * mRelativeDir, LLCriticalDamp::getInterpolant(0.1f));
+
+ // calculate average velocity of foot slippage
+ F32 footSlipVelocity = (deltaTime != 0.f) ? (-mAvgCorrection / deltaTime) : 0.f;
+
+ F32 newSpeedAdjust = 0.f;
+
+ // modulate speed by dot products of facing and velocity
+ // so that if we are moving sideways, we slow down the animation
+ // and if we're moving backward, we walk backward
+
+ F32 directional_factor = localVel.mV[VX] * mRelativeDir;
+
+ if (speed > 0.1f)
+ {
+ // calculate ratio of desired foot velocity to detected foot velocity
+ newSpeedAdjust = llclamp(footSlipVelocity - mAvgSpeed * (1.f - directional_factor),
+ -SPEED_ADJUST_MAX, SPEED_ADJUST_MAX);
+ newSpeedAdjust = lerp(mSpeedAdjust, newSpeedAdjust, LLCriticalDamp::getInterpolant(0.2f));
+
+ F32 speedDelta = newSpeedAdjust - mSpeedAdjust;
+ speedDelta = llclamp(speedDelta, -SPEED_ADJUST_MAX_SEC * deltaTime, SPEED_ADJUST_MAX_SEC * deltaTime);
+
+ mSpeedAdjust = mSpeedAdjust + speedDelta;
}
else
- { // standing/turning
-
- // damp out speed adjustment to 0
- mAnimSpeed = lerp(mAnimSpeed, 1.f, LLCriticalDamp::getInterpolant(0.2f));
- //mPelvisOffset = lerp(mPelvisOffset, LLVector3::zero, LLCriticalDamp::getInterpolant(0.2f));
+ {
+ mSpeedAdjust = lerp(mSpeedAdjust, 0.f, LLCriticalDamp::getInterpolant(0.2f));
}
- // broadcast walk speed change
+ mAnimSpeed = (mAvgSpeed + mSpeedAdjust) * mRelativeDir;
+ if (mAnimSpeed>0)
+ {
+ mAnimSpeed = llclamp(mAnimSpeed, ANIM_SPEED_MIN, ANIM_SPEED_MAX);
+ }
+ else
+ {
+ mAnimSpeed = llclamp(mAnimSpeed, -ANIM_SPEED_MAX, -ANIM_SPEED_MIN);
+ }
+// char debug_text[64];
+// sprintf(debug_text, "Foot slip vel: %.2f", footSlipVelocity);
+// mCharacter->addDebugText(debug_text);
+// sprintf(debug_text, "Speed: %.2f", mAvgSpeed);
+// mCharacter->addDebugText(debug_text);
+// sprintf(debug_text, "Speed Adjust: %.2f", mSpeedAdjust);
+// mCharacter->addDebugText(debug_text);
+// sprintf(debug_text, "Animation Playback Speed: %.2f", mAnimSpeed);
+// mCharacter->addDebugText(debug_text);
mCharacter->setAnimationData("Walk Speed", &mAnimSpeed);
+ if (mCharacter->getMotionController().mIsSelf)
+ {
+// F32 elapsed = mCharacter->getMotionController().getFrameTimer().getElapsedTimeF32();
+// llinfos << "PLOT elapsed: " << elapsed
+// << " footSlipVelocity: " << footSlipVelocity
+// << " mAvgCorrection: " << mAvgCorrection
+// << " mAvgSpeed: " << mAvgSpeed
+// << " mAnimSpeed: " << mAnimSpeed
+// << " ANIM_SPEED_MAX: " << ANIM_SPEED_MAX
+// << " ANIM_SPEED_MIN: " << ANIM_SPEED_MIN
+// << llendl;
+ }
+
+ // clamp pelvis offset to a 90 degree arc behind the nominal position
+ F32 drift_comp_max = llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED;
+ drift_comp_max *= DRIFT_COMP_MAX_TOTAL;
+
+ LLVector3 currentPelvisPos = mPelvisState->getJoint()->getPosition();
+
+ // NB: this is an ADDITIVE amount that is accumulated every frame, so clamping it alone won't do the trick
+ // must clamp with absolute position of pelvis in mind
+ mPelvisOffset.mV[VX] = llclamp( mPelvisOffset.mV[VX], -drift_comp_max - currentPelvisPos.mV[VX], drift_comp_max - currentPelvisPos.mV[VX] );
+ mPelvisOffset.mV[VY] = llclamp( mPelvisOffset.mV[VY], -drift_comp_max - currentPelvisPos.mV[VY], drift_comp_max - currentPelvisPos.mV[VY]);
+ mPelvisOffset.mV[VZ] = 0.f;
// set position
- // need to update *some* joint to keep this animation active
mPelvisState->setPosition(mPelvisOffset);
+ mCharacter->setAnimationData("Pelvis Offset", &mPelvisOffset);
+
return TRUE;
}
@@ -385,8 +438,14 @@ BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
// roll is critically damped interpolation between current roll and angular velocity-derived target roll
mRoll = lerp(mRoll, target_roll, LLCriticalDamp::getInterpolant(0.1f));
+// llinfos << mRoll << llendl;
+
LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));
mPelvisState->setRotation(roll);
+// F32 lerp_amt = LLCriticalDamp::getInterpolant(0.2f);
+//
+// LLVector3 pelvis_correction = mPelvisState->getPosition() - lerp(LLVector3::zero, mPelvisState->getJoint()->getPosition() + mPelvisState->getPosition(), lerp_amt);
+// mPelvisState->setPosition(pelvis_correction);
return TRUE;
}