/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

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