PageRenderTime 416ms CodeModel.GetById 151ms app.highlight 104ms RepoModel.GetById 158ms app.codeStats 0ms

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