aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcharacter/llkeyframewalkmotion.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcharacter/llkeyframewalkmotion.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llcharacter/llkeyframewalkmotion.cpp')
-rw-r--r--linden/indra/llcharacter/llkeyframewalkmotion.cpp398
1 files changed, 398 insertions, 0 deletions
diff --git a/linden/indra/llcharacter/llkeyframewalkmotion.cpp b/linden/indra/llcharacter/llkeyframewalkmotion.cpp
new file mode 100644
index 0000000..b1838d8
--- /dev/null
+++ b/linden/indra/llcharacter/llkeyframewalkmotion.cpp
@@ -0,0 +1,398 @@
1/**
2 * @file llkeyframewalkmotion.cpp
3 * @brief Implementation of LLKeyframeWalkMotion class.
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28//-----------------------------------------------------------------------------
29// Header Files
30//-----------------------------------------------------------------------------
31#include "linden_common.h"
32
33#include "llkeyframewalkmotion.h"
34#include "llcharacter.h"
35#include "llmath.h"
36#include "m3math.h"
37#include "llcriticaldamp.h"
38
39//-----------------------------------------------------------------------------
40// Macros
41//-----------------------------------------------------------------------------
42const F32 MAX_WALK_PLAYBACK_SPEED = 8.f; // max m/s for which we adjust walk cycle speed
43
44const F32 MIN_WALK_SPEED = 0.1f; // minimum speed at which we use velocity for down foot detection
45const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation
46const F32 SPEED_ADJUST_MAX = 2.5f; // maximum adjustment of walk animation playback speed
47const F32 SPEED_ADJUST_MAX_SEC = 3.f; // maximum adjustment to walk animation playback speed for a second
48const F32 DRIFT_COMP_MAX_TOTAL = 0.07f;//0.55f; // maximum drift compensation overall, in any direction
49const F32 DRIFT_COMP_MAX_SPEED = 4.f; // speed at which drift compensation total maxes out
50const F32 MAX_ROLL = 0.6f;
51
52//-----------------------------------------------------------------------------
53// LLKeyframeWalkMotion()
54// Class Constructor
55//-----------------------------------------------------------------------------
56LLKeyframeWalkMotion::LLKeyframeWalkMotion(const LLUUID &id) : LLKeyframeMotion(id)
57{
58 mRealTimeLast = 0.0f;
59 mAdjTimeLast = 0.0f;
60 mCharacter = NULL;
61}
62
63
64//-----------------------------------------------------------------------------
65// ~LLKeyframeWalkMotion()
66// Class Destructor
67//-----------------------------------------------------------------------------
68LLKeyframeWalkMotion::~LLKeyframeWalkMotion()
69{
70}
71
72
73//-----------------------------------------------------------------------------
74// LLKeyframeWalkMotion::onInitialize()
75//-----------------------------------------------------------------------------
76LLMotion::LLMotionInitStatus LLKeyframeWalkMotion::onInitialize(LLCharacter *character)
77{
78 mCharacter = character;
79
80 return LLKeyframeMotion::onInitialize(character);
81}
82
83//-----------------------------------------------------------------------------
84// LLKeyframeWalkMotion::onActivate()
85//-----------------------------------------------------------------------------
86BOOL LLKeyframeWalkMotion::onActivate()
87{
88 mRealTimeLast = 0.0f;
89 mAdjTimeLast = 0.0f;
90
91 return LLKeyframeMotion::onActivate();
92}
93
94//-----------------------------------------------------------------------------
95// LLKeyframeWalkMotion::onDeactivate()
96//-----------------------------------------------------------------------------
97void LLKeyframeWalkMotion::onDeactivate()
98{
99 mCharacter->removeAnimationData("Down Foot");
100 LLKeyframeMotion::onDeactivate();
101}
102
103//-----------------------------------------------------------------------------
104// LLKeyframeWalkMotion::onUpdate()
105//-----------------------------------------------------------------------------
106BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask)
107{
108 // compute time since last update
109 F32 deltaTime = time - mRealTimeLast;
110
111 void* speed_ptr = mCharacter->getAnimationData("Walk Speed");
112 F32 speed = (speed_ptr) ? *((F32 *)speed_ptr) : 1.f;
113
114 // adjust the passage of time accordingly
115 F32 adjusted_time = mAdjTimeLast + (deltaTime * speed);
116
117 // save time for next update
118 mRealTimeLast = time;
119 mAdjTimeLast = adjusted_time;
120
121 // handle wrap around
122 if (adjusted_time < 0.0f)
123 {
124 adjusted_time = getDuration() + fmod(adjusted_time, getDuration());
125 }
126
127 // let the base class update the cycle
128 return LLKeyframeMotion::onUpdate( adjusted_time, joint_mask );
129}
130
131// End
132
133
134//-----------------------------------------------------------------------------
135// LLWalkAdjustMotion()
136// Class Constructor
137//-----------------------------------------------------------------------------
138LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) : LLMotion(id)
139{
140 mLastTime = 0.f;
141 mName = "walk_adjust";
142}
143
144//-----------------------------------------------------------------------------
145// LLWalkAdjustMotion::onInitialize()
146//-----------------------------------------------------------------------------
147LLMotion::LLMotionInitStatus LLWalkAdjustMotion::onInitialize(LLCharacter *character)
148{
149 mCharacter = character;
150 mLeftAnkleJoint = mCharacter->getJoint("mAnkleLeft");
151 mRightAnkleJoint = mCharacter->getJoint("mAnkleRight");
152
153 mPelvisJoint = mCharacter->getJoint("mPelvis");
154 mPelvisState.setJoint( mPelvisJoint );
155 if ( !mPelvisJoint )
156 {
157 llwarns << getName() << ": Can't get pelvis joint." << llendl;
158 return STATUS_FAILURE;
159 }
160
161 mPelvisState.setUsage(LLJointState::POS);
162 addJointState( &mPelvisState );
163
164 return STATUS_SUCCESS;
165}
166
167//-----------------------------------------------------------------------------
168// LLWalkAdjustMotion::onActivate()
169//-----------------------------------------------------------------------------
170BOOL LLWalkAdjustMotion::onActivate()
171{
172 mAvgCorrection = 0.f;
173 mSpeedAdjust = 0.f;
174 mAnimSpeed = 0.f;
175 mAvgSpeed = 0.f;
176 mRelativeDir = 1.f;
177 mPelvisState.setPosition(LLVector3::zero);
178 // store ankle positions for next frame
179 mLastLeftAnklePos = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition());
180 mLastRightAnklePos = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition());
181
182 F32 leftAnkleOffset = (mLeftAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
183 F32 rightAnkleOffset = (mRightAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
184 mAnkleOffset = llmax(leftAnkleOffset, rightAnkleOffset);
185
186 return TRUE;
187}
188
189//-----------------------------------------------------------------------------
190// LLWalkAdjustMotion::onUpdate()
191//-----------------------------------------------------------------------------
192BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
193{
194 LLVector3 footCorrection;
195 LLVector3 vel = mCharacter->getCharacterVelocity() * mCharacter->getTimeDilation();
196 F32 deltaTime = llclamp(time - mLastTime, 0.f, MAX_TIME_DELTA);
197 mLastTime = time;
198
199 LLQuaternion inv_rotation = ~mPelvisJoint->getWorldRotation();
200
201 // get speed and normalize velocity vector
202 LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
203 F32 speed = llmin(vel.normVec(), MAX_WALK_PLAYBACK_SPEED);
204 mAvgSpeed = lerp(mAvgSpeed, speed, LLCriticalDamp::getInterpolant(0.2f));
205
206 // calculate facing vector in pelvis-local space
207 // (either straight forward or back, depending on velocity)
208 LLVector3 localVel = vel * inv_rotation;
209 if (localVel.mV[VX] > 0.f)
210 {
211 mRelativeDir = 1.f;
212 }
213 else if (localVel.mV[VX] < 0.f)
214 {
215 mRelativeDir = -1.f;
216 }
217
218 // calculate world-space foot drift
219 LLVector3 leftFootDelta;
220 LLVector3 leftFootWorldPosition = mLeftAnkleJoint->getWorldPosition();
221 LLVector3d leftFootGlobalPosition = mCharacter->getPosGlobalFromAgent(leftFootWorldPosition);
222 leftFootDelta.setVec(mLastLeftAnklePos - leftFootGlobalPosition);
223 mLastLeftAnklePos = leftFootGlobalPosition;
224
225 LLVector3 rightFootDelta;
226 LLVector3 rightFootWorldPosition = mRightAnkleJoint->getWorldPosition();
227 LLVector3d rightFootGlobalPosition = mCharacter->getPosGlobalFromAgent(rightFootWorldPosition);
228 rightFootDelta.setVec(mLastRightAnklePos - rightFootGlobalPosition);
229 mLastRightAnklePos = rightFootGlobalPosition;
230
231 // find foot drift along velocity vector
232 if (mAvgSpeed > 0.1)
233 {
234 // walking/running
235 F32 leftFootDriftAmt = leftFootDelta * vel;
236 F32 rightFootDriftAmt = rightFootDelta * vel;
237
238 if (rightFootDriftAmt > leftFootDriftAmt)
239 {
240 footCorrection = rightFootDelta;
241 } else
242 {
243 footCorrection = leftFootDelta;
244 }
245 }
246 else
247 {
248 mAvgSpeed = ang_vel.magVec() * mAnkleOffset;
249 mRelativeDir = 1.f;
250
251 // standing/turning
252 // find the lower foot
253 if (leftFootWorldPosition.mV[VZ] < rightFootWorldPosition.mV[VZ])
254 {
255 // pivot on left foot
256 footCorrection = leftFootDelta;
257 }
258 else
259 {
260 // pivot on right foot
261 footCorrection = rightFootDelta;
262 }
263 }
264
265 // rotate into avatar coordinates
266 footCorrection = footCorrection * inv_rotation;
267
268 // calculate ideal pelvis offset so that foot is glued to ground and damp towards it
269 // the amount of foot slippage this frame + the offset applied last frame
270 mPelvisOffset = mPelvisState.getPosition() + lerp(LLVector3::zero, footCorrection, LLCriticalDamp::getInterpolant(0.2f));
271
272 // pelvis drift (along walk direction)
273 mAvgCorrection = lerp(mAvgCorrection, footCorrection.mV[VX] * mRelativeDir, LLCriticalDamp::getInterpolant(0.1f));
274
275 // calculate average velocity of foot slippage
276 F32 footSlipVelocity = (deltaTime != 0.f) ? (-mAvgCorrection / deltaTime) : 0.f;
277
278 F32 newSpeedAdjust = 0.f;
279
280 // modulate speed by dot products of facing and velocity
281 // so that if we are moving sideways, we slow down the animation
282 // and if we're moving backward, we walk backward
283
284 F32 directional_factor = localVel.mV[VX] * mRelativeDir;
285 if (speed > 0.1f)
286 {
287 // calculate ratio of desired foot velocity to detected foot velocity
288 newSpeedAdjust = llclamp(footSlipVelocity - mAvgSpeed * (1.f - directional_factor),
289 -SPEED_ADJUST_MAX, SPEED_ADJUST_MAX);
290 newSpeedAdjust = lerp(mSpeedAdjust, newSpeedAdjust, LLCriticalDamp::getInterpolant(0.2f));
291
292 F32 speedDelta = newSpeedAdjust - mSpeedAdjust;
293 speedDelta = llclamp(speedDelta, -SPEED_ADJUST_MAX_SEC * deltaTime, SPEED_ADJUST_MAX_SEC * deltaTime);
294
295 mSpeedAdjust = mSpeedAdjust + speedDelta;
296 }
297 else
298 {
299 mSpeedAdjust = lerp(mSpeedAdjust, 0.f, LLCriticalDamp::getInterpolant(0.2f));
300 }
301
302 mAnimSpeed = (mAvgSpeed + mSpeedAdjust) * mRelativeDir;
303// char debug_text[64];
304// sprintf(debug_text, "Foot slip vel: %.2f", footSlipVelocity);
305// mCharacter->addDebugText(debug_text);
306// sprintf(debug_text, "Speed: %.2f", mAvgSpeed);
307// mCharacter->addDebugText(debug_text);
308// sprintf(debug_text, "Speed Adjust: %.2f", mSpeedAdjust);
309// mCharacter->addDebugText(debug_text);
310// sprintf(debug_text, "Animation Playback Speed: %.2f", mAnimSpeed);
311// mCharacter->addDebugText(debug_text);
312 mCharacter->setAnimationData("Walk Speed", &mAnimSpeed);
313
314 // clamp pelvis offset to a 90 degree arc behind the nominal position
315 F32 drift_comp_max = llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED;
316 drift_comp_max *= DRIFT_COMP_MAX_TOTAL;
317
318 LLVector3 currentPelvisPos = mPelvisState.getJoint()->getPosition();
319
320 // NB: this is an ADDITIVE amount that is accumulated every frame, so clamping it alone won't do the trick
321 // must clamp with absolute position of pelvis in mind
322 mPelvisOffset.mV[VX] = llclamp( mPelvisOffset.mV[VX], -drift_comp_max - currentPelvisPos.mV[VX], drift_comp_max - currentPelvisPos.mV[VX] );
323 mPelvisOffset.mV[VY] = llclamp( mPelvisOffset.mV[VY], -drift_comp_max - currentPelvisPos.mV[VY], drift_comp_max - currentPelvisPos.mV[VY]);
324 mPelvisOffset.mV[VZ] = 0.f;
325
326 // set position
327 mPelvisState.setPosition(mPelvisOffset);
328
329 mCharacter->setAnimationData("Pelvis Offset", &mPelvisOffset);
330
331 return TRUE;
332}
333
334//-----------------------------------------------------------------------------
335// LLWalkAdjustMotion::onDeactivate()
336//-----------------------------------------------------------------------------
337void LLWalkAdjustMotion::onDeactivate()
338{
339 mCharacter->removeAnimationData("Walk Speed");
340}
341
342//-----------------------------------------------------------------------------
343// LLFlyAdjustMotion::onInitialize()
344//-----------------------------------------------------------------------------
345LLMotion::LLMotionInitStatus LLFlyAdjustMotion::onInitialize(LLCharacter *character)
346{
347 mCharacter = character;
348
349 LLJoint* pelvisJoint = mCharacter->getJoint("mPelvis");
350 mPelvisState.setJoint( pelvisJoint );
351 if ( !pelvisJoint )
352 {
353 llwarns << getName() << ": Can't get pelvis joint." << llendl;
354 return STATUS_FAILURE;
355 }
356
357 mPelvisState.setUsage(LLJointState::POS | LLJointState::ROT);
358 addJointState( &mPelvisState );
359
360 return STATUS_SUCCESS;
361}
362
363//-----------------------------------------------------------------------------
364// LLFlyAdjustMotion::onActivate()
365//-----------------------------------------------------------------------------
366BOOL LLFlyAdjustMotion::onActivate()
367{
368 mPelvisState.setPosition(LLVector3::zero);
369 mPelvisState.setRotation(LLQuaternion::DEFAULT);
370 mRoll = 0.f;
371 return TRUE;
372}
373
374//-----------------------------------------------------------------------------
375// LLFlyAdjustMotion::onUpdate()
376//-----------------------------------------------------------------------------
377BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
378{
379 LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
380 F32 speed = mCharacter->getCharacterVelocity().magVec();
381
382 F32 roll_factor = clamp_rescale(speed, 7.f, 15.f, 0.f, -MAX_ROLL);
383 F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor;
384
385 // roll is critically damped interpolation between current roll and angular velocity-derived target roll
386 mRoll = lerp(mRoll, target_roll, LLCriticalDamp::getInterpolant(0.1f));
387
388// llinfos << mRoll << llendl;
389
390 LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));
391 mPelvisState.setRotation(roll);
392
393// F32 lerp_amt = LLCriticalDamp::getInterpolant(0.2f);
394//
395// LLVector3 pelvis_correction = mPelvisState.getPosition() - lerp(LLVector3::zero, mPelvisState.getJoint()->getPosition() + mPelvisState.getPosition(), lerp_amt);
396// mPelvisState.setPosition(pelvis_correction);
397 return TRUE;
398}