diff options
Diffstat (limited to 'linden/indra/llcharacter/llheadrotmotion.cpp')
-rw-r--r-- | linden/indra/llcharacter/llheadrotmotion.cpp | 524 |
1 files changed, 524 insertions, 0 deletions
diff --git a/linden/indra/llcharacter/llheadrotmotion.cpp b/linden/indra/llcharacter/llheadrotmotion.cpp new file mode 100644 index 0000000..3bf7be0 --- /dev/null +++ b/linden/indra/llcharacter/llheadrotmotion.cpp | |||
@@ -0,0 +1,524 @@ | |||
1 | /** | ||
2 | * @file llheadrotmotion.cpp | ||
3 | * @brief Implementation of LLHeadRotMotion 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 "llheadrotmotion.h" | ||
34 | #include "llcharacter.h" | ||
35 | #include "llrand.h" | ||
36 | #include "m3math.h" | ||
37 | #include "v3dmath.h" | ||
38 | #include "llcriticaldamp.h" | ||
39 | |||
40 | //----------------------------------------------------------------------------- | ||
41 | // Constants | ||
42 | //----------------------------------------------------------------------------- | ||
43 | const F32 TORSO_LAG = 0.35f; // torso rotation factor | ||
44 | const F32 NECK_LAG = 0.5f; // neck rotation factor | ||
45 | const F32 HEAD_LOOKAT_LAG_HALF_LIFE = 0.15f; // half-life of lookat targeting for head | ||
46 | const F32 TORSO_LOOKAT_LAG_HALF_LIFE = 0.27f; // half-life of lookat targeting for torso | ||
47 | const F32 EYE_LOOKAT_LAG_HALF_LIFE = 0.06f; // half-life of lookat targeting for eye | ||
48 | const F32 HEAD_ROTATION_CONSTRAINT = F_PI_BY_TWO * 0.8f; // limit angle for head rotation | ||
49 | |||
50 | const F32 MIN_HEAD_LOOKAT_DISTANCE = 0.3f; // minimum distance from head before we turn to look at it | ||
51 | const F32 MAX_TIME_DELTA = 2.f; //max two seconds a frame for calculating interpolation | ||
52 | const F32 EYE_JITTER_MIN_TIME = 0.3f; // min amount of time between eye "jitter" motions | ||
53 | const F32 EYE_JITTER_MAX_TIME = 2.5f; // max amount of time between eye "jitter" motions | ||
54 | const F32 EYE_JITTER_MAX_YAW = 0.08f; // max yaw of eye jitter motion | ||
55 | const F32 EYE_JITTER_MAX_PITCH = 0.015f; // max pitch of eye jitter motion | ||
56 | const F32 EYE_LOOK_AWAY_MIN_TIME = 5.f; // min amount of time between eye "look away" motions | ||
57 | const F32 EYE_LOOK_AWAY_MAX_TIME = 15.f; // max amount of time between eye "look away" motions | ||
58 | const F32 EYE_LOOK_BACK_MIN_TIME = 1.f; // min amount of time before looking back after looking away | ||
59 | const F32 EYE_LOOK_BACK_MAX_TIME = 5.f; // max amount of time before looking back after looking away | ||
60 | const F32 EYE_LOOK_AWAY_MAX_YAW = 0.15f; // max yaw of eye look away motion | ||
61 | const F32 EYE_LOOK_AWAY_MAX_PITCH = 0.12f; // max pitch of look away motion | ||
62 | const F32 EYE_ROT_LIMIT_ANGLE = F_PI_BY_TWO * 0.3f; //max angle in radians for eye rotation | ||
63 | |||
64 | const F32 EYE_BLINK_MIN_TIME = 0.5f; // minimum amount of time between blinks | ||
65 | const F32 EYE_BLINK_MAX_TIME = 8.f; // maximum amount of time between blinks | ||
66 | const F32 EYE_BLINK_CLOSE_TIME = 0.03f; // how long the eye stays closed in a blink | ||
67 | const F32 EYE_BLINK_SPEED = 0.015f; // seconds it takes for a eye open/close movement | ||
68 | const F32 EYE_BLINK_TIME_DELTA = 0.005f; // time between one eye starting a blink and the other following | ||
69 | |||
70 | //----------------------------------------------------------------------------- | ||
71 | // LLHeadRotMotion() | ||
72 | // Class Constructor | ||
73 | //----------------------------------------------------------------------------- | ||
74 | LLHeadRotMotion::LLHeadRotMotion(const LLUUID &id) : | ||
75 | LLMotion(id), | ||
76 | mCharacter(NULL), | ||
77 | mTorsoJoint(NULL), | ||
78 | mHeadJoint(NULL) | ||
79 | { | ||
80 | mName = "head_rot"; | ||
81 | } | ||
82 | |||
83 | |||
84 | //----------------------------------------------------------------------------- | ||
85 | // ~LLHeadRotMotion() | ||
86 | // Class Destructor | ||
87 | //----------------------------------------------------------------------------- | ||
88 | LLHeadRotMotion::~LLHeadRotMotion() | ||
89 | { | ||
90 | } | ||
91 | |||
92 | //----------------------------------------------------------------------------- | ||
93 | // LLHeadRotMotion::onInitialize(LLCharacter *character) | ||
94 | //----------------------------------------------------------------------------- | ||
95 | LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *character) | ||
96 | { | ||
97 | if (!character) | ||
98 | return STATUS_FAILURE; | ||
99 | mCharacter = character; | ||
100 | |||
101 | mPelvisJoint = character->getJoint("mPelvis"); | ||
102 | if ( ! mPelvisJoint ) | ||
103 | { | ||
104 | llinfos << getName() << ": Can't get pelvis joint." << llendl; | ||
105 | return STATUS_FAILURE; | ||
106 | } | ||
107 | |||
108 | mRootJoint = character->getJoint("mRoot"); | ||
109 | if ( ! mRootJoint ) | ||
110 | { | ||
111 | llinfos << getName() << ": Can't get root joint." << llendl; | ||
112 | return STATUS_FAILURE; | ||
113 | } | ||
114 | |||
115 | mTorsoJoint = character->getJoint("mTorso"); | ||
116 | if ( ! mTorsoJoint ) | ||
117 | { | ||
118 | llinfos << getName() << ": Can't get torso joint." << llendl; | ||
119 | return STATUS_FAILURE; | ||
120 | } | ||
121 | |||
122 | mHeadJoint = character->getJoint("mHead"); | ||
123 | if ( ! mHeadJoint ) | ||
124 | { | ||
125 | llinfos << getName() << ": Can't get head joint." << llendl; | ||
126 | return STATUS_FAILURE; | ||
127 | } | ||
128 | |||
129 | mTorsoState.setJoint( character->getJoint("mTorso") ); | ||
130 | if ( ! mTorsoState.getJoint() ) | ||
131 | { | ||
132 | llinfos << getName() << ": Can't get torso joint." << llendl; | ||
133 | return STATUS_FAILURE; | ||
134 | } | ||
135 | |||
136 | mNeckState.setJoint( character->getJoint("mNeck") ); | ||
137 | if ( ! mNeckState.getJoint() ) | ||
138 | { | ||
139 | llinfos << getName() << ": Can't get neck joint." << llendl; | ||
140 | return STATUS_FAILURE; | ||
141 | } | ||
142 | |||
143 | mHeadState.setJoint( character->getJoint("mHead") ); | ||
144 | if ( ! mHeadState.getJoint() ) | ||
145 | { | ||
146 | llinfos << getName() << ": Can't get head joint." << llendl; | ||
147 | return STATUS_FAILURE; | ||
148 | } | ||
149 | |||
150 | mTorsoState.setUsage(LLJointState::ROT); | ||
151 | mNeckState.setUsage(LLJointState::ROT); | ||
152 | mHeadState.setUsage(LLJointState::ROT); | ||
153 | |||
154 | addJointState( &mTorsoState ); | ||
155 | addJointState( &mNeckState ); | ||
156 | addJointState( &mHeadState ); | ||
157 | |||
158 | mLastHeadRot.loadIdentity(); | ||
159 | |||
160 | return STATUS_SUCCESS; | ||
161 | } | ||
162 | |||
163 | |||
164 | //----------------------------------------------------------------------------- | ||
165 | // LLHeadRotMotion::onActivate() | ||
166 | //----------------------------------------------------------------------------- | ||
167 | BOOL LLHeadRotMotion::onActivate() | ||
168 | { | ||
169 | return TRUE; | ||
170 | } | ||
171 | |||
172 | |||
173 | //----------------------------------------------------------------------------- | ||
174 | // LLHeadRotMotion::onUpdate() | ||
175 | //----------------------------------------------------------------------------- | ||
176 | BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask) | ||
177 | { | ||
178 | LLQuaternion targetHeadRotWorld; | ||
179 | LLQuaternion currentRootRotWorld = mRootJoint->getWorldRotation(); | ||
180 | LLQuaternion currentInvRootRotWorld = ~currentRootRotWorld; | ||
181 | |||
182 | F32 head_slerp_amt = LLCriticalDamp::getInterpolant(HEAD_LOOKAT_LAG_HALF_LIFE); | ||
183 | F32 torso_slerp_amt = LLCriticalDamp::getInterpolant(TORSO_LOOKAT_LAG_HALF_LIFE); | ||
184 | |||
185 | LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint"); | ||
186 | |||
187 | if (targetPos) | ||
188 | { | ||
189 | LLVector3 headLookAt = *targetPos; | ||
190 | |||
191 | // llinfos << "Look At: " << headLookAt + mHeadJoint->getWorldPosition() << llendl; | ||
192 | |||
193 | F32 lookatDistance = headLookAt.normVec(); | ||
194 | |||
195 | if (lookatDistance < MIN_HEAD_LOOKAT_DISTANCE) | ||
196 | { | ||
197 | targetHeadRotWorld = mPelvisJoint->getWorldRotation(); | ||
198 | } | ||
199 | else | ||
200 | { | ||
201 | LLVector3 root_up = LLVector3(0.f, 0.f, 1.f) * currentRootRotWorld; | ||
202 | LLVector3 left(root_up % headLookAt); | ||
203 | // if look_at has zero length, fail | ||
204 | // if look_at and skyward are parallel, fail | ||
205 | // | ||
206 | // Test both of these conditions with a cross product. | ||
207 | |||
208 | if (left.magVecSquared() < 0.15f) | ||
209 | { | ||
210 | LLVector3 root_at = LLVector3(1.f, 0.f, 0.f) * currentRootRotWorld; | ||
211 | root_at.mV[VZ] = 0.f; | ||
212 | root_at.normVec(); | ||
213 | |||
214 | headLookAt = lerp(headLookAt, root_at, 0.4f); | ||
215 | headLookAt.normVec(); | ||
216 | |||
217 | left = root_up % headLookAt; | ||
218 | } | ||
219 | |||
220 | // Make sure look_at and skyward and not parallel | ||
221 | // and neither are zero length | ||
222 | LLVector3 up(headLookAt % left); | ||
223 | |||
224 | targetHeadRotWorld = LLQuaternion(headLookAt, left, up); | ||
225 | } | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | targetHeadRotWorld = currentRootRotWorld; | ||
230 | } | ||
231 | |||
232 | LLQuaternion head_rot_local = targetHeadRotWorld * currentInvRootRotWorld; | ||
233 | head_rot_local.constrain(HEAD_ROTATION_CONSTRAINT); | ||
234 | |||
235 | // set final torso rotation | ||
236 | // Set torso target rotation such that it lags behind the head rotation | ||
237 | // by a fixed amount. | ||
238 | LLQuaternion torso_rot_local = nlerp(TORSO_LAG, LLQuaternion::DEFAULT, head_rot_local ); | ||
239 | mTorsoState.setRotation( nlerp(torso_slerp_amt, mTorsoState.getRotation(), torso_rot_local) ); | ||
240 | |||
241 | head_rot_local = nlerp(head_slerp_amt, mLastHeadRot, head_rot_local); | ||
242 | mLastHeadRot = head_rot_local; | ||
243 | |||
244 | // Set the head rotation. | ||
245 | LLQuaternion torsoRotLocal = mNeckState.getJoint()->getParent()->getWorldRotation() * currentInvRootRotWorld; | ||
246 | head_rot_local = head_rot_local * ~torsoRotLocal; | ||
247 | mNeckState.setRotation( nlerp(NECK_LAG, LLQuaternion::DEFAULT, head_rot_local) ); | ||
248 | mHeadState.setRotation( nlerp(1.f - NECK_LAG, LLQuaternion::DEFAULT, head_rot_local)); | ||
249 | |||
250 | return TRUE; | ||
251 | } | ||
252 | |||
253 | |||
254 | //----------------------------------------------------------------------------- | ||
255 | // LLHeadRotMotion::onDeactivate() | ||
256 | //----------------------------------------------------------------------------- | ||
257 | void LLHeadRotMotion::onDeactivate() | ||
258 | { | ||
259 | } | ||
260 | |||
261 | |||
262 | //----------------------------------------------------------------------------- | ||
263 | // LLEyeMotion() | ||
264 | // Class Constructor | ||
265 | //----------------------------------------------------------------------------- | ||
266 | LLEyeMotion::LLEyeMotion(const LLUUID &id) : LLMotion(id) | ||
267 | { | ||
268 | mCharacter = NULL; | ||
269 | mEyeJitterTime = 0.f; | ||
270 | mEyeJitterYaw = 0.f; | ||
271 | mEyeJitterPitch = 0.f; | ||
272 | |||
273 | mEyeLookAwayTime = 0.f; | ||
274 | mEyeLookAwayYaw = 0.f; | ||
275 | mEyeLookAwayPitch = 0.f; | ||
276 | |||
277 | mEyeBlinkTime = 0.f; | ||
278 | mEyesClosed = FALSE; | ||
279 | |||
280 | mHeadJoint = NULL; | ||
281 | |||
282 | mName = "eye_rot"; | ||
283 | } | ||
284 | |||
285 | |||
286 | //----------------------------------------------------------------------------- | ||
287 | // ~LLEyeMotion() | ||
288 | // Class Destructor | ||
289 | //----------------------------------------------------------------------------- | ||
290 | LLEyeMotion::~LLEyeMotion() | ||
291 | { | ||
292 | } | ||
293 | |||
294 | //----------------------------------------------------------------------------- | ||
295 | // LLEyeMotion::onInitialize(LLCharacter *character) | ||
296 | //----------------------------------------------------------------------------- | ||
297 | LLMotion::LLMotionInitStatus LLEyeMotion::onInitialize(LLCharacter *character) | ||
298 | { | ||
299 | mCharacter = character; | ||
300 | |||
301 | mHeadJoint = character->getJoint("mHead"); | ||
302 | if ( ! mHeadJoint ) | ||
303 | { | ||
304 | llinfos << getName() << ": Can't get head joint." << llendl; | ||
305 | return STATUS_FAILURE; | ||
306 | } | ||
307 | |||
308 | mLeftEyeState.setJoint( character->getJoint("mEyeLeft") ); | ||
309 | if ( ! mLeftEyeState.getJoint() ) | ||
310 | { | ||
311 | llinfos << getName() << ": Can't get left eyeball joint." << llendl; | ||
312 | return STATUS_FAILURE; | ||
313 | } | ||
314 | |||
315 | mRightEyeState.setJoint( character->getJoint("mEyeRight") ); | ||
316 | if ( ! mRightEyeState.getJoint() ) | ||
317 | { | ||
318 | llinfos << getName() << ": Can't get Right eyeball joint." << llendl; | ||
319 | return STATUS_FAILURE; | ||
320 | } | ||
321 | |||
322 | mLeftEyeState.setUsage(LLJointState::ROT); | ||
323 | mRightEyeState.setUsage(LLJointState::ROT); | ||
324 | |||
325 | addJointState( &mLeftEyeState ); | ||
326 | addJointState( &mRightEyeState ); | ||
327 | |||
328 | return STATUS_SUCCESS; | ||
329 | } | ||
330 | |||
331 | |||
332 | //----------------------------------------------------------------------------- | ||
333 | // LLEyeMotion::onActivate() | ||
334 | //----------------------------------------------------------------------------- | ||
335 | BOOL LLEyeMotion::onActivate() | ||
336 | { | ||
337 | return TRUE; | ||
338 | } | ||
339 | |||
340 | |||
341 | //----------------------------------------------------------------------------- | ||
342 | // LLEyeMotion::onUpdate() | ||
343 | //----------------------------------------------------------------------------- | ||
344 | BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask) | ||
345 | { | ||
346 | // Compute eye rotation. | ||
347 | LLQuaternion target_eye_rot; | ||
348 | LLVector3 eye_look_at; | ||
349 | F32 vergence; | ||
350 | |||
351 | //calculate jitter | ||
352 | if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime) | ||
353 | { | ||
354 | mEyeJitterTime = EYE_JITTER_MIN_TIME + frand(EYE_JITTER_MAX_TIME - EYE_JITTER_MIN_TIME); | ||
355 | mEyeJitterYaw = (frand(2.f) - 1.f) * EYE_JITTER_MAX_YAW; | ||
356 | mEyeJitterPitch = (frand(2.f) - 1.f) * EYE_JITTER_MAX_PITCH; | ||
357 | // make sure lookaway time count gets updated, because we're resetting the timer | ||
358 | mEyeLookAwayTime -= llmax(0.f, mEyeJitterTimer.getElapsedTimeF32()); | ||
359 | mEyeJitterTimer.reset(); | ||
360 | } | ||
361 | else if (mEyeJitterTimer.getElapsedTimeF32() > mEyeLookAwayTime) | ||
362 | { | ||
363 | if (frand(1.f) > 0.1f) | ||
364 | { | ||
365 | // blink while moving eyes some percentage of the time | ||
366 | mEyeBlinkTime = mEyeBlinkTimer.getElapsedTimeF32(); | ||
367 | } | ||
368 | if (mEyeLookAwayYaw == 0.f && mEyeLookAwayPitch == 0.f) | ||
369 | { | ||
370 | mEyeLookAwayYaw = (frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_YAW; | ||
371 | mEyeLookAwayPitch = (frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_PITCH; | ||
372 | mEyeLookAwayTime = EYE_LOOK_BACK_MIN_TIME + frand(EYE_LOOK_BACK_MAX_TIME - EYE_LOOK_BACK_MIN_TIME); | ||
373 | } | ||
374 | else | ||
375 | { | ||
376 | mEyeLookAwayYaw = 0.f; | ||
377 | mEyeLookAwayPitch = 0.f; | ||
378 | mEyeLookAwayTime = EYE_LOOK_AWAY_MIN_TIME + frand(EYE_LOOK_AWAY_MAX_TIME - EYE_LOOK_AWAY_MIN_TIME); | ||
379 | } | ||
380 | } | ||
381 | |||
382 | // do blinking | ||
383 | if (!mEyesClosed && mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime) | ||
384 | { | ||
385 | F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime; | ||
386 | F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA; | ||
387 | |||
388 | leftEyeBlinkMorph = llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); | ||
389 | rightEyeBlinkMorph = llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); | ||
390 | mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph); | ||
391 | mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph); | ||
392 | mCharacter->updateVisualParams(); | ||
393 | |||
394 | if (rightEyeBlinkMorph == 1.f) | ||
395 | { | ||
396 | mEyesClosed = TRUE; | ||
397 | mEyeBlinkTime = EYE_BLINK_CLOSE_TIME; | ||
398 | mEyeBlinkTimer.reset(); | ||
399 | } | ||
400 | } | ||
401 | else if (mEyesClosed) | ||
402 | { | ||
403 | if (mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime) | ||
404 | { | ||
405 | F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime; | ||
406 | F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA; | ||
407 | |||
408 | leftEyeBlinkMorph = 1.f - llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); | ||
409 | rightEyeBlinkMorph = 1.f - llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f); | ||
410 | mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph); | ||
411 | mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph); | ||
412 | mCharacter->updateVisualParams(); | ||
413 | |||
414 | if (rightEyeBlinkMorph == 0.f) | ||
415 | { | ||
416 | mEyesClosed = FALSE; | ||
417 | mEyeBlinkTime = EYE_BLINK_MIN_TIME + frand(EYE_BLINK_MAX_TIME - EYE_BLINK_MIN_TIME); | ||
418 | mEyeBlinkTimer.reset(); | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | BOOL has_eye_target = FALSE; | ||
424 | LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint"); | ||
425 | |||
426 | if (targetPos) | ||
427 | { | ||
428 | LLVector3 skyward(0.f, 0.f, 1.f); | ||
429 | LLVector3 left; | ||
430 | LLVector3 up; | ||
431 | |||
432 | eye_look_at = *targetPos; | ||
433 | F32 lookAtDistance = eye_look_at.normVec(); | ||
434 | |||
435 | left.setVec(skyward % eye_look_at); | ||
436 | up.setVec(eye_look_at % left); | ||
437 | |||
438 | target_eye_rot = LLQuaternion(eye_look_at, left, up); | ||
439 | |||
440 | // calculate vergence | ||
441 | F32 interocular_dist = (mLeftEyeState.getJoint()->getWorldPosition() - mRightEyeState.getJoint()->getWorldPosition()).magVec(); | ||
442 | vergence = -atan2((interocular_dist / 2.f), lookAtDistance); | ||
443 | llclamp(vergence, -F_PI_BY_TWO, 0.f); | ||
444 | } | ||
445 | else | ||
446 | { | ||
447 | target_eye_rot = mHeadJoint->getWorldRotation(); | ||
448 | vergence = 0.f; | ||
449 | } | ||
450 | |||
451 | //RN: subtract 4 degrees to account for foveal angular offset relative to pupil | ||
452 | vergence += 4.f * DEG_TO_RAD; | ||
453 | |||
454 | // calculate eye jitter | ||
455 | LLQuaternion eye_jitter_rot; | ||
456 | |||
457 | // vergence not too high... | ||
458 | if (vergence > -0.05f) | ||
459 | { | ||
460 | //...go ahead and jitter | ||
461 | eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw); | ||
462 | } | ||
463 | else | ||
464 | { | ||
465 | //...or don't | ||
466 | eye_jitter_rot.loadIdentity(); | ||
467 | } | ||
468 | |||
469 | // calculate vergence of eyes as an object gets closer to the avatar's head | ||
470 | LLQuaternion vergence_quat; | ||
471 | |||
472 | if (has_eye_target) | ||
473 | { | ||
474 | vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f)); | ||
475 | } | ||
476 | else | ||
477 | { | ||
478 | vergence_quat.loadIdentity(); | ||
479 | } | ||
480 | |||
481 | // calculate eye rotations | ||
482 | LLQuaternion left_eye_rot = target_eye_rot; | ||
483 | left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot; | ||
484 | |||
485 | LLQuaternion right_eye_rot = target_eye_rot; | ||
486 | vergence_quat.transQuat(); | ||
487 | right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot; | ||
488 | |||
489 | //set final eye rotations | ||
490 | // start with left | ||
491 | LLQuaternion tQw = mLeftEyeState.getJoint()->getParent()->getWorldRotation(); | ||
492 | LLQuaternion tQh = left_eye_rot * ~tQw; | ||
493 | tQh.constrain(EYE_ROT_LIMIT_ANGLE); | ||
494 | mLeftEyeState.setRotation( tQh ); | ||
495 | |||
496 | // now do right eye | ||
497 | tQw = mRightEyeState.getJoint()->getParent()->getWorldRotation(); | ||
498 | tQh = right_eye_rot * ~tQw; | ||
499 | tQh.constrain(EYE_ROT_LIMIT_ANGLE); | ||
500 | mRightEyeState.setRotation( tQh ); | ||
501 | |||
502 | return TRUE; | ||
503 | } | ||
504 | |||
505 | |||
506 | //----------------------------------------------------------------------------- | ||
507 | // LLEyeMotion::onDeactivate() | ||
508 | //----------------------------------------------------------------------------- | ||
509 | void LLEyeMotion::onDeactivate() | ||
510 | { | ||
511 | LLJoint* joint = mLeftEyeState.getJoint(); | ||
512 | if (joint) | ||
513 | { | ||
514 | joint->setRotation(LLQuaternion::DEFAULT); | ||
515 | } | ||
516 | |||
517 | joint = mRightEyeState.getJoint(); | ||
518 | if (joint) | ||
519 | { | ||
520 | joint->setRotation(LLQuaternion::DEFAULT); | ||
521 | } | ||
522 | } | ||
523 | |||
524 | // End | ||