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         mPelvisState = new LLJointState;
00148 }
00149 
00150 //-----------------------------------------------------------------------------
00151 // LLWalkAdjustMotion::onInitialize()
00152 //-----------------------------------------------------------------------------
00153 LLMotion::LLMotionInitStatus LLWalkAdjustMotion::onInitialize(LLCharacter *character)
00154 {
00155         mCharacter = character;
00156         mLeftAnkleJoint = mCharacter->getJoint("mAnkleLeft");
00157         mRightAnkleJoint = mCharacter->getJoint("mAnkleRight");
00158 
00159         mPelvisJoint = mCharacter->getJoint("mPelvis");
00160         mPelvisState->setJoint( mPelvisJoint );
00161         if ( !mPelvisJoint )
00162         {
00163                 llwarns << getName() << ": Can't get pelvis joint." << llendl;
00164                 return STATUS_FAILURE;
00165         }
00166 
00167         mPelvisState->setUsage(LLJointState::POS);
00168         addJointState( mPelvisState );
00169 
00170         return STATUS_SUCCESS;
00171 }
00172 
00173 //-----------------------------------------------------------------------------
00174 // LLWalkAdjustMotion::onActivate()
00175 //-----------------------------------------------------------------------------
00176 BOOL LLWalkAdjustMotion::onActivate()
00177 {
00178         mAvgCorrection = 0.f;
00179         mSpeedAdjust = 0.f;
00180         mAnimSpeed = 0.f;
00181         mAvgSpeed = 0.f;
00182         mRelativeDir = 1.f;
00183         mPelvisState->setPosition(LLVector3::zero);
00184         // store ankle positions for next frame
00185         mLastLeftAnklePos = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition());
00186         mLastRightAnklePos = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition());
00187 
00188         F32 leftAnkleOffset = (mLeftAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
00189         F32 rightAnkleOffset = (mRightAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
00190         mAnkleOffset = llmax(leftAnkleOffset, rightAnkleOffset);
00191 
00192         return TRUE;
00193 }
00194 
00195 //-----------------------------------------------------------------------------
00196 // LLWalkAdjustMotion::onUpdate()
00197 //-----------------------------------------------------------------------------
00198 BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
00199 {
00200         LLVector3 footCorrection;
00201         LLVector3 vel = mCharacter->getCharacterVelocity() * mCharacter->getTimeDilation();
00202         F32 deltaTime = llclamp(time - mLastTime, 0.f, MAX_TIME_DELTA);
00203         mLastTime = time;
00204 
00205         LLQuaternion inv_rotation = ~mPelvisJoint->getWorldRotation();
00206 
00207         // get speed and normalize velocity vector
00208         LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
00209         F32 speed = llmin(vel.normVec(), MAX_WALK_PLAYBACK_SPEED);
00210         mAvgSpeed = lerp(mAvgSpeed, speed, LLCriticalDamp::getInterpolant(0.2f));
00211 
00212         // calculate facing vector in pelvis-local space 
00213         // (either straight forward or back, depending on velocity)
00214         LLVector3 localVel = vel * inv_rotation;
00215         if (localVel.mV[VX] > 0.f)
00216         {
00217                 mRelativeDir = 1.f;
00218         }
00219         else if (localVel.mV[VX] < 0.f)
00220         {
00221                 mRelativeDir = -1.f;
00222         }
00223 
00224         // calculate world-space foot drift
00225         LLVector3 leftFootDelta;
00226         LLVector3 leftFootWorldPosition = mLeftAnkleJoint->getWorldPosition();
00227         LLVector3d leftFootGlobalPosition = mCharacter->getPosGlobalFromAgent(leftFootWorldPosition);
00228         leftFootDelta.setVec(mLastLeftAnklePos - leftFootGlobalPosition);
00229         mLastLeftAnklePos = leftFootGlobalPosition;
00230 
00231         LLVector3 rightFootDelta;
00232         LLVector3 rightFootWorldPosition = mRightAnkleJoint->getWorldPosition();
00233         LLVector3d rightFootGlobalPosition = mCharacter->getPosGlobalFromAgent(rightFootWorldPosition);
00234         rightFootDelta.setVec(mLastRightAnklePos - rightFootGlobalPosition);
00235         mLastRightAnklePos = rightFootGlobalPosition;
00236 
00237         // find foot drift along velocity vector
00238         if (mAvgSpeed > 0.1)
00239         {
00240                 // walking/running
00241                 F32 leftFootDriftAmt = leftFootDelta * vel;
00242                 F32 rightFootDriftAmt = rightFootDelta * vel;
00243 
00244                 if (rightFootDriftAmt > leftFootDriftAmt)
00245                 {
00246                         footCorrection = rightFootDelta;
00247                 } else
00248                 {
00249                         footCorrection = leftFootDelta;
00250                 }
00251         }
00252         else
00253         {
00254                 mAvgSpeed = ang_vel.magVec() * mAnkleOffset;
00255                 mRelativeDir = 1.f;
00256 
00257                 // standing/turning
00258                 // find the lower foot
00259                 if (leftFootWorldPosition.mV[VZ] < rightFootWorldPosition.mV[VZ])
00260                 {
00261                         // pivot on left foot
00262                         footCorrection = leftFootDelta;
00263                 }
00264                 else
00265                 {
00266                         // pivot on right foot
00267                         footCorrection = rightFootDelta;
00268                 }
00269         }
00270 
00271         // rotate into avatar coordinates
00272         footCorrection = footCorrection * inv_rotation;
00273 
00274         // calculate ideal pelvis offset so that foot is glued to ground and damp towards it
00275         // the amount of foot slippage this frame + the offset applied last frame
00276         mPelvisOffset = mPelvisState->getPosition() + lerp(LLVector3::zero, footCorrection, LLCriticalDamp::getInterpolant(0.2f));
00277 
00278         // pelvis drift (along walk direction)
00279         mAvgCorrection = lerp(mAvgCorrection, footCorrection.mV[VX] * mRelativeDir, LLCriticalDamp::getInterpolant(0.1f));
00280 
00281         // calculate average velocity of foot slippage
00282         F32 footSlipVelocity = (deltaTime != 0.f) ? (-mAvgCorrection / deltaTime) : 0.f;
00283 
00284         F32 newSpeedAdjust = 0.f;
00285         
00286         // modulate speed by dot products of facing and velocity
00287         // so that if we are moving sideways, we slow down the animation
00288         // and if we're moving backward, we walk backward
00289 
00290         F32 directional_factor = localVel.mV[VX] * mRelativeDir;
00291         if (speed > 0.1f)
00292         {
00293                 // calculate ratio of desired foot velocity to detected foot velocity
00294                 newSpeedAdjust = llclamp(footSlipVelocity - mAvgSpeed * (1.f - directional_factor), 
00295                                                                 -SPEED_ADJUST_MAX, SPEED_ADJUST_MAX);
00296                 newSpeedAdjust = lerp(mSpeedAdjust, newSpeedAdjust, LLCriticalDamp::getInterpolant(0.2f));
00297 
00298                 F32 speedDelta = newSpeedAdjust - mSpeedAdjust;
00299                 speedDelta = llclamp(speedDelta, -SPEED_ADJUST_MAX_SEC * deltaTime, SPEED_ADJUST_MAX_SEC * deltaTime);
00300 
00301                 mSpeedAdjust = mSpeedAdjust + speedDelta;
00302         }
00303         else
00304         {
00305                 mSpeedAdjust = lerp(mSpeedAdjust, 0.f, LLCriticalDamp::getInterpolant(0.2f));
00306         }
00307 
00308         mAnimSpeed = (mAvgSpeed + mSpeedAdjust) * mRelativeDir;
00309 //      char debug_text[64];
00310 //      sprintf(debug_text, "Foot slip vel: %.2f", footSlipVelocity);
00311 //      mCharacter->addDebugText(debug_text);
00312 //      sprintf(debug_text, "Speed: %.2f", mAvgSpeed);
00313 //      mCharacter->addDebugText(debug_text);
00314 //      sprintf(debug_text, "Speed Adjust: %.2f", mSpeedAdjust);
00315 //      mCharacter->addDebugText(debug_text);
00316 //      sprintf(debug_text, "Animation Playback Speed: %.2f", mAnimSpeed);
00317 //      mCharacter->addDebugText(debug_text);
00318         mCharacter->setAnimationData("Walk Speed", &mAnimSpeed);
00319 
00320         // clamp pelvis offset to a 90 degree arc behind the nominal position
00321         F32 drift_comp_max = llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED;
00322         drift_comp_max *= DRIFT_COMP_MAX_TOTAL;
00323 
00324         LLVector3 currentPelvisPos = mPelvisState->getJoint()->getPosition();
00325 
00326         // NB: this is an ADDITIVE amount that is accumulated every frame, so clamping it alone won't do the trick
00327         // must clamp with absolute position of pelvis in mind
00328         mPelvisOffset.mV[VX] = llclamp( mPelvisOffset.mV[VX], -drift_comp_max - currentPelvisPos.mV[VX], drift_comp_max - currentPelvisPos.mV[VX]  );
00329         mPelvisOffset.mV[VY] = llclamp( mPelvisOffset.mV[VY], -drift_comp_max - currentPelvisPos.mV[VY], drift_comp_max - currentPelvisPos.mV[VY]);
00330         mPelvisOffset.mV[VZ] = 0.f;
00331 
00332         // set position
00333         mPelvisState->setPosition(mPelvisOffset);
00334 
00335         mCharacter->setAnimationData("Pelvis Offset", &mPelvisOffset);
00336 
00337         return TRUE;
00338 }
00339 
00340 //-----------------------------------------------------------------------------
00341 // LLWalkAdjustMotion::onDeactivate()
00342 //-----------------------------------------------------------------------------
00343 void LLWalkAdjustMotion::onDeactivate()
00344 {
00345         mCharacter->removeAnimationData("Walk Speed");
00346 }
00347 
00348 //-----------------------------------------------------------------------------
00349 // LLFlyAdjustMotion::LLFlyAdjustMotion()
00350 //-----------------------------------------------------------------------------
00351 LLFlyAdjustMotion::LLFlyAdjustMotion(const LLUUID &id)
00352         : LLMotion(id)
00353 {
00354         mName = "fly_adjust";
00355 
00356         mPelvisState = new LLJointState;
00357 }
00358 
00359 //-----------------------------------------------------------------------------
00360 // LLFlyAdjustMotion::onInitialize()
00361 //-----------------------------------------------------------------------------
00362 LLMotion::LLMotionInitStatus LLFlyAdjustMotion::onInitialize(LLCharacter *character)
00363 {
00364         mCharacter = character;
00365 
00366         LLJoint* pelvisJoint = mCharacter->getJoint("mPelvis");
00367         mPelvisState->setJoint( pelvisJoint );
00368         if ( !pelvisJoint )
00369         {
00370                 llwarns << getName() << ": Can't get pelvis joint." << llendl;
00371                 return STATUS_FAILURE;
00372         }
00373 
00374         mPelvisState->setUsage(LLJointState::POS | LLJointState::ROT);
00375         addJointState( mPelvisState );
00376 
00377         return STATUS_SUCCESS;
00378 }
00379 
00380 //-----------------------------------------------------------------------------
00381 // LLFlyAdjustMotion::onActivate()
00382 //-----------------------------------------------------------------------------
00383 BOOL LLFlyAdjustMotion::onActivate()
00384 {
00385         mPelvisState->setPosition(LLVector3::zero);
00386         mPelvisState->setRotation(LLQuaternion::DEFAULT);
00387         mRoll = 0.f;
00388         return TRUE;
00389 }
00390 
00391 //-----------------------------------------------------------------------------
00392 // LLFlyAdjustMotion::onUpdate()
00393 //-----------------------------------------------------------------------------
00394 BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
00395 {
00396         LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
00397         F32 speed = mCharacter->getCharacterVelocity().magVec();
00398 
00399         F32 roll_factor = clamp_rescale(speed, 7.f, 15.f, 0.f, -MAX_ROLL);
00400         F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor;
00401 
00402         // roll is critically damped interpolation between current roll and angular velocity-derived target roll
00403         mRoll = lerp(mRoll, target_roll, LLCriticalDamp::getInterpolant(0.1f));
00404 
00405 //      llinfos << mRoll << llendl;
00406 
00407         LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));
00408         mPelvisState->setRotation(roll);
00409 
00410 //      F32 lerp_amt = LLCriticalDamp::getInterpolant(0.2f);
00411 //      
00412 //      LLVector3 pelvis_correction = mPelvisState->getPosition() - lerp(LLVector3::zero, mPelvisState->getJoint()->getPosition() + mPelvisState->getPosition(), lerp_amt);
00413 //      mPelvisState->setPosition(pelvis_correction);
00414         return TRUE;
00415 }

Generated on Fri May 16 08:31:59 2008 for SecondLife by  doxygen 1.5.5