PageRenderTime 77ms CodeModel.GetById 32ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 0ms

/src/away3d/tools/utils/Projector.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 404 lines | 329 code | 66 blank | 9 comment | 51 complexity | 5d77f4479e0c2b6850dad9af6f4dc678 MD5 | raw file
  1package away3d.tools.utils
  2{
  3	import away3d.containers.*;
  4	import away3d.core.base.*;
  5	import away3d.core.base.data.*;
  6	import away3d.entities.*;
  7	
  8	import flash.geom.*;
  9	
 10	public class Projector
 11	{
 12		public static const FRONT:String = "front";
 13		public static const BACK:String = "back";
 14		public static const TOP:String = "top";
 15		public static const BOTTOM:String = "bottom";
 16		public static const LEFT:String = "left";
 17		public static const RIGHT:String = "right";
 18		public static const CYLINDRICAL_X:String = "cylindricalx";
 19		public static const CYLINDRICAL_Y:String = "cylindricaly";
 20		public static const CYLINDRICAL_Z:String = "cylindricalz";
 21		public static const SPHERICAL:String = "spherical";
 22		
 23		private static var _width:Number;
 24		private static var _height:Number;
 25		private static var _depth:Number;
 26		private static var _offsetW:Number;
 27		private static var _offsetH:Number;
 28		private static var _offsetD:Number;
 29		private static var _orientation:String;
 30		private static var _center:Vector3D;
 31		private static var _vn:Vector3D;
 32		private static var _ve:Vector3D;
 33		private static var _vp:Vector3D;
 34		private static var _dir:Vector3D;
 35		private static var _radius:Number;
 36		private static var _uv:UV;
 37		
 38		private static const PI:Number = Math.PI;
 39		private static const DOUBLEPI:Number = Math.PI * 2;
 40		
 41		/**
 42		 * Class remaps the uv data of a mesh
 43		 *
 44		 * @param     orientation    String. Defines the projection direction and methods.
 45		 * Note: As we use triangles, cylindrical and spherical projections might require correction,
 46		 * as some faces, may have vertices pointing at other side of the map, causing some faces to be rendered as a whole reverted map.
 47		 *
 48		 * @param     obj        ObjectContainer3D. The ObjectContainer3D to remap.
 49		 */
 50		public static function project(orientation:String, obj:ObjectContainer3D):void
 51		{
 52			_orientation = orientation.toLowerCase();
 53			parse(obj);
 54		}
 55		
 56		private static function parse(obj:ObjectContainer3D):void
 57		{
 58			var child:ObjectContainer3D;
 59			if (obj is Mesh && obj.numChildren == 0)
 60				remapMesh(Mesh(obj));
 61			
 62			for (var i:uint = 0; i < obj.numChildren; ++i) {
 63				child = obj.getChildAt(i);
 64				parse(child);
 65			}
 66		}
 67		
 68		private static function remapMesh(mesh:Mesh):void
 69		{
 70			var minX:Number = Infinity;
 71			var minY:Number = Infinity;
 72			var minZ:Number = Infinity;
 73			var maxX:Number = -Infinity;
 74			var maxY:Number = -Infinity;
 75			var maxZ:Number = -Infinity;
 76			
 77			Bounds.getMeshBounds(mesh);
 78			minX = Bounds.minX;
 79			minY = Bounds.minY;
 80			minZ = Bounds.minZ;
 81			maxX = Bounds.maxX;
 82			maxY = Bounds.maxY;
 83			maxZ = Bounds.maxZ;
 84			
 85			if (_orientation == FRONT || _orientation == BACK || _orientation == CYLINDRICAL_X) {
 86				_width = maxX - minX;
 87				_height = maxY - minY;
 88				_depth = maxZ - minZ;
 89				_offsetW = (minX > 0)? -minX : Math.abs(minX);
 90				_offsetH = (minY > 0)? -minY : Math.abs(minY);
 91				_offsetD = (minZ > 0)? -minZ : Math.abs(minZ);
 92				
 93			} else if (_orientation == LEFT || _orientation == RIGHT || _orientation == CYLINDRICAL_Z) {
 94				_width = maxZ - minZ;
 95				_height = maxY - minY;
 96				_depth = maxX - minX;
 97				_offsetW = (minZ > 0)? -minZ : Math.abs(minZ);
 98				_offsetH = (minY > 0)? -minY : Math.abs(minY);
 99				_offsetD = (minX > 0)? -minX : Math.abs(minX);
100				
101			} else if (_orientation == TOP || _orientation == BOTTOM || _orientation == CYLINDRICAL_Y) {
102				_width = maxX - minX;
103				_height = maxZ - minZ;
104				_depth = maxY - minY;
105				_offsetW = (minX > 0)? -minX : Math.abs(minX);
106				_offsetH = (minZ > 0)? -minZ : Math.abs(minZ);
107				_offsetD = (minY > 0)? -minY : Math.abs(minY);
108			}
109			
110			var geometry:Geometry = mesh.geometry;
111			var geometries:Vector.<ISubGeometry> = geometry.subGeometries;
112			
113			if (_orientation == SPHERICAL) {
114				if (!_center)
115					_center = new Vector3D();
116				_width = maxX - minX;
117				_height = maxZ - minZ;
118				_depth = maxY - minY;
119				_radius = Math.max(_width, _depth, _height) + 10;
120				_center.x = _center.y = _center.z = .0001;
121				
122				remapSpherical(geometries, mesh.scenePosition);
123				
124			} else if (_orientation.indexOf("cylindrical") != -1)
125				remapCylindrical(geometries, mesh.scenePosition);
126			
127			else
128				remapLinear(geometries, mesh.scenePosition);
129		}
130		
131		private static function remapLinear(geometries:Vector.<ISubGeometry>, position:Vector3D):void
132		{
133			var numSubGeoms:uint = geometries.length;
134			var sub_geom:ISubGeometry;
135			var vertices:Vector.<Number>;
136			var vertexOffset:int;
137			var vertexStride:int;
138			var indices:Vector.<uint>;
139			var uvs:Vector.<Number>;
140			var uvOffset:int;
141			var uvStride:int;
142			var i:uint;
143			var j:uint;
144			var vIndex:uint;
145			var uvIndex:uint;
146			var numIndices:uint;
147			var offsetU:Number;
148			var offsetV:Number;
149			
150			for (i = 0; i < numSubGeoms; ++i) {
151				sub_geom = geometries[i];
152				
153				vertices = sub_geom.vertexData
154				vertexOffset = sub_geom.vertexOffset;
155				vertexStride = sub_geom.vertexStride;
156				
157				uvs = sub_geom.UVData;
158				uvOffset = sub_geom.UVOffset;
159				uvStride = sub_geom.UVStride;
160				
161				indices = sub_geom.indexData;
162				
163				numIndices = indices.length;
164				
165				switch (_orientation) {
166					case FRONT:
167						offsetU = _offsetW + position.x;
168						offsetV = _offsetH + position.y;
169						for (j = 0; j < numIndices; ++j) {
170							vIndex = vertexOffset + vertexStride*indices[j];
171							uvIndex = uvOffset + uvStride*indices[j];
172							uvs[uvIndex] = (vertices[vIndex] + offsetU)/_width;
173							uvs[uvIndex + 1] = 1 - (vertices[vIndex + 1] + offsetV)/_height;
174						}
175						break;
176					
177					case BACK:
178						offsetU = _offsetW + position.x;
179						offsetV = _offsetH + position.y;
180						for (j = 0; j < numIndices; ++j) {
181							vIndex = vertexOffset + vertexStride*indices[j];
182							uvIndex = uvOffset + uvStride*indices[j];
183							uvs[uvIndex] = 1 - (vertices[vIndex] + offsetU)/_width;
184							uvs[uvIndex + 1] = 1 - (vertices[vIndex + 1] + offsetV)/_height;
185						}
186						break;
187					
188					case RIGHT:
189						offsetU = _offsetW + position.z;
190						offsetV = _offsetH + position.y;
191						for (j = 0; j < numIndices; ++j) {
192							vIndex = vertexOffset + vertexStride*indices[j] + 1;
193							uvIndex = uvOffset + uvStride*indices[j];
194							uvs[uvIndex] = (vertices[vIndex + 1] + offsetU)/_width;
195							uvs[uvIndex + 1] = 1 - (vertices[vIndex] + offsetV)/_height;
196						}
197						break;
198					
199					case LEFT:
200						offsetU = _offsetW + position.z;
201						offsetV = _offsetH + position.y;
202						for (j = 0; j < numIndices; ++j) {
203							vIndex = vertexOffset + vertexStride*indices[j] + 1;
204							uvIndex = uvOffset + uvStride*indices[j];
205							uvs[uvIndex] = 1 - (vertices[vIndex + 1] + offsetU)/_width;
206							uvs[uvIndex + 1] = 1 - (vertices[vIndex] + offsetV)/_height;
207						}
208						break;
209					
210					case TOP:
211						offsetU = _offsetW + position.x;
212						offsetV = _offsetH + position.z;
213						for (j = 0; j < numIndices; ++j) {
214							vIndex = vertexOffset + vertexStride*indices[j];
215							uvIndex = uvOffset + uvStride*indices[j];
216							uvs[uvIndex] = (vertices[vIndex] + offsetU)/_width;
217							uvs[uvIndex + 1] = 1 - (vertices[vIndex + 2] + offsetV)/_height;
218						}
219						break;
220					
221					case BOTTOM:
222						offsetU = _offsetW + position.x;
223						offsetV = _offsetH + position.z;
224						for (j = 0; j < numIndices; ++j) {
225							vIndex = vertexOffset + vertexStride*indices[j];
226							uvIndex = uvOffset + uvStride*indices[j];
227							uvs[uvIndex] = 1 - (vertices[vIndex] + offsetU)/_width;
228							uvs[uvIndex + 1] = 1 - (vertices[vIndex + 2] + offsetV)/_height;
229						}
230				}
231				
232				if (sub_geom is CompactSubGeometry)
233					CompactSubGeometry(sub_geom).updateData(uvs);
234				else
235					SubGeometry(sub_geom).updateUVData(uvs);
236			}
237		}
238		
239		private static function remapCylindrical(geometries:Vector.<ISubGeometry>, position:Vector3D):void
240		{
241			var numSubGeoms:uint = geometries.length;
242			var sub_geom:ISubGeometry;
243			var vertices:Vector.<Number>;
244			var vertexOffset:int;
245			var vertexStride:int;
246			var indices:Vector.<uint>;
247			var uvs:Vector.<Number>;
248			var uvOffset:int;
249			var uvStride:int;
250			var i:uint;
251			var j:uint;
252			var vIndex:uint;
253			var uvIndex:uint;
254			var numIndices:uint;
255			var offset:Number;
256			
257			for (i = 0; i < numSubGeoms; ++i) {
258				sub_geom = geometries[i];
259				
260				vertices = sub_geom.vertexData
261				vertexOffset = sub_geom.vertexOffset;
262				vertexStride = sub_geom.vertexStride;
263				
264				uvs = sub_geom.UVData;
265				uvOffset = sub_geom.UVOffset;
266				uvStride = sub_geom.UVStride;
267				
268				indices = sub_geom.indexData;
269				
270				numIndices = indices.length;
271				
272				switch (_orientation) {
273					
274					case CYLINDRICAL_X:
275						
276						offset = _offsetW + position.x;
277						for (j = 0; j < numIndices; ++j) {
278							vIndex = vertexOffset + vertexStride*indices[j];
279							uvIndex = uvOffset + uvStride*indices[j];
280							uvs[uvIndex] = (vertices[vIndex] + offset)/_width;
281							uvs[uvIndex + 1] = (PI + Math.atan2(vertices[vIndex + 1], vertices[vIndex + 2]))/DOUBLEPI;
282						}
283						break;
284					
285					case CYLINDRICAL_Y:
286						offset = _offsetD + position.y;
287						for (j = 0; j < numIndices; ++j) {
288							vIndex = vertexOffset + vertexStride*indices[j];
289							uvIndex = uvOffset + uvStride*indices[j];
290							uvs[uvIndex] = (PI + Math.atan2(vertices[vIndex], vertices[vIndex + 2]))/DOUBLEPI;
291							uvs[uvIndex + 1] = 1 - (vertices[vIndex + 1] + offset)/_depth;
292						}
293						break;
294					
295					case CYLINDRICAL_Z:
296						offset = _offsetW + position.z;
297						for (j = 0; j < numIndices; ++j) {
298							vIndex = vertexOffset + vertexStride*indices[j];
299							uvIndex = uvOffset + uvStride*indices[j];
300							uvs[uvIndex + 1] = (vertices[vIndex + 2] + offset)/_width;
301							uvs[uvIndex] = (PI + Math.atan2(vertices[vIndex + 1], vertices[vIndex]))/DOUBLEPI;
302						}
303					
304				}
305				
306				if (sub_geom is CompactSubGeometry)
307					CompactSubGeometry(sub_geom).updateData(uvs);
308				else
309					SubGeometry(sub_geom).updateUVData(uvs);
310				
311			}
312		}
313		
314		private static function remapSpherical(geometries:Vector.<ISubGeometry>, position:Vector3D):void
315		{
316			position = position;
317			var numSubGeoms:uint = geometries.length;
318			var sub_geom:ISubGeometry;
319			
320			var vertices:Vector.<Number>;
321			var vertexOffset:int;
322			var vertexStride:int;
323			var indices:Vector.<uint>;
324			var uvs:Vector.<Number>;
325			var uvOffset:int;
326			var uvStride:int;
327			
328			var i:uint;
329			var j:uint;
330			var vIndex:uint;
331			var uvIndex:uint;
332			var numIndices:uint;
333			
334			for (i = 0; i < numSubGeoms; ++i) {
335				sub_geom = geometries[i];
336				
337				vertices = sub_geom.vertexData
338				vertexOffset = sub_geom.vertexOffset;
339				vertexStride = sub_geom.vertexStride;
340				
341				uvs = sub_geom.UVData;
342				uvOffset = sub_geom.UVOffset;
343				uvStride = sub_geom.UVStride;
344				
345				indices = sub_geom.indexData;
346				
347				numIndices = indices.length;
348				
349				numIndices = indices.length;
350				
351				for (j = 0; j < numIndices; ++j) {
352					vIndex = vertexOffset + vertexStride*indices[j];
353					uvIndex = uvOffset + uvStride*indices[j];
354					
355					projectVertex(vertices[vIndex], vertices[vIndex + 1], vertices[vIndex + 2]);
356					uvs[uvIndex] = _uv.u;
357					uvs[uvIndex + 1] = _uv.v;
358				}
359				
360				if (sub_geom is CompactSubGeometry)
361					CompactSubGeometry(sub_geom).updateData(uvs);
362				else
363					SubGeometry(sub_geom).updateUVData(uvs);
364			}
365		}
366		
367		private static function projectVertex(x:Number, y:Number, z:Number):void
368		{
369			if (!_dir) {
370				_dir = new Vector3D(x, y, z);
371				_uv = new UV();
372				_vn = new Vector3D(0, -1, 0);
373				_ve = new Vector3D(.1, 0, .9);
374				_vp = new Vector3D();
375			} else {
376				_dir.x = x;
377				_dir.y = y;
378				_dir.z = z;
379			}
380			
381			_dir.normalize();
382			
383			_vp.x = _dir.x*_radius;
384			_vp.y = _dir.y*_radius;
385			_vp.z = _dir.z*_radius;
386			_vp.normalize();
387			
388			var phi:Number = Math.acos(-_vn.dotProduct(_vp));
389			
390			_uv.v = phi/PI;
391			
392			var theta:Number = Math.acos(_vp.dotProduct(_ve)/Math.sin(phi))/DOUBLEPI;
393			
394			var _crp:Vector3D = _vn.crossProduct(_ve);
395			
396			if (_crp.dotProduct(_vp) < 0)
397				_uv.u = 1 - theta;
398			else
399				_uv.u = theta;
400		
401		}
402	
403	}
404}