topical media & game development

talk show tell print

student-ar-org-papervision3d-core-culling-FrustumCuller.ax

student-ar-org-papervision3d-core-culling-FrustumCuller.ax [swf] [flash] flex


  package org.papervision3d.core.culling
  {
          import org.papervision3d.core.geom.renderables.Vertex3D;
          import org.papervision3d.core.math.AxisAlignedBoundingBox;
          import org.papervision3d.core.math.BoundingSphere;
          import org.papervision3d.core.math.Matrix3D;
          import org.papervision3d.core.math.Number3D;
          import org.papervision3d.objects.DisplayObject3D;
          
          

author: Tim Knip

   
          public class @ax-student-ar-org-papervision3d-core-culling-FrustumCuller implements IObjectCuller
          {
                  public static const INSIDE:int = 1;
                  public static const OUTSIDE:int = -1;
                  public static const INTERSECT:int = 0;
                  
                  

  
                  public var transform        : Matrix3D;
  
                  
Constructor.

   
                  public function @ax-student-ar-org-papervision3d-core-culling-FrustumCuller()
                  {
                          this.transform = Matrix3D.IDENTITY;
                          
                          this.initialize();
                  }
                  
                  
Intializes the frustum. @param fovY Vertical Field Of View in degrees. @param ratio Aspect ratio (ie: viewport.width / viewport.height). @param near Distance to near plane (ie: camera.focus). @param far Distance to far plane.

   
                  public function initialize(fovY:Number=60, ratio:Number=1.333, near:Number=1, far:Number=5000):void
                  {
                          // store the information
                          _fov = fovY;
                          _ratio = ratio;
                          _near = near;
                          _far = far;
  
                          var angle : Number = (Math.PI/180) * _fov * 0.5;
                          
                          // compute width and height of the near and far section
                          _tang = Math.tan(angle);
                          _nh = _near * _tang;
                          _nw = _nh * _ratio;
                          _fh = _far * _tang;
                          _fw = _fh * _ratio;
                  
                          var anglex : Number = Math.atan(_tang * _ratio);
                  
                          // used for bounding-sphere culling
                          _sphereX = 1.0 / Math.cos(anglex);                
                          _sphereY = 1.0 / Math.cos(angle);
                  }
                  
                  
Tests whether an axis aligned boundingbox is inside, outside or intersecting the frustum. When earlyOut is set to true, the method returns INSIDE when a single point of the aabb is inside the frustum (fast). Set earlyOut to false if you want to test for INTERSECT. @param object The object to test. @param aabb AxisAlignedBoundingBox. @param earlyOut Early out. Default is true.
returns: Integer indicating inside(1), outside(-1) or intersecting(0) the frustum.

  
                  public function aabbInFrustum(object:DisplayObject3D, aabb:AxisAlignedBoundingBox, earlyOut:Boolean=true):int
                  {
                          var vertex:Vertex3D;
                          var num:Number3D;
                          var numInside:int = 0;
                          var numOutside:int = 0;
                          var vertices:Array = aabb.getBoxVertices();
                          
                          // Transform the boundingbox to world and test...
                          for each(vertex in vertices)
                          {
                                  num = vertex.toNumber3D();
                                  Matrix3D.multiplyVector(object.world, num);
                                  if(pointInFrustum(num.x, num.y, num.z) == INSIDE)
                                  {
                                          numInside++;
                                          if(earlyOut)
                                                  return INSIDE;        
                                  }
                                  else
                                          numOutside++;
                                  
                                  // aabb has points both inside and outside the frustum, must be intersecting.
                                  if(numInside && numOutside)
                                          return INTERSECT;
                          }
                                  
                          if(numInside)
                                  return (numInside < 8 ? INTERSECT : INSIDE);
                          else
                                  return OUTSIDE;
                  }
                  
                  
Tests whether a point is inside the frustum.
parameter: x
parameter: y
parameter: z @return Integer indicating inside (1) or outside (-1) the frustum.

  
                  public function pointInFrustum(x : Number, y : Number, z : Number) : int
                  {
                          var m        :Matrix3D = this.transform;
                          
                          // compute vector from camera position to p
                          var px        :Number = x - m.n14;
                          var py        :Number = y - m.n24;
                          var pz        :Number = z - m.n34;
                          
                          // compute and test the Z coordinate
                          var pcz : Number = px * m.n13 + py * m.n23 + pz * m.n33;
                          if (pcz > _far || pcz < _near)
                                  return OUTSIDE;
                          
                          // compute and test the Y coordinate
                          var pcy : Number = px * m.n12 + py * m.n22 + pz * m.n32;
                          var aux : Number = pcz * _tang;
                          if(pcy > aux || pcy < -aux)
                                  return OUTSIDE;
          
                          // compute and test the X coordinate
                          var pcx : Number = px * m.n11 + py * m.n21 + pz * m.n31;
                          aux = aux * _ratio;
                          if (pcx > aux || pcx < -aux)
                                  return OUTSIDE;
                          
                          return INSIDE;
                  }
                  
                  
Tests whether a sphere is inside the frustum.
parameter: object The object to test. @param boundingSphere The bounding sphere. @return Integer indicating inside (1), outside (0) or intersecting (-1) the frustum.

  
                  public function sphereInFrustum(obj:DisplayObject3D, boundingSphere:BoundingSphere) : int
                  {
                          var radius:Number = boundingSphere.radius;
                          var d : Number;
                          var ax : Number;
                          var ay : Number;
                          var az : Number;
                          var result : int = INSIDE;
                  
                          var m:Matrix3D = this.transform;
  
                          // compute vector from camera position to p
                          var px : Number = obj.world.n14 - m.n14;
                          var py : Number = obj.world.n24 - m.n24;
                          var pz : Number = obj.world.n34 - m.n34;
                          
                          // near and far
                          az =  px * m.n13 + py * m.n23 + pz * m.n33;
                          if(az > _far + radius || az < _near-radius)
                                  return OUTSIDE;                        
                          if(az > _far - radius || az < _near+radius)
                                  result = INTERSECT;
  
                          // top and bottom
                          ay = px * m.n12 + py * m.n22 + pz * m.n32;
                          d = _sphereY * radius;
                          az *= _tang;
                          if(ay > az+d || ay < -az-d)
                                  return OUTSIDE;
                          if(ay > az-d || ay < -az+d)
                                  result = INTERSECT;
          
                          // left and right
                          ax = px * m.n11 + py * m.n21 + pz * m.n31;
                          az *= _ratio;
                          d = _sphereX * radius;
                          if(ax > az+d || ax < -az-d)
                                  return OUTSIDE;
                          if(ax > az-d || ax < -az+d)
                                  result = INTERSECT;
                                  
                          return result;
                  }
                  
                  
Tests whether an object is inside the frustum. @param obj The object to test @return Integer indicating inside(1), outside(-1) or intersecting(0)

  
                  public function testObject( obj:DisplayObject3D ):int
                  {        
                          var result        : int = INSIDE;
                          
                          if(!obj.geometry || !obj.geometry.vertices || !obj.geometry.vertices.length)
                                  return result;        
                          
                          switch(obj.frustumTestMethod)
                          {
                                  case FrustumTestMethod.BOUNDING_SPHERE:
                                          result = sphereInFrustum(obj, obj.geometry.boundingSphere); 
                                          break;
                                  case FrustumTestMethod.BOUNDING_BOX:
                                          result = aabbInFrustum(obj, obj.geometry.aabb);
                                          break;
                                  case FrustumTestMethod.NO_TESTING:
                                          break;
                                  default:
                                          break;        
                          }
                          
                          return result;
                  }
                  
                  public function set far(value : Number):void
                  {
                          this.initialize(_fov, _ratio, _near, value);
                  }
                  
                  public function get far() : Number
                  {
                          return _far;
                  }
                  
                  public function set fov(value : Number):void
                  {
                          this.initialize(value, _ratio, _near, _far);
                  }
                  
                  public function get fov() : Number
                  {
                          return _fov;
                  }
                  
                  public function set near(value : Number):void
                  {
                          this.initialize(_fov, _ratio, value, _far);
                  }
                  
                  public function get near() : Number
                  {
                          return _near;
                  }
                  
                  public function set ratio(value : Number):void
                  {
                          this.initialize(_fov, value, _near, _far);
                  }
                  
                  public function get ratio() : Number
                  {
                          return _ratio;
                  }
                  
                  private var _fov                : Number;
                  private var _far                : Number;
                  private var _near                : Number;
                  private var _nw                        : Number;
                  private var _nh                        : Number;
                  private var _fw                        : Number;
                  private var _fh                        : Number;
                  private var _tang                : Number;
                  private var _ratio          : Number;
                  private var _sphereX         : Number;
                  private var _sphereY        : Number;
          }
  }


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.