/src/away3d/core/math/Matrix3DUtils.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 367 lines | 292 code | 41 blank | 34 comment | 25 complexity | a77b9aabe8ed50ddc2dc95bb9d8d7441 MD5 | raw file
```  1package away3d.core.math {
2	import flash.geom.*;
3
4	/**
5	 * Matrix3DUtils provides additional Matrix3D math functions.
6	 */
7	public class Matrix3DUtils {
8		/**
9		 * A reference to a Vector to be used as a temporary raw data container, to prevent object creation.
10		 */
11		public static const RAW_DATA_CONTAINER:Vector.<Number> = new Vector.<Number>(16);
12
13		public static const CALCULATION_MATRIX:Matrix3D = new Matrix3D();
14		public static const CALCULATION_VECTOR3D:Vector3D = new Vector3D();
15		public static const CALCULATION_DECOMPOSE:Vector.<Vector3D> = Vector.<Vector3D>([new Vector3D(), new Vector3D(), new Vector3D()]);
16
17		/**
18		 * Fills the 3d matrix object with values representing the transformation made by the given quaternion.
19		 *
20		 * @param    quarternion    The quarterion object to convert.
21		 */
22		public static function quaternion2matrix(quarternion:Quaternion, m:Matrix3D = null):Matrix3D {
23			var x:Number = quarternion.x;
24			var y:Number = quarternion.y;
25			var z:Number = quarternion.z;
26			var w:Number = quarternion.w;
27
28			var xx:Number = x * x;
29			var xy:Number = x * y;
30			var xz:Number = x * z;
31			var xw:Number = x * w;
32
33			var yy:Number = y * y;
34			var yz:Number = y * z;
35			var yw:Number = y * w;
36
37			var zz:Number = z * z;
38			var zw:Number = z * w;
39
40			var raw:Vector.<Number> = RAW_DATA_CONTAINER;
41			raw[0] = 1 - 2 * (yy + zz);
42			raw[1] = 2 * (xy + zw);
43			raw[2] = 2 * (xz - yw);
44			raw[4] = 2 * (xy - zw);
45			raw[5] = 1 - 2 * (xx + zz);
46			raw[6] = 2 * (yz + xw);
47			raw[8] = 2 * (xz + yw);
48			raw[9] = 2 * (yz - xw);
49			raw[10] = 1 - 2 * (xx + yy);
50			raw[3] = raw[7] = raw[11] = raw[12] = raw[13] = raw[14] = 0;
51			raw[15] = 1;
52
53			if (m) {
54				m.copyRawDataFrom(raw);
55				return m;
56			} else
57				return new Matrix3D(raw);
58		}
59
60		/**
61		 * Returns a normalised <code>Vector3D</code> object representing the forward vector of the given matrix.
62		 * @param    m        The Matrix3D object to use to get the forward vector
63		 * @param    v        [optional] A vector holder to prevent make new Vector3D instance if already exists. Default is null.
64		 * @return            The forward vector
65		 */
66		public static function getForward(m:Matrix3D, v:Vector3D = null):Vector3D {
67			if(!v) v = new Vector3D();
68			m.copyColumnTo(2, v);
69			v.normalize();
70
71			return v;
72		}
73
74		/**
75		 * Returns a normalised <code>Vector3D</code> object representing the up vector of the given matrix.
76		 * @param    m        The Matrix3D object to use to get the up vector
77		 * @param    v        [optional] A vector holder to prevent make new Vector3D instance if already exists. Default is null.
78		 * @return            The up vector
79		 */
80		public static function getUp(m:Matrix3D, v:Vector3D = null):Vector3D {
81			if(!v) v = new Vector3D();
82			m.copyColumnTo(1, v);
83			v.normalize();
84
85			return v;
86		}
87
88		/**
89		 * Returns a normalised <code>Vector3D</code> object representing the right vector of the given matrix.
90		 * @param    m        The Matrix3D object to use to get the right vector
91		 * @param    v        [optional] A vector holder to prevent make new Vector3D instance if already exists. Default is null.
92		 * @return            The right vector
93		 */
94		public static function getRight(m:Matrix3D, v:Vector3D = null):Vector3D {
95			if(!v) v = new Vector3D();
96			m.copyColumnTo(0, v);
97			v.normalize();
98
99			return v;
100		}
101
102		/**
103		 * Returns a boolean value representing whether there is any significant difference between the two given 3d matrices.
104		 */
105		public static function compare(m1:Matrix3D, m2:Matrix3D):Boolean {
106			var r1:Vector.<Number> = Matrix3DUtils.RAW_DATA_CONTAINER;
107			var r2:Vector.<Number> = m2.rawData;
108			m1.copyRawDataTo(r1);
109
110			for (var i:uint = 0; i < 16; ++i) {
111				if (r1[i] != r2[i])
112					return false;
113			}
114
115			return true;
116		}
117
118		public static function lookAt(matrix:Matrix3D, pos:Vector3D, dir:Vector3D, up:Vector3D):void {
119			var dirN:Vector3D;
120			var upN:Vector3D;
121			var lftN:Vector3D;
122			var raw:Vector.<Number> = RAW_DATA_CONTAINER;
123
124			lftN = dir.crossProduct(up);
125			lftN.normalize();
126
127			upN = lftN.crossProduct(dir);
128			upN.normalize();
129			dirN = dir.clone();
130			dirN.normalize();
131
132			raw[0] = lftN.x;
133			raw[1] = upN.x;
134			raw[2] = -dirN.x;
135			raw[3] = 0.0;
136
137			raw[4] = lftN.y;
138			raw[5] = upN.y;
139			raw[6] = -dirN.y;
140			raw[7] = 0.0;
141
142			raw[8] = lftN.z;
143			raw[9] = upN.z;
144			raw[10] = -dirN.z;
145			raw[11] = 0.0;
146
147			raw[12] = -lftN.dotProduct(pos);
148			raw[13] = -upN.dotProduct(pos);
149			raw[14] = dirN.dotProduct(pos);
150			raw[15] = 1.0;
151
152			matrix.copyRawDataFrom(raw);
153		}
154
155		public static function reflection(plane:Plane3D, target:Matrix3D = null):Matrix3D {
156			target ||= new Matrix3D();
157			var a:Number = plane.a, b:Number = plane.b, c:Number = plane.c, d:Number = plane.d;
158			var rawData:Vector.<Number> = Matrix3DUtils.RAW_DATA_CONTAINER;
159			var ab2:Number = -2 * a * b;
160			var ac2:Number = -2 * a * c;
161			var bc2:Number = -2 * b * c;
162			// reflection matrix
163			rawData[0] = 1 - 2 * a * a;
164			rawData[4] = ab2;
165			rawData[8] = ac2;
166			rawData[12] = -2 * a * d;
167			rawData[1] = ab2;
168			rawData[5] = 1 - 2 * b * b;
169			rawData[9] = bc2;
170			rawData[13] = -2 * b * d;
171			rawData[2] = ac2;
172			rawData[6] = bc2;
173			rawData[10] = 1 - 2 * c * c;
174			rawData[14] = -2 * c * d;
175			rawData[3] = 0;
176			rawData[7] = 0;
177			rawData[11] = 0;
178			rawData[15] = 1;
179			target.copyRawDataFrom(rawData);
180
181			return target;
182		}
183
184		public static function decompose(sourceMatrix:Matrix3D, orientationStyle:String = "eulerAngles"):Vector.<Vector3D> {
185			var raw:Vector.<Number> = RAW_DATA_CONTAINER;
186			sourceMatrix.copyRawDataTo(raw);
187
188			var a:Number = raw[0];
189			var e:Number = raw[1];
190			var i:Number = raw[2];
191			var b:Number = raw[4];
192			var f:Number = raw[5];
193			var j:Number = raw[6];
194			var c:Number = raw[8];
195			var g:Number = raw[9];
196			var k:Number = raw[10];
197
198			var x:Number = raw[12];
199			var y:Number = raw[13];
200			var z:Number = raw[14];
201
202			var tx:Number = Math.sqrt(a * a + e * e + i * i);
203			var ty:Number = Math.sqrt(b * b + f * f + j * j);
204			var tz:Number = Math.sqrt(c * c + g * g + k * k);
205			var tw:Number = 0;
206
207			var scaleX:Number = tx;
208			var scaleY:Number = ty;
209			var scaleZ:Number = tz;
210
211			if (a*(f*k - j*g) - e*(b*k - j*c) + i*(b*g - f*c) < 0) {
212				scaleZ = -scaleZ;
213			}
214
215			a = a / scaleX;
216			e = e / scaleX;
217			i = i / scaleX;
218			b = b / scaleY;
219			f = f / scaleY;
220			j = j / scaleY;
221			c = c / scaleZ;
222			g = g / scaleZ;
223			k = k / scaleZ;
224
225			//from away3d-ts
226			if (orientationStyle == Orientation3D.EULER_ANGLES) {
227				tx = Math.atan2(j, k);
228				ty = Math.atan2(-i, Math.sqrt(a * a + e * e));
229				var s1:Number = Math.sin(tx);
230				var c1:Number = Math.cos(tx);
231				tz = Math.atan2(s1*c-c1*b, c1*f - s1*g);
232			} else if (orientationStyle == Orientation3D.AXIS_ANGLE) {
233				tw = Math.acos((a + f + k - 1) / 2);
234				var len:Number = Math.sqrt((j - g) * (j - g) + (c - i) * (c - i) + (e - b) * (e - b));
235				tx = (j - g) / len;
236				ty = (c - i) / len;
237				tz = (e - b) / len;
238			} else {//Orientation3D.QUATERNION
239				var tr:Number = a + f + k;
240				if (tr > 0) {
241					tw = Math.sqrt(1 + tr) / 2;
242					tx = (j - g) / (4 * tw);
243					ty = (c - i) / (4 * tw);
244					tz = (e - b) / (4 * tw);
245				} else if ((a > f) && (a > k)) {
246					tx = Math.sqrt(1 + a - f - k) / 2;
247					tw = (j - g) / (4 * tx);
248					ty = (e + b) / (4 * tx);
249					tz = (c + i) / (4 * tx);
250				} else if (f > k) {
251					ty = Math.sqrt(1 + f - a - k) / 2;
252					tx = (e + b) / (4 * ty);
253					tw = (c - i) / (4 * ty);
254					tz = (j + g) / (4 * ty);
255				} else {
256					tz = Math.sqrt(1 + k - a - f) / 2;
257					tx = (c + i) / (4 * tz);
258					ty = (j + g) / (4 * tz);
259					tw = (e - b) / (4 * tz);
260				}
261			}
262
263			var v:Vector.<Vector3D> = CALCULATION_DECOMPOSE;
264			v[0].x = x;
265			v[0].y = y;
266			v[0].z = z;
267			v[1].x = tx;
268			v[1].y = ty;
269			v[1].z = tz;
270			v[1].w = tw;
271			v[2].x = scaleX;
272			v[2].y = scaleY;
273			v[2].z = scaleZ;
274			return v;
275		}
276
277		public static function transformVector(matrix:Matrix3D, vector:Vector3D, result:Vector3D = null):Vector3D {
278			if (!result) result = new Vector3D();
279			var raw:Vector.<Number> = Matrix3DUtils.RAW_DATA_CONTAINER;
280			matrix.copyRawDataTo(raw);
281			var a:Number = raw[0];
282			var e:Number = raw[1];
283			var i:Number = raw[2];
284			var m:Number = raw[3];
285			var b:Number = raw[4];
286			var f:Number = raw[5];
287			var j:Number = raw[6];
288			var n:Number = raw[7];
289			var c:Number = raw[8];
290			var g:Number = raw[9];
291			var k:Number = raw[10];
292			var o:Number = raw[11];
293			var d:Number = raw[12];
294			var h:Number = raw[13];
295			var l:Number = raw[14];
296			var p:Number = raw[15];
297
298			var x:Number = vector.x;
299			var y:Number = vector.y;
300			var z:Number = vector.z;
301			result.x = a * x + b * y + c * z + d;
302			result.y = e * x + f * y + g * z + h;
303			result.z = i * x + j * y + k * z + l;
304			result.w = m * x + n * y + o * z + p;
305			return result;
306		}
307
308		public static function deltaTransformVector(matrix:Matrix3D, vector:Vector3D, result:Vector3D = null):Vector3D {
309			if (!result) result = new Vector3D();
310			var raw:Vector.<Number> = Matrix3DUtils.RAW_DATA_CONTAINER;
311			matrix.copyRawDataTo(raw);
312			var a:Number = raw[0];
313			var e:Number = raw[1];
314			var i:Number = raw[2];
315			var m:Number = raw[3];
316			var b:Number = raw[4];
317			var f:Number = raw[5];
318			var j:Number = raw[6];
319			var n:Number = raw[7];
320			var c:Number = raw[8];
321			var g:Number = raw[9];
322			var k:Number = raw[10];
323			var o:Number = raw[11];
324			var x:Number = vector.x;
325			var y:Number = vector.y;
326			var z:Number = vector.z;
327			result.x = a * x + b * y + c * z;
328			result.y = e * x + f * y + g * z;
329			result.z = i * x + j * y + k * z;
330			result.w = m * x + n * y + o * z;
331			return result;
332		}
333
334		public static function getTranslation(transform:Matrix3D, result:Vector3D = null):Vector3D {
335			if(!result) result = new Vector3D();
336			transform.copyColumnTo(3, result);
337			return result;
338		}
339
340		public static function deltaTransformVectors(matrix:Matrix3D, vin:Vector.<Number>, vout:Vector.<Number>):void {
341			var raw:Vector.<Number> = Matrix3DUtils.RAW_DATA_CONTAINER;
342			matrix.copyRawDataTo(raw);
343			var a:Number = raw[0];
344			var e:Number = raw[1];
345			var i:Number = raw[2];
346			var m:Number = raw[3];
347			var b:Number = raw[4];
348			var f:Number = raw[5];
349			var j:Number = raw[6];
350			var n:Number = raw[7];
351			var c:Number = raw[8];
352			var g:Number = raw[9];
353			var k:Number = raw[10];
354			var o:Number = raw[11];
355			var outIndex:uint = 0;
356			var length:Number = vin.length;
357			for(var index:uint = 0; index<length; index+=3) {
358				var x:Number = vin[index];
359				var y:Number = vin[index+1];
360				var z:Number = vin[index+2];
361				vout[outIndex++] = a * x + b * y + c * z;
362				vout[outIndex++] = e * x + f * y + g * z;
363				vout[outIndex++] = i * x + j * y + k * z;
364			}
365		}
366	}
367}
```