diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llcharacter/llkeyframewalkmotion.cpp | |
parent | README.txt (diff) | |
download | meta-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.cpp | 398 |
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 | //----------------------------------------------------------------------------- | ||
42 | const F32 MAX_WALK_PLAYBACK_SPEED = 8.f; // max m/s for which we adjust walk cycle speed | ||
43 | |||
44 | const F32 MIN_WALK_SPEED = 0.1f; // minimum speed at which we use velocity for down foot detection | ||
45 | const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation | ||
46 | const F32 SPEED_ADJUST_MAX = 2.5f; // maximum adjustment of walk animation playback speed | ||
47 | const F32 SPEED_ADJUST_MAX_SEC = 3.f; // maximum adjustment to walk animation playback speed for a second | ||
48 | const F32 DRIFT_COMP_MAX_TOTAL = 0.07f;//0.55f; // maximum drift compensation overall, in any direction | ||
49 | const F32 DRIFT_COMP_MAX_SPEED = 4.f; // speed at which drift compensation total maxes out | ||
50 | const F32 MAX_ROLL = 0.6f; | ||
51 | |||
52 | //----------------------------------------------------------------------------- | ||
53 | // LLKeyframeWalkMotion() | ||
54 | // Class Constructor | ||
55 | //----------------------------------------------------------------------------- | ||
56 | LLKeyframeWalkMotion::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 | //----------------------------------------------------------------------------- | ||
68 | LLKeyframeWalkMotion::~LLKeyframeWalkMotion() | ||
69 | { | ||
70 | } | ||
71 | |||
72 | |||
73 | //----------------------------------------------------------------------------- | ||
74 | // LLKeyframeWalkMotion::onInitialize() | ||
75 | //----------------------------------------------------------------------------- | ||
76 | LLMotion::LLMotionInitStatus LLKeyframeWalkMotion::onInitialize(LLCharacter *character) | ||
77 | { | ||
78 | mCharacter = character; | ||
79 | |||
80 | return LLKeyframeMotion::onInitialize(character); | ||
81 | } | ||
82 | |||
83 | //----------------------------------------------------------------------------- | ||
84 | // LLKeyframeWalkMotion::onActivate() | ||
85 | //----------------------------------------------------------------------------- | ||
86 | BOOL LLKeyframeWalkMotion::onActivate() | ||
87 | { | ||
88 | mRealTimeLast = 0.0f; | ||
89 | mAdjTimeLast = 0.0f; | ||
90 | |||
91 | return LLKeyframeMotion::onActivate(); | ||
92 | } | ||
93 | |||
94 | //----------------------------------------------------------------------------- | ||
95 | // LLKeyframeWalkMotion::onDeactivate() | ||
96 | //----------------------------------------------------------------------------- | ||
97 | void LLKeyframeWalkMotion::onDeactivate() | ||
98 | { | ||
99 | mCharacter->removeAnimationData("Down Foot"); | ||
100 | LLKeyframeMotion::onDeactivate(); | ||
101 | } | ||
102 | |||
103 | //----------------------------------------------------------------------------- | ||
104 | // LLKeyframeWalkMotion::onUpdate() | ||
105 | //----------------------------------------------------------------------------- | ||
106 | BOOL 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 | //----------------------------------------------------------------------------- | ||
138 | LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) : LLMotion(id) | ||
139 | { | ||
140 | mLastTime = 0.f; | ||
141 | mName = "walk_adjust"; | ||
142 | } | ||
143 | |||
144 | //----------------------------------------------------------------------------- | ||
145 | // LLWalkAdjustMotion::onInitialize() | ||
146 | //----------------------------------------------------------------------------- | ||
147 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
170 | BOOL 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 | //----------------------------------------------------------------------------- | ||
192 | BOOL 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 | //----------------------------------------------------------------------------- | ||
337 | void LLWalkAdjustMotion::onDeactivate() | ||
338 | { | ||
339 | mCharacter->removeAnimationData("Walk Speed"); | ||
340 | } | ||
341 | |||
342 | //----------------------------------------------------------------------------- | ||
343 | // LLFlyAdjustMotion::onInitialize() | ||
344 | //----------------------------------------------------------------------------- | ||
345 | LLMotion::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 | //----------------------------------------------------------------------------- | ||
366 | BOOL 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 | //----------------------------------------------------------------------------- | ||
377 | BOOL 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 | } | ||