1 | /**
|
---|
2 | * @author mikael emtinger / http://gomo.se/
|
---|
3 | * @author alteredq / http://alteredqualia.com/
|
---|
4 | * @author WestLangley / http://github.com/WestLangley
|
---|
5 | * @author bhouston / http://exocortex.com
|
---|
6 | */
|
---|
7 |
|
---|
8 | THREE.Quaternion = function ( x, y, z, w ) {
|
---|
9 |
|
---|
10 | this._x = x || 0;
|
---|
11 | this._y = y || 0;
|
---|
12 | this._z = z || 0;
|
---|
13 | this._w = ( w !== undefined ) ? w : 1;
|
---|
14 |
|
---|
15 | };
|
---|
16 |
|
---|
17 | THREE.Quaternion.prototype = {
|
---|
18 |
|
---|
19 | constructor: THREE.Quaternion,
|
---|
20 |
|
---|
21 | _x: 0,_y: 0, _z: 0, _w: 0,
|
---|
22 |
|
---|
23 | _euler: undefined,
|
---|
24 |
|
---|
25 | _updateEuler: function ( callback ) {
|
---|
26 |
|
---|
27 | if ( this._euler !== undefined ) {
|
---|
28 |
|
---|
29 | this._euler.setFromQuaternion( this, undefined, false );
|
---|
30 |
|
---|
31 | }
|
---|
32 |
|
---|
33 | },
|
---|
34 |
|
---|
35 | get x () {
|
---|
36 |
|
---|
37 | return this._x;
|
---|
38 |
|
---|
39 | },
|
---|
40 |
|
---|
41 | set x ( value ) {
|
---|
42 |
|
---|
43 | this._x = value;
|
---|
44 | this._updateEuler();
|
---|
45 |
|
---|
46 | },
|
---|
47 |
|
---|
48 | get y () {
|
---|
49 |
|
---|
50 | return this._y;
|
---|
51 |
|
---|
52 | },
|
---|
53 |
|
---|
54 | set y ( value ) {
|
---|
55 |
|
---|
56 | this._y = value;
|
---|
57 | this._updateEuler();
|
---|
58 |
|
---|
59 | },
|
---|
60 |
|
---|
61 | get z () {
|
---|
62 |
|
---|
63 | return this._z;
|
---|
64 |
|
---|
65 | },
|
---|
66 |
|
---|
67 | set z ( value ) {
|
---|
68 |
|
---|
69 | this._z = value;
|
---|
70 | this._updateEuler();
|
---|
71 |
|
---|
72 | },
|
---|
73 |
|
---|
74 | get w () {
|
---|
75 |
|
---|
76 | return this._w;
|
---|
77 |
|
---|
78 | },
|
---|
79 |
|
---|
80 | set w ( value ) {
|
---|
81 |
|
---|
82 | this._w = value;
|
---|
83 | this._updateEuler();
|
---|
84 |
|
---|
85 | },
|
---|
86 |
|
---|
87 | set: function ( x, y, z, w ) {
|
---|
88 |
|
---|
89 | this._x = x;
|
---|
90 | this._y = y;
|
---|
91 | this._z = z;
|
---|
92 | this._w = w;
|
---|
93 |
|
---|
94 | this._updateEuler();
|
---|
95 |
|
---|
96 | return this;
|
---|
97 |
|
---|
98 | },
|
---|
99 |
|
---|
100 | copy: function ( quaternion ) {
|
---|
101 |
|
---|
102 | this._x = quaternion._x;
|
---|
103 | this._y = quaternion._y;
|
---|
104 | this._z = quaternion._z;
|
---|
105 | this._w = quaternion._w;
|
---|
106 |
|
---|
107 | this._updateEuler();
|
---|
108 |
|
---|
109 | return this;
|
---|
110 |
|
---|
111 | },
|
---|
112 |
|
---|
113 | setFromEuler: function ( euler, update ) {
|
---|
114 |
|
---|
115 | if ( euler instanceof THREE.Euler === false ) {
|
---|
116 |
|
---|
117 | throw new Error( 'ERROR: Quaternion\'s .setFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' );
|
---|
118 | }
|
---|
119 |
|
---|
120 | // http://www.mathworks.com/matlabcentral/fileexchange/
|
---|
121 | // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
|
---|
122 | // content/SpinCalc.m
|
---|
123 |
|
---|
124 | var c1 = Math.cos( euler._x / 2 );
|
---|
125 | var c2 = Math.cos( euler._y / 2 );
|
---|
126 | var c3 = Math.cos( euler._z / 2 );
|
---|
127 | var s1 = Math.sin( euler._x / 2 );
|
---|
128 | var s2 = Math.sin( euler._y / 2 );
|
---|
129 | var s3 = Math.sin( euler._z / 2 );
|
---|
130 |
|
---|
131 | if ( euler.order === 'XYZ' ) {
|
---|
132 |
|
---|
133 | this._x = s1 * c2 * c3 + c1 * s2 * s3;
|
---|
134 | this._y = c1 * s2 * c3 - s1 * c2 * s3;
|
---|
135 | this._z = c1 * c2 * s3 + s1 * s2 * c3;
|
---|
136 | this._w = c1 * c2 * c3 - s1 * s2 * s3;
|
---|
137 |
|
---|
138 | } else if ( euler.order === 'YXZ' ) {
|
---|
139 |
|
---|
140 | this._x = s1 * c2 * c3 + c1 * s2 * s3;
|
---|
141 | this._y = c1 * s2 * c3 - s1 * c2 * s3;
|
---|
142 | this._z = c1 * c2 * s3 - s1 * s2 * c3;
|
---|
143 | this._w = c1 * c2 * c3 + s1 * s2 * s3;
|
---|
144 |
|
---|
145 | } else if ( euler.order === 'ZXY' ) {
|
---|
146 |
|
---|
147 | this._x = s1 * c2 * c3 - c1 * s2 * s3;
|
---|
148 | this._y = c1 * s2 * c3 + s1 * c2 * s3;
|
---|
149 | this._z = c1 * c2 * s3 + s1 * s2 * c3;
|
---|
150 | this._w = c1 * c2 * c3 - s1 * s2 * s3;
|
---|
151 |
|
---|
152 | } else if ( euler.order === 'ZYX' ) {
|
---|
153 |
|
---|
154 | this._x = s1 * c2 * c3 - c1 * s2 * s3;
|
---|
155 | this._y = c1 * s2 * c3 + s1 * c2 * s3;
|
---|
156 | this._z = c1 * c2 * s3 - s1 * s2 * c3;
|
---|
157 | this._w = c1 * c2 * c3 + s1 * s2 * s3;
|
---|
158 |
|
---|
159 | } else if ( euler.order === 'YZX' ) {
|
---|
160 |
|
---|
161 | this._x = s1 * c2 * c3 + c1 * s2 * s3;
|
---|
162 | this._y = c1 * s2 * c3 + s1 * c2 * s3;
|
---|
163 | this._z = c1 * c2 * s3 - s1 * s2 * c3;
|
---|
164 | this._w = c1 * c2 * c3 - s1 * s2 * s3;
|
---|
165 |
|
---|
166 | } else if ( euler.order === 'XZY' ) {
|
---|
167 |
|
---|
168 | this._x = s1 * c2 * c3 - c1 * s2 * s3;
|
---|
169 | this._y = c1 * s2 * c3 - s1 * c2 * s3;
|
---|
170 | this._z = c1 * c2 * s3 + s1 * s2 * c3;
|
---|
171 | this._w = c1 * c2 * c3 + s1 * s2 * s3;
|
---|
172 |
|
---|
173 | }
|
---|
174 |
|
---|
175 | if ( update !== false ) this._updateEuler();
|
---|
176 |
|
---|
177 | return this;
|
---|
178 |
|
---|
179 | },
|
---|
180 |
|
---|
181 | setFromAxisAngle: function ( axis, angle ) {
|
---|
182 |
|
---|
183 | // from http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
|
---|
184 | // axis have to be normalized
|
---|
185 |
|
---|
186 | var halfAngle = angle / 2, s = Math.sin( halfAngle );
|
---|
187 |
|
---|
188 | this._x = axis.x * s;
|
---|
189 | this._y = axis.y * s;
|
---|
190 | this._z = axis.z * s;
|
---|
191 | this._w = Math.cos( halfAngle );
|
---|
192 |
|
---|
193 | this._updateEuler();
|
---|
194 |
|
---|
195 | return this;
|
---|
196 |
|
---|
197 | },
|
---|
198 |
|
---|
199 | setFromRotationMatrix: function ( m ) {
|
---|
200 |
|
---|
201 | // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
|
---|
202 |
|
---|
203 | // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
|
---|
204 |
|
---|
205 | var te = m.elements,
|
---|
206 |
|
---|
207 | m11 = te[0], m12 = te[4], m13 = te[8],
|
---|
208 | m21 = te[1], m22 = te[5], m23 = te[9],
|
---|
209 | m31 = te[2], m32 = te[6], m33 = te[10],
|
---|
210 |
|
---|
211 | trace = m11 + m22 + m33,
|
---|
212 | s;
|
---|
213 |
|
---|
214 | if ( trace > 0 ) {
|
---|
215 |
|
---|
216 | s = 0.5 / Math.sqrt( trace + 1.0 );
|
---|
217 |
|
---|
218 | this._w = 0.25 / s;
|
---|
219 | this._x = ( m32 - m23 ) * s;
|
---|
220 | this._y = ( m13 - m31 ) * s;
|
---|
221 | this._z = ( m21 - m12 ) * s;
|
---|
222 |
|
---|
223 | } else if ( m11 > m22 && m11 > m33 ) {
|
---|
224 |
|
---|
225 | s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
|
---|
226 |
|
---|
227 | this._w = (m32 - m23 ) / s;
|
---|
228 | this._x = 0.25 * s;
|
---|
229 | this._y = (m12 + m21 ) / s;
|
---|
230 | this._z = (m13 + m31 ) / s;
|
---|
231 |
|
---|
232 | } else if ( m22 > m33 ) {
|
---|
233 |
|
---|
234 | s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
|
---|
235 |
|
---|
236 | this._w = (m13 - m31 ) / s;
|
---|
237 | this._x = (m12 + m21 ) / s;
|
---|
238 | this._y = 0.25 * s;
|
---|
239 | this._z = (m23 + m32 ) / s;
|
---|
240 |
|
---|
241 | } else {
|
---|
242 |
|
---|
243 | s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
|
---|
244 |
|
---|
245 | this._w = ( m21 - m12 ) / s;
|
---|
246 | this._x = ( m13 + m31 ) / s;
|
---|
247 | this._y = ( m23 + m32 ) / s;
|
---|
248 | this._z = 0.25 * s;
|
---|
249 |
|
---|
250 | }
|
---|
251 |
|
---|
252 | this._updateEuler();
|
---|
253 |
|
---|
254 | return this;
|
---|
255 |
|
---|
256 | },
|
---|
257 |
|
---|
258 | inverse: function () {
|
---|
259 |
|
---|
260 | this.conjugate().normalize();
|
---|
261 |
|
---|
262 | return this;
|
---|
263 |
|
---|
264 | },
|
---|
265 |
|
---|
266 | conjugate: function () {
|
---|
267 |
|
---|
268 | this._x *= -1;
|
---|
269 | this._y *= -1;
|
---|
270 | this._z *= -1;
|
---|
271 |
|
---|
272 | this._updateEuler();
|
---|
273 |
|
---|
274 | return this;
|
---|
275 |
|
---|
276 | },
|
---|
277 |
|
---|
278 | lengthSq: function () {
|
---|
279 |
|
---|
280 | return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
|
---|
281 |
|
---|
282 | },
|
---|
283 |
|
---|
284 | length: function () {
|
---|
285 |
|
---|
286 | return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
|
---|
287 |
|
---|
288 | },
|
---|
289 |
|
---|
290 | normalize: function () {
|
---|
291 |
|
---|
292 | var l = this.length();
|
---|
293 |
|
---|
294 | if ( l === 0 ) {
|
---|
295 |
|
---|
296 | this._x = 0;
|
---|
297 | this._y = 0;
|
---|
298 | this._z = 0;
|
---|
299 | this._w = 1;
|
---|
300 |
|
---|
301 | } else {
|
---|
302 |
|
---|
303 | l = 1 / l;
|
---|
304 |
|
---|
305 | this._x = this._x * l;
|
---|
306 | this._y = this._y * l;
|
---|
307 | this._z = this._z * l;
|
---|
308 | this._w = this._w * l;
|
---|
309 |
|
---|
310 | }
|
---|
311 |
|
---|
312 | return this;
|
---|
313 |
|
---|
314 | },
|
---|
315 |
|
---|
316 | multiply: function ( q, p ) {
|
---|
317 |
|
---|
318 | if ( p !== undefined ) {
|
---|
319 |
|
---|
320 | console.warn( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
|
---|
321 | return this.multiplyQuaternions( q, p );
|
---|
322 |
|
---|
323 | }
|
---|
324 |
|
---|
325 | return this.multiplyQuaternions( this, q );
|
---|
326 |
|
---|
327 | },
|
---|
328 |
|
---|
329 | multiplyQuaternions: function ( a, b ) {
|
---|
330 |
|
---|
331 | // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
|
---|
332 |
|
---|
333 | var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
|
---|
334 | var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
|
---|
335 |
|
---|
336 | this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
|
---|
337 | this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
|
---|
338 | this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
|
---|
339 | this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
|
---|
340 |
|
---|
341 | this._updateEuler();
|
---|
342 |
|
---|
343 | return this;
|
---|
344 |
|
---|
345 | },
|
---|
346 |
|
---|
347 | multiplyVector3: function ( vector ) {
|
---|
348 |
|
---|
349 | console.warn( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
|
---|
350 | return vector.applyQuaternion( this );
|
---|
351 |
|
---|
352 | },
|
---|
353 |
|
---|
354 | slerp: function ( qb, t ) {
|
---|
355 |
|
---|
356 | var x = this._x, y = this._y, z = this._z, w = this._w;
|
---|
357 |
|
---|
358 | // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
|
---|
359 |
|
---|
360 | var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
|
---|
361 |
|
---|
362 | if ( cosHalfTheta < 0 ) {
|
---|
363 |
|
---|
364 | this._w = -qb._w;
|
---|
365 | this._x = -qb._x;
|
---|
366 | this._y = -qb._y;
|
---|
367 | this._z = -qb._z;
|
---|
368 |
|
---|
369 | cosHalfTheta = -cosHalfTheta;
|
---|
370 |
|
---|
371 | } else {
|
---|
372 |
|
---|
373 | this.copy( qb );
|
---|
374 |
|
---|
375 | }
|
---|
376 |
|
---|
377 | if ( cosHalfTheta >= 1.0 ) {
|
---|
378 |
|
---|
379 | this._w = w;
|
---|
380 | this._x = x;
|
---|
381 | this._y = y;
|
---|
382 | this._z = z;
|
---|
383 |
|
---|
384 | return this;
|
---|
385 |
|
---|
386 | }
|
---|
387 |
|
---|
388 | var halfTheta = Math.acos( cosHalfTheta );
|
---|
389 | var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
|
---|
390 |
|
---|
391 | if ( Math.abs( sinHalfTheta ) < 0.001 ) {
|
---|
392 |
|
---|
393 | this._w = 0.5 * ( w + this._w );
|
---|
394 | this._x = 0.5 * ( x + this._x );
|
---|
395 | this._y = 0.5 * ( y + this._y );
|
---|
396 | this._z = 0.5 * ( z + this._z );
|
---|
397 |
|
---|
398 | return this;
|
---|
399 |
|
---|
400 | }
|
---|
401 |
|
---|
402 | var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
|
---|
403 | ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
|
---|
404 |
|
---|
405 | this._w = ( w * ratioA + this._w * ratioB );
|
---|
406 | this._x = ( x * ratioA + this._x * ratioB );
|
---|
407 | this._y = ( y * ratioA + this._y * ratioB );
|
---|
408 | this._z = ( z * ratioA + this._z * ratioB );
|
---|
409 |
|
---|
410 | this._updateEuler();
|
---|
411 |
|
---|
412 | return this;
|
---|
413 |
|
---|
414 | },
|
---|
415 |
|
---|
416 | equals: function ( quaternion ) {
|
---|
417 |
|
---|
418 | return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
|
---|
419 |
|
---|
420 | },
|
---|
421 |
|
---|
422 | fromArray: function ( array ) {
|
---|
423 |
|
---|
424 | this._x = array[ 0 ];
|
---|
425 | this._y = array[ 1 ];
|
---|
426 | this._z = array[ 2 ];
|
---|
427 | this._w = array[ 3 ];
|
---|
428 |
|
---|
429 | this._updateEuler();
|
---|
430 |
|
---|
431 | return this;
|
---|
432 |
|
---|
433 | },
|
---|
434 |
|
---|
435 | toArray: function () {
|
---|
436 |
|
---|
437 | return [ this._x, this._y, this._z, this._w ];
|
---|
438 |
|
---|
439 | },
|
---|
440 |
|
---|
441 | clone: function () {
|
---|
442 |
|
---|
443 | return new THREE.Quaternion( this._x, this._y, this._z, this._w );
|
---|
444 |
|
---|
445 | }
|
---|
446 |
|
---|
447 | };
|
---|
448 |
|
---|
449 | THREE.Quaternion.slerp = function ( qa, qb, qm, t ) {
|
---|
450 |
|
---|
451 | return qm.copy( qa ).slerp( qb, t );
|
---|
452 |
|
---|
453 | }
|
---|