llkeyframewalkmotion.cpp

Go to the documentation of this file.
00001 
00032 //-----------------------------------------------------------------------------
00033 // Header Files
00034 //-----------------------------------------------------------------------------
00035 #include "linden_common.h"
00036 
00037 #include "llkeyframewalkmotion.h"
00038 #include "llcharacter.h"
00039 #include "llmath.h"
00040 #include "m3math.h"
00041 #include "llcriticaldamp.h"
00042 
00043 //-----------------------------------------------------------------------------
00044 // Macros
00045 //-----------------------------------------------------------------------------
00046 const F32 MAX_WALK_PLAYBACK_SPEED = 8.f;        // max m/s for which we adjust walk cycle speed
00047 
00048 const F32 MIN_WALK_SPEED = 0.1f;        // minimum speed at which we use velocity for down foot detection
00049 const F32 MAX_TIME_DELTA = 2.f;         //max two seconds a frame for calculating interpolation
00050 const F32 SPEED_ADJUST_MAX = 2.5f; // maximum adjustment of walk animation playback speed
00051 const F32 SPEED_ADJUST_MAX_SEC = 3.f;   // maximum adjustment to walk animation playback speed for a second
00052 const F32 DRIFT_COMP_MAX_TOTAL = 0.07f;//0.55f; // maximum drift compensation overall, in any direction 
00053 const F32 DRIFT_COMP_MAX_SPEED = 4.f; // speed at which drift compensation total maxes out
00054 const F32 MAX_ROLL = 0.6f;
00055 
00056 //-----------------------------------------------------------------------------
00057 // LLKeyframeWalkMotion()
00058 // Class Constructor
00059 //-----------------------------------------------------------------------------
00060 LLKeyframeWalkMotion::LLKeyframeWalkMotion(const LLUUID &id) : LLKeyframeMotion(id)
00061 {
00062         mRealTimeLast = 0.0f;
00063         mAdjTimeLast = 0.0f;
00064         mCharacter = NULL;
00065 }
00066 
00067 
00068 //-----------------------------------------------------------------------------
00069 // ~LLKeyframeWalkMotion()
00070 // Class Destructor
00071 //-----------------------------------------------------------------------------
00072 LLKeyframeWalkMotion::~LLKeyframeWalkMotion()
00073 {
00074 }
00075 
00076 
00077 //-----------------------------------------------------------------------------
00078 // LLKeyframeWalkMotion::onInitialize()
00079 //-----------------------------------------------------------------------------
00080 LLMotion::LLMotionInitStatus LLKeyframeWalkMotion::onInitialize(LLCharacter *character)
00081 {
00082         mCharacter = character;
00083 
00084         return LLKeyframeMotion::onInitialize(character);
00085 }
00086 
00087 //-----------------------------------------------------------------------------
00088 // LLKeyframeWalkMotion::onActivate()
00089 //-----------------------------------------------------------------------------
00090 BOOL LLKeyframeWalkMotion::onActivate()
00091 {
00092         mRealTimeLast = 0.0f;
00093         mAdjTimeLast = 0.0f;
00094 
00095         return LLKeyframeMotion::onActivate();
00096 }
00097 
00098 //-----------------------------------------------------------------------------
00099 // LLKeyframeWalkMotion::onDeactivate()
00100 //-----------------------------------------------------------------------------
00101 void LLKeyframeWalkMotion::onDeactivate()
00102 {
00103         mCharacter->removeAnimationData("Down Foot");           
00104         LLKeyframeMotion::onDeactivate();
00105 }
00106 
00107 //-----------------------------------------------------------------------------
00108 // LLKeyframeWalkMotion::onUpdate()
00109 //-----------------------------------------------------------------------------
00110 BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask)
00111 {
00112         // compute time since last update
00113         F32 deltaTime = time - mRealTimeLast;
00114 
00115         void* speed_ptr = mCharacter->getAnimationData("Walk Speed");
00116         F32 speed = (speed_ptr) ? *((F32 *)speed_ptr) : 1.f;
00117 
00118         // adjust the passage of time accordingly
00119         F32 adjusted_time = mAdjTimeLast + (deltaTime * speed);
00120 
00121         // save time for next update
00122         mRealTimeLast = time;
00123         mAdjTimeLast = adjusted_time;
00124 
00125         // handle wrap around
00126         if (adjusted_time < 0.0f)
00127         {
00128                 adjusted_time = getDuration() + fmod(adjusted_time, getDuration());
00129         }
00130 
00131         // let the base class update the cycle
00132         return LLKeyframeMotion::onUpdate( adjusted_time, joint_mask );
00133 }
00134 
00135 // End
00136 
00137 
00138 //-----------------------------------------------------------------------------
00139 // LLWalkAdjustMotion()
00140 // Class Constructor
00141 //-----------------------------------------------------------------------------
00142 LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) : LLMotion(id)
00143 {
00144         mLastTime = 0.f;
00145         mName = "walk_adjust";
00146 }
00147 
00148 //-----------------------------------------------------------------------------
00149 // LLWalkAdjustMotion::onInitialize()
00150 //-----------------------------------------------------------------------------
00151 LLMotion::LLMotionInitStatus LLWalkAdjustMotion::onInitialize(LLCharacter *character)
00152 {
00153         mCharacter = character;
00154         mLeftAnkleJoint = mCharacter->getJoint("mAnkleLeft");
00155         mRightAnkleJoint = mCharacter->getJoint("mAnkleRight");
00156 
00157         mPelvisJoint = mCharacter->getJoint("mPelvis");
00158         mPelvisState.setJoint( mPelvisJoint );
00159         if ( !mPelvisJoint )
00160         {
00161                 llwarns << getName() << ": Can't get pelvis joint." << llendl;
00162                 return STATUS_FAILURE;
00163         }
00164 
00165         mPelvisState.setUsage(LLJointState::POS);
00166         addJointState( &mPelvisState );
00167 
00168         return STATUS_SUCCESS;
00169 }
00170 
00171 //-----------------------------------------------------------------------------
00172 // LLWalkAdjustMotion::onActivate()
00173 //-----------------------------------------------------------------------------
00174 BOOL LLWalkAdjustMotion::onActivate()
00175 {
00176         mAvgCorrection = 0.f;
00177         mSpeedAdjust = 0.f;
00178         mAnimSpeed = 0.f;
00179         mAvgSpeed = 0.f;
00180         mRelativeDir = 1.f;
00181         mPelvisState.setPosition(LLVector3::zero);
00182         // store ankle positions for next frame
00183         mLastLeftAnklePos = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition());
00184         mLastRightAnklePos = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition());
00185 
00186         F32 leftAnkleOffset = (mLeftAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
00187         F32 rightAnkleOffset = (mRightAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
00188         mAnkleOffset = llmax(leftAnkleOffset, rightAnkleOffset);
00189 
00190         return TRUE;
00191 }
00192 
00193 //-----------------------------------------------------------------------------
00194 // LLWalkAdjustMotion::onUpdate()
00195 //-----------------------------------------------------------------------------
00196 BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
00197 {
00198         LLVector3 footCorrection;
00199         LLVector3 vel = mCharacter->getCharacterVelocity() * mCharacter->getTimeDilation();
00200         F32 deltaTime = llclamp(time - mLastTime, 0.f, MAX_TIME_DELTA);
00201         mLastTime = time;
00202 
00203         LLQuaternion inv_rotation = ~mPelvisJoint->getWorldRotation();
00204 
00205         // get speed and normalize velocity vector
00206         LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
00207         F32 speed = llmin(vel.normVec(), MAX_WALK_PLAYBACK_SPEED);
00208         mAvgSpeed = lerp(mAvgSpeed, speed, LLCriticalDamp::getInterpolant(0.2f));
00209 
00210         // calculate facing vector in pelvis-local space 
00211         // (either straight forward or back, depending on velocity)
00212         LLVector3 localVel = vel * inv_rotation;
00213         if (localVel.mV[VX] > 0.f)
00214         {
00215                 mRelativeDir = 1.f;
00216         }
00217         else if (localVel.mV[VX] < 0.f)
00218         {
00219                 mRelativeDir = -1.f;
00220         }
00221 
00222         // calculate world-space foot drift
00223         LLVector3 leftFootDelta;
00224         LLVector3 leftFootWorldPosition = mLeftAnkleJoint->getWorldPosition();
00225         LLVector3d leftFootGlobalPosition = mCharacter->getPosGlobalFromAgent(leftFootWorldPosition);
00226         leftFootDelta.setVec(mLastLeftAnklePos - leftFootGlobalPosition);
00227         mLastLeftAnklePos = leftFootGlobalPosition;
00228 
00229         LLVector3 rightFootDelta;
00230         LLVector3 rightFootWorldPosition = mRightAnkleJoint->getWorldPosition();
00231         LLVector3d rightFootGlobalPosition = mCharacter->getPosGlobalFromAgent(rightFootWorldPosition);
00232         rightFootDelta.setVec(mLastRightAnklePos - rightFootGlobalPosition);
00233         mLastRightAnklePos = rightFootGlobalPosition;
00234 
00235         // find foot drift along velocity vector
00236         if (mAvgSpeed > 0.1)
00237         {
00238                 // walking/running
00239                 F32 leftFootDriftAmt = leftFootDelta * vel;
00240                 F32 rightFootDriftAmt = rightFootDelta * vel;
00241 
00242                 if (rightFootDriftAmt > leftFootDriftAmt)
00243                 {
00244                         footCorrection = rightFootDelta;
00245                 } else
00246                 {
00247                         footCorrection = leftFootDelta;
00248                 }
00249         }
00250         else
00251         {
00252                 mAvgSpeed = ang_vel.magVec() * mAnkleOffset;
00253                 mRelativeDir = 1.f;
00254 
00255                 // standing/turning
00256                 // find the lower foot
00257                 if (leftFootWorldPosition.mV[VZ] < rightFootWorldPosition.mV[VZ])
00258                 {
00259                         // pivot on left foot
00260                         footCorrection = leftFootDelta;
00261                 }
00262                 else
00263                 {
00264                         // pivot on right foot
00265                         footCorrection = rightFootDelta;
00266                 }
00267         }
00268 
00269         // rotate into avatar coordinates
00270         footCorrection = footCorrection * inv_rotation;
00271 
00272         // calculate ideal pelvis offset so that foot is glued to ground and damp towards it
00273         // the amount of foot slippage this frame + the offset applied last frame
00274         mPelvisOffset = mPelvisState.getPosition() + lerp(LLVector3::zero, footCorrection, LLCriticalDamp::getInterpolant(0.2f));
00275 
00276         // pelvis drift (along walk direction)
00277         mAvgCorrection = lerp(mAvgCorrection, footCorrection.mV[VX] * mRelativeDir, LLCriticalDamp::getInterpolant(0.1f));
00278 
00279         // calculate average velocity of foot slippage
00280         F32 footSlipVelocity = (deltaTime != 0.f) ? (-mAvgCorrection / deltaTime) : 0.f;
00281 
00282         F32 newSpeedAdjust = 0.f;
00283         
00284         // modulate speed by dot products of facing and velocity
00285         // so that if we are moving sideways, we slow down the animation
00286         // and if we're moving backward, we walk backward
00287 
00288         F32 directional_factor = localVel.mV[VX] * mRelativeDir;
00289         if (speed > 0.1f)
00290         {
00291                 // calculate ratio of desired foot velocity to detected foot velocity
00292                 newSpeedAdjust = llclamp(footSlipVelocity - mAvgSpeed * (1.f - directional_factor), 
00293                                                                 -SPEED_ADJUST_MAX, SPEED_ADJUST_MAX);
00294                 newSpeedAdjust = lerp(mSpeedAdjust, newSpeedAdjust, LLCriticalDamp::getInterpolant(0.2f));
00295 
00296                 F32 speedDelta = newSpeedAdjust - mSpeedAdjust;
00297                 speedDelta = llclamp(speedDelta, -SPEED_ADJUST_MAX_SEC * deltaTime, SPEED_ADJUST_MAX_SEC * deltaTime);
00298 
00299                 mSpeedAdjust = mSpeedAdjust + speedDelta;
00300         }
00301         else
00302         {
00303                 mSpeedAdjust = lerp(mSpeedAdjust, 0.f, LLCriticalDamp::getInterpolant(0.2f));
00304         }
00305 
00306         mAnimSpeed = (mAvgSpeed + mSpeedAdjust) * mRelativeDir;
00307 //      char debug_text[64];
00308 //      sprintf(debug_text, "Foot slip vel: %.2f", footSlipVelocity);
00309 //      mCharacter->addDebugText(debug_text);
00310 //      sprintf(debug_text, "Speed: %.2f", mAvgSpeed);
00311 //      mCharacter->addDebugText(debug_text);
00312 //      sprintf(debug_text, "Speed Adjust: %.2f", mSpeedAdjust);
00313 //      mCharacter->addDebugText(debug_text);
00314 //      sprintf(debug_text, "Animation Playback Speed: %.2f", mAnimSpeed);
00315 //      mCharacter->addDebugText(debug_text);
00316         mCharacter->setAnimationData("Walk Speed", &mAnimSpeed);
00317 
00318         // clamp pelvis offset to a 90 degree arc behind the nominal position
00319         F32 drift_comp_max = llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED;
00320         drift_comp_max *= DRIFT_COMP_MAX_TOTAL;
00321 
00322         LLVector3 currentPelvisPos = mPelvisState.getJoint()->getPosition();
00323 
00324         // NB: this is an ADDITIVE amount that is accumulated every frame, so clamping it alone won't do the trick
00325         // must clamp with absolute position of pelvis in mind
00326         mPelvisOffset.mV[VX] = llclamp( mPelvisOffset.mV[VX], -drift_comp_max - currentPelvisPos.mV[VX], drift_comp_max - currentPelvisPos.mV[VX]  );
00327         mPelvisOffset.mV[VY] = llclamp( mPelvisOffset.mV[VY], -drift_comp_max - currentPelvisPos.mV[VY], drift_comp_max - currentPelvisPos.mV[VY]);
00328         mPelvisOffset.mV[VZ] = 0.f;
00329 
00330         // set position
00331         mPelvisState.setPosition(mPelvisOffset);
00332 
00333         mCharacter->setAnimationData("Pelvis Offset", &mPelvisOffset);
00334 
00335         return TRUE;
00336 }
00337 
00338 //-----------------------------------------------------------------------------
00339 // LLWalkAdjustMotion::onDeactivate()
00340 //-----------------------------------------------------------------------------
00341 void LLWalkAdjustMotion::onDeactivate()
00342 {
00343         mCharacter->removeAnimationData("Walk Speed");
00344 }
00345 
00346 //-----------------------------------------------------------------------------
00347 // LLFlyAdjustMotion::onInitialize()
00348 //-----------------------------------------------------------------------------
00349 LLMotion::LLMotionInitStatus LLFlyAdjustMotion::onInitialize(LLCharacter *character)
00350 {
00351         mCharacter = character;
00352 
00353         LLJoint* pelvisJoint = mCharacter->getJoint("mPelvis");
00354         mPelvisState.setJoint( pelvisJoint );
00355         if ( !pelvisJoint )
00356         {
00357                 llwarns << getName() << ": Can't get pelvis joint." << llendl;
00358                 return STATUS_FAILURE;
00359         }
00360 
00361         mPelvisState.setUsage(LLJointState::POS | LLJointState::ROT);
00362         addJointState( &mPelvisState );
00363 
00364         return STATUS_SUCCESS;
00365 }
00366 
00367 //-----------------------------------------------------------------------------
00368 // LLFlyAdjustMotion::onActivate()
00369 //-----------------------------------------------------------------------------
00370 BOOL LLFlyAdjustMotion::onActivate()
00371 {
00372         mPelvisState.setPosition(LLVector3::zero);
00373         mPelvisState.setRotation(LLQuaternion::DEFAULT);
00374         mRoll = 0.f;
00375         return TRUE;
00376 }
00377 
00378 //-----------------------------------------------------------------------------
00379 // LLFlyAdjustMotion::onUpdate()
00380 //-----------------------------------------------------------------------------
00381 BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
00382 {
00383         LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
00384         F32 speed = mCharacter->getCharacterVelocity().magVec();
00385 
00386         F32 roll_factor = clamp_rescale(speed, 7.f, 15.f, 0.f, -MAX_ROLL);
00387         F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor;
00388 
00389         // roll is critically damped interpolation between current roll and angular velocity-derived target roll
00390         mRoll = lerp(mRoll, target_roll, LLCriticalDamp::getInterpolant(0.1f));
00391 
00392 //      llinfos << mRoll << llendl;
00393 
00394         LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));
00395         mPelvisState.setRotation(roll);
00396 
00397 //      F32 lerp_amt = LLCriticalDamp::getInterpolant(0.2f);
00398 //      
00399 //      LLVector3 pelvis_correction = mPelvisState.getPosition() - lerp(LLVector3::zero, mPelvisState.getJoint()->getPosition() + mPelvisState.getPosition(), lerp_amt);
00400 //      mPelvisState.setPosition(pelvis_correction);
00401         return TRUE;
00402 }

Generated on Thu Jul 1 06:08:48 2010 for Second Life Viewer by  doxygen 1.4.7