/src/away3d/bounds/BoundingSphere.as

http://github.com/away3d/away3d-core-fp11 · ActionScript · 247 lines · 185 code · 30 blank · 32 comment · 22 complexity · 2cbafbf2334fe18199c0a2474cda3c18 MD5 · raw file

  1. package away3d.bounds
  2. {
  3. import away3d.arcane;
  4. import away3d.core.math.*;
  5. import away3d.primitives.*;
  6. import flash.geom.*;
  7. use namespace arcane;
  8. /**
  9. * BoundingSphere represents a spherical bounding volume defined by a center point and a radius.
  10. * This bounding volume is useful for point lights.
  11. */
  12. public class BoundingSphere extends BoundingVolumeBase
  13. {
  14. private var _radius:Number = 0;
  15. private var _centerX:Number = 0;
  16. private var _centerY:Number = 0;
  17. private var _centerZ:Number = 0;
  18. /**
  19. * The radius of the bounding sphere, calculated from the contents of the entity.
  20. */
  21. public function get radius():Number
  22. {
  23. return _radius;
  24. }
  25. /**
  26. * Creates a new <code>BoundingSphere</code> object
  27. */
  28. public function BoundingSphere()
  29. {
  30. }
  31. /**
  32. * @inheritDoc
  33. */
  34. override public function nullify():void
  35. {
  36. super.nullify();
  37. _centerX = _centerY = _centerZ = 0;
  38. _radius = 0;
  39. }
  40. /**
  41. * todo: pass planes?
  42. * @inheritDoc
  43. */
  44. override public function isInFrustum(planes:Vector.<Plane3D>, numPlanes:int):Boolean
  45. {
  46. for (var i:uint = 0; i < numPlanes; ++i) {
  47. var plane:Plane3D = planes[i];
  48. var flippedExtentX:Number = plane.a < 0? -_radius : _radius;
  49. var flippedExtentY:Number = plane.b < 0? -_radius : _radius;
  50. var flippedExtentZ:Number = plane.c < 0? -_radius : _radius;
  51. var projDist:Number = plane.a*(_centerX + flippedExtentX) + plane.b*(_centerY + flippedExtentY) + plane.c*(_centerZ + flippedExtentZ) - plane.d;
  52. if (projDist < 0)
  53. return false;
  54. }
  55. return true;
  56. }
  57. /**
  58. * @inheritDoc
  59. */
  60. override public function fromSphere(center:Vector3D, radius:Number):void
  61. {
  62. _centerX = center.x;
  63. _centerY = center.y;
  64. _centerZ = center.z;
  65. _radius = radius;
  66. _max.x = _centerX + radius;
  67. _max.y = _centerY + radius;
  68. _max.z = _centerZ + radius;
  69. _min.x = _centerX - radius;
  70. _min.y = _centerY - radius;
  71. _min.z = _centerZ - radius;
  72. _aabbPointsDirty = true;
  73. if (_boundingRenderable)
  74. updateBoundingRenderable();
  75. }
  76. // TODO: fromGeometry can probably be updated a lot
  77. // find center from extremes, but radius from actual furthest distance from center
  78. /**
  79. * @inheritDoc
  80. */
  81. override public function fromExtremes(minX:Number, minY:Number, minZ:Number, maxX:Number, maxY:Number, maxZ:Number):void
  82. {
  83. _centerX = (maxX + minX)*.5;
  84. _centerY = (maxY + minY)*.5;
  85. _centerZ = (maxZ + minZ)*.5;
  86. var d:Number = maxX - minX;
  87. var y:Number = maxY - minY;
  88. var z:Number = maxZ - minZ;
  89. if (y > d)
  90. d = y;
  91. if (z > d)
  92. d = z;
  93. _radius = d*Math.sqrt(.5);
  94. super.fromExtremes(minX, minY, minZ, maxX, maxY, maxZ);
  95. }
  96. /**
  97. * @inheritDoc
  98. */
  99. override public function clone():BoundingVolumeBase
  100. {
  101. var clone:BoundingSphere = new BoundingSphere();
  102. clone.fromSphere(new Vector3D(_centerX, _centerY, _centerZ), _radius);
  103. return clone;
  104. }
  105. override public function rayIntersection(position:Vector3D, direction:Vector3D, targetNormal:Vector3D):Number
  106. {
  107. if (containsPoint(position))
  108. return 0;
  109. var px:Number = position.x - _centerX, py:Number = position.y - _centerY, pz:Number = position.z - _centerZ;
  110. var vx:Number = direction.x, vy:Number = direction.y, vz:Number = direction.z;
  111. var rayEntryDistance:Number;
  112. var a:Number = vx*vx + vy*vy + vz*vz;
  113. var b:Number = 2*( px*vx + py*vy + pz*vz );
  114. var c:Number = px*px + py*py + pz*pz - _radius*_radius;
  115. var det:Number = b*b - 4*a*c;
  116. if (det >= 0) { // ray goes through sphere
  117. var sqrtDet:Number = Math.sqrt(det);
  118. rayEntryDistance = ( -b - sqrtDet )/( 2*a );
  119. if (rayEntryDistance >= 0) {
  120. targetNormal.x = px + rayEntryDistance*vx;
  121. targetNormal.y = py + rayEntryDistance*vy;
  122. targetNormal.z = pz + rayEntryDistance*vz;
  123. targetNormal.normalize();
  124. return rayEntryDistance;
  125. }
  126. }
  127. // ray misses sphere
  128. return -1;
  129. }
  130. /**
  131. * @inheritDoc
  132. */
  133. override public function containsPoint(position:Vector3D):Boolean
  134. {
  135. var px:Number = position.x - _centerX, py:Number = position.y - _centerY, pz:Number = position.z - _centerZ;
  136. var distance:Number = Math.sqrt(px*px + py*py + pz*pz);
  137. return distance <= _radius;
  138. }
  139. override protected function updateBoundingRenderable():void
  140. {
  141. var sc:Number = _radius;
  142. if (sc == 0)
  143. sc = 0.001;
  144. _boundingRenderable.scaleX = sc;
  145. _boundingRenderable.scaleY = sc;
  146. _boundingRenderable.scaleZ = sc;
  147. _boundingRenderable.x = _centerX;
  148. _boundingRenderable.y = _centerY;
  149. _boundingRenderable.z = _centerZ;
  150. }
  151. override protected function createBoundingRenderable():WireframePrimitiveBase
  152. {
  153. return new WireframeSphere(1, 16, 12, 0xffffff, 0.5);
  154. }
  155. override public function classifyToPlane(plane:Plane3D):int
  156. {
  157. var a:Number = plane.a;
  158. var b:Number = plane.b;
  159. var c:Number = plane.c;
  160. var dd:Number = a*_centerX + b*_centerY + c*_centerZ - plane.d;
  161. if (a < 0)
  162. a = -a;
  163. if (b < 0)
  164. b = -b;
  165. if (c < 0)
  166. c = -c;
  167. var rr:Number = (a + b + c)*_radius;
  168. return dd > rr? PlaneClassification.FRONT :
  169. dd < -rr? PlaneClassification.BACK :
  170. PlaneClassification.INTERSECT;
  171. }
  172. override public function transformFrom(bounds:BoundingVolumeBase, matrix:Matrix3D):void
  173. {
  174. var sphere:BoundingSphere = BoundingSphere(bounds);
  175. var cx:Number = sphere._centerX;
  176. var cy:Number = sphere._centerY;
  177. var cz:Number = sphere._centerZ;
  178. var raw:Vector.<Number> = Matrix3DUtils.RAW_DATA_CONTAINER;
  179. matrix.copyRawDataTo(raw);
  180. var m11:Number = raw[0], m12:Number = raw[4], m13:Number = raw[8], m14:Number = raw[12];
  181. var m21:Number = raw[1], m22:Number = raw[5], m23:Number = raw[9], m24:Number = raw[13];
  182. var m31:Number = raw[2], m32:Number = raw[6], m33:Number = raw[10], m34:Number = raw[14];
  183. _centerX = cx*m11 + cy*m12 + cz*m13 + m14;
  184. _centerY = cx*m21 + cy*m22 + cz*m23 + m24;
  185. _centerZ = cx*m31 + cy*m32 + cz*m33 + m34;
  186. if (m11 < 0)
  187. m11 = -m11;
  188. if (m12 < 0)
  189. m12 = -m12;
  190. if (m13 < 0)
  191. m13 = -m13;
  192. if (m21 < 0)
  193. m21 = -m21;
  194. if (m22 < 0)
  195. m22 = -m22;
  196. if (m23 < 0)
  197. m23 = -m23;
  198. if (m31 < 0)
  199. m31 = -m31;
  200. if (m32 < 0)
  201. m32 = -m32;
  202. if (m33 < 0)
  203. m33 = -m33;
  204. var r:Number = sphere._radius;
  205. var rx:Number = m11 + m12 + m13;
  206. var ry:Number = m21 + m22 + m23;
  207. var rz:Number = m31 + m32 + m33;
  208. _radius = r*Math.sqrt(rx*rx + ry*ry + rz*rz);
  209. _min.x = _centerX - _radius;
  210. _min.y = _centerY - _radius;
  211. _min.z = _centerZ - _radius;
  212. _max.x = _centerX + _radius;
  213. _max.y = _centerY + _radius;
  214. _max.z = _centerZ + _radius;
  215. }
  216. }
  217. }