topical media & game development

talk show tell print

student-ar-org-papervision3d-cameras-Camera3D.ax

student-ar-org-papervision3d-cameras-Camera3D.ax [swf] flex


  package org.papervision3d.cameras
  {
          import flash.geom.Rectangle;
          import flash.utils.Dictionary;
          import flash.utils.getTimer;
          
          import org.papervision3d.core.culling.FrustumCuller;
          import org.papervision3d.core.geom.renderables.Triangle3D;
          import org.papervision3d.core.geom.renderables.Vertex3D;
          import org.papervision3d.core.geom.renderables.Vertex3DInstance;
          import org.papervision3d.core.math.Matrix3D;
          import org.papervision3d.core.proto.CameraObject3D;
          import org.papervision3d.core.render.data.RenderSessionData;
          import org.papervision3d.objects.DisplayObject3D;
          
          
@ax-student-ar-org-papervision3d-cameras-Camera3D is the basic camera used by Papervision3D. </p>
author: Tim Knip

   
          public class @ax-student-ar-org-papervision3d-cameras-Camera3D extends CameraObject3D
          {        
                  
Constructor. @param fov This value is the vertical Field Of View (FOV) in degrees. @param near Distance to the near clipping plane. @param far Distance to the far clipping plane. @param useCulling Boolean indicating whether to use frustum culling. When true all objects outside the view will be culled. @param useProjection Boolean indicating whether to use a projection matrix for perspective.

   
                  public function @ax-student-ar-org-papervision3d-cameras-Camera3D(fov:Number=60, near:Number=10, far:Number=5000, useCulling:Boolean=false, useProjection:Boolean=false)
                  {
                          super(near, 40);
                          
                          this.fov = fov; 
                          
                          _prevFocus = 0;
                          _prevZoom = 0;
                          _prevOrtho = false;
                          _prevUseProjection = false;
                          _useCulling = useCulling;
                          _useProjectionMatrix = useProjection;
                          _far = far;
                          _focusFix = Matrix3D.IDENTITY;
                  }
                  
                  
Orbits the camera around the specified target. If no target is specified the camera's #target property is used. If this camera's #target property equals null the camera orbits the origin (0, 0, 0). @param pitch Rotation around X=axis (looking up or down). @param yaw Rotation around Y-axis (looking left or right). @param useDegrees Whether to use degrees for pitch and yaw (defaults to 'true'). @param target An optional target to orbit around.

   
                  public override function orbit(pitch:Number, yaw:Number, useDegrees:Boolean=true, target:DisplayObject3D=null):void
                  {
                          target = target || _target;
                          target = target || DisplayObject3D.ZERO;
  
                          if(useDegrees)
                          {
                                  pitch *= (Math.PI/180);
                                  yaw *= (Math.PI/180);
                          }
                          
                          // Number3D.sub
                          var dx                         :Number = target.world.n14 - this.x;
                          var dy                         :Number = target.world.n24 - this.y;
                          var dz                         :Number = target.world.n34 - this.z;
                          
                          // Number3D.modulo
                          var distance         :Number = Math.sqrt(dx*dx+dy*dy+dz*dz);
  
                          // Rotations
                          var rx :Number = Math.cos(yaw) * Math.sin(pitch);
                          var rz :Number = Math.sin(yaw) * Math.sin(pitch);
                          var ry :Number = Math.cos(pitch);
                          
                          // Move to specified location
                          this.x = target.world.n14 + (rx * distance);
                          this.y = target.world.n24 + (ry * distance);
                          this.z = target.world.n34 + (rz * distance);
                          
                          this.lookAt(target);
                  }
                  
                  public override function projectFaces(faces:Array, object:DisplayObject3D, renderSessionData:RenderSessionData):Number{
                                  
                  /* 	 
                          //alternative way - less code but slower
                          
                          var vertices:Array = [];
                          var uniques:Dictionary = new Dictionary(true);
                          
                          for each(var f:Triangle3D in faces){
                                  for each(var v:Vertex3D in f.vertices){
                                          if(!uniques[v]){
                                                  vertices.push(v);
                                                  uniques[v] = true;
                                          }
                                  } 
                                  //vertices.push(f.v0, f.v1, f.v2);
                          }        
                          
                          return projectVertices(vertices, object, renderSessionData);  */
                          
                          var view                :Matrix3D = object.view,
                                  m11                 :Number = view.n11,
                                  m12                 :Number = view.n12,
                                  m13                 :Number = view.n13,
                                  m21                 :Number = view.n21,
                                  m22                 :Number = view.n22,
                                  m23                 :Number = view.n23,
                                  m31                 :Number = view.n31,
                                  m32                 :Number = view.n32,
                                  m33                 :Number = view.n33,
                                  m41                 :Number = view.n41,
                                  m42                 :Number = view.n42,
                                  m43                 :Number = view.n43,
                                  vx                        :Number,
                                  vy                        :Number,
                                  vz                        :Number,
                                  s_x                        :Number,
                                  s_y                        :Number,
                                  s_z                        :Number,
                                  s_w                        :Number,
                                  vertex                :Vertex3D, 
                                  screen                :Vertex3DInstance,
                                  persp                 :Number,
                                  i                :int    = 0,
                                  focus            :Number = renderSessionData.camera.focus,
                                  fz               :Number = focus * renderSessionData.camera.zoom,
                                  vpw                        :Number = viewport.width / 2,
                                  vph                        :Number = viewport.height / 2,
                                  far                        :Number = renderSessionData.camera.far,
                                  fdist                :Number = far - focus,
                                  vertices        :Array;
                                  
                          var time:Number = getTimer();
                          
                          for each(var f:Triangle3D in faces){
                                  
                                  vertices = f.vertices;
                                  i = vertices.length; 
                                  
                                  while( vertex = vertices[--i] )
                                  {
                                          if(vertex.timestamp == time)
                                                  continue;
                                          
                                          vertex.timestamp = time;
                                          // Center position
                                          vx = vertex.x;
                                          vy = vertex.y;
                                          vz = vertex.z;
                                          
                                          s_z = vx * m31 + vy * m32 + vz * m33 + view.n34;
                                          
                                          screen = vertex.vertex3DInstance;
                                          
                                          if(_useProjectionMatrix)
                                          {
                                                  s_w = vx * m41 + vy * m42 + vz * m43 + view.n44;
                                                  // to normalized clip space (0.0 to 1.0)
                                                  // NOTE: can skip and simply test (s_z < 0) and save a div
                                                  s_z /= s_w;
                                                  
                                                  // is point between near- and far-plane?
                                                  if( screen.visible = (s_z > 0 && s_z < 1) )
                                                  {
                                                          // to normalized clip space (-1,-1) to (1, 1)
                                                          s_x = (vx * m11 + vy * m12 + vz * m13 + view.n14) / s_w;
                                                          s_y = (vx * m21 + vy * m22 + vz * m23 + view.n24) / s_w;
          
                                                          // project to viewport.
                                                          screen.x = s_x * vpw;
                                                          screen.y = s_y * vph;
                                                          
                                                          // NOTE: z not linear, value increases when nearing far-plane.
                                                          screen.z = s_z * s_w;
                                                  }
                                          }
                                          else
                                          {
                                                  if(screen.visible = ( focus + s_z > 0 ))
                                                  {
                                                          s_x = vx * m11 + vy * m12 + vz * m13 + view.n14;
                                                          s_y = vx * m21 + vy * m22 + vz * m23 + view.n24;
                                                          
                                                          persp = fz / (focus + s_z);
                                                          screen.x = s_x * persp;
                                                          screen.y = s_y * persp;
                                                          screen.z = s_z;
                                                  }
                                          }
                                  }
  
                          }
                          
                          return 0;
                          
                          
                  }
                  
                  
                  
                  
Projects vertices. @param object The <code>DisplayObject3D</code> to be projected @param renderSessionData The <code>RenderSessionData</code> holding the containing the camera properties

   
                  public override function projectVertices(vertices:Array, object:DisplayObject3D, renderSessionData:RenderSessionData):Number
                  {
                                  
                          var view                :Matrix3D = object.view,
                                  m11                 :Number = view.n11,
                                  m12                 :Number = view.n12,
                                  m13                 :Number = view.n13,
                                  m21                 :Number = view.n21,
                                  m22                 :Number = view.n22,
                                  m23                 :Number = view.n23,
                                  m31                 :Number = view.n31,
                                  m32                 :Number = view.n32,
                                  m33                 :Number = view.n33,
                                  m41                 :Number = view.n41,
                                  m42                 :Number = view.n42,
                                  m43                 :Number = view.n43,
                                  vx                        :Number,
                                  vy                        :Number,
                                  vz                        :Number,
                                  s_x                        :Number,
                                  s_y                        :Number,
                                  s_z                        :Number,
                                  s_w                        :Number,
                                  vertex                :Vertex3D, 
                                  screen                :Vertex3DInstance,
                                  persp                 :Number,
                                  i                :int    = vertices.length,
                                  focus            :Number = renderSessionData.camera.focus,
                                  fz               :Number = focus * renderSessionData.camera.zoom,
                                  vpw                        :Number = viewport.width / 2,
                                  vph                        :Number = viewport.height / 2,
                                  far                        :Number = renderSessionData.camera.far,
                                  fdist                :Number = far - focus;
                          
                          while( vertex = vertices[--i] )
                          {
                                  // Center position
                                  vx = vertex.x;
                                  vy = vertex.y;
                                  vz = vertex.z;
                                  
                                  s_z = vx * m31 + vy * m32 + vz * m33 + view.n34;
                                  
                                  screen = vertex.vertex3DInstance;
                                  
                                  if(_useProjectionMatrix)
                                  {
                                          s_w = vx * m41 + vy * m42 + vz * m43 + view.n44;
                                          // to normalized clip space (0.0 to 1.0)
                                          // NOTE: can skip and simply test (s_z < 0) and save a div
                                          s_z /= s_w;
                                          
                                          // is point between near- and far-plane?
                                          if( screen.visible = (s_z > 0 && s_z < 1) )
                                          {
                                                  // to normalized clip space (-1,-1) to (1, 1)
                                                  s_x = (vx * m11 + vy * m12 + vz * m13 + view.n14) / s_w;
                                                  s_y = (vx * m21 + vy * m22 + vz * m23 + view.n24) / s_w;
  
                                                  // project to viewport.
                                                  screen.x = s_x * vpw;
                                                  screen.y = s_y * vph;
                                                  
                                                  // NOTE: z not linear, value increases when nearing far-plane.
                                                  screen.z = s_z * s_w;
                                          }
                                  }
                                  else
                                  {
                                          if(screen.visible = ( focus + s_z > 0 ))
                                          {
                                                  s_x = vx * m11 + vy * m12 + vz * m13 + view.n14;
                                                  s_y = vx * m21 + vy * m22 + vz * m23 + view.n24;
                                                  
                                                  persp = fz / (focus + s_z);
                                                  screen.x = s_x * persp;
                                                  screen.y = s_y * persp;
                                                  screen.z = s_z;
                                          }
                                  }
                          }
  
                          return 0;
                  }
                  
                  
Updates the internal camera settings. @param viewport

   
                  public function update(viewport:Rectangle):void
                  {
                          if(!viewport)
                                  throw new Error("@ax-student-ar-org-papervision3d-cameras-Camera3D#update: Invalid viewport rectangle! " + viewport);
          
                          this.viewport = viewport;
  
                          // used to detect value changes
                          _prevFocus = this.focus;
                          _prevZoom = this.zoom;
                          _prevWidth = this.viewport.width;
                          _prevHeight = this.viewport.height;
  
                          if(_prevOrtho != this.ortho)
                          {
                                  if(this.ortho)
                                  {
                                          _prevOrthoProjection = this.useProjectionMatrix;
                                          this.useProjectionMatrix = true;        
                                  }
                                  else
                                          this.useProjectionMatrix = _prevOrthoProjection;
                          }
                          else if(_prevUseProjection != _useProjectionMatrix)
                          {
                                  this.useProjectionMatrix = this._useProjectionMatrix;
                          }        
                          
                          _prevOrtho = this.ortho;
                          _prevUseProjection = _useProjectionMatrix;
                          
                          this.useCulling = _useCulling;
                  }
                  
                  
[INTERNAL-USE] Transforms world coordinates into camera space. @param transform An optional transform.

   
                  public override function transformView(transform:Matrix3D=null):void
                  {        
                          // check whether camera internals need updating
                          if(        ortho != _prevOrtho || _prevUseProjection != _useProjectionMatrix || 
                                  focus != _prevFocus || zoom != _prevZoom || viewport.width != _prevWidth || viewport.height != _prevHeight)
                          {
                                  update(viewport);
                          }
                          
                          // handle camera 'types'
                          if(_target)
                          {
                                  // Target camera...
                                  lookAt(_target);
                          }
                          else if(_transformDirty)
                          {
                                  // Free camera...
                                  updateTransform();
                          }
                          
                          if(_useProjectionMatrix)
                          {
                                  super.transformView();
                                  this.eye.calculateMultiply4x4(_projection, this.eye);
                          }
                          else
                          {
                                  _focusFix.copy(this.transform);
                                  _focusFix.n14 += focus * this.transform.n13;
                                  _focusFix.n24 += focus * this.transform.n23;
                                  _focusFix.n34 += focus * this.transform.n33;
                                  super.transformView(_focusFix);
                          }
                          
                          // handle frustum if available
                          if(culler is FrustumCuller)
                          {
                                  // The frustum culler simply uses the camera transform
                                  FrustumCuller(culler).transform.copy(this.transform);
                          }
                  }
                  
                  
Whether this camera uses frustum culling.
returns: Boolean

   
                  public override function set useCulling(value:Boolean):void
                  {
                          super.useCulling = value;
                          
                          if(_useCulling)
                          {
                                  if(!this.culler)
                                          this.culler = new FrustumCuller();
                                          
                                  FrustumCuller(this.culler).initialize(this.fov, this.viewport.width/this.viewport.height, this.focus/this.zoom, _far);
                          }
                          else
                                  this.culler = null;        
                  }
                  
                  
Whether this camera uses a projection matrix.

  
                  public override function set useProjectionMatrix(value:Boolean):void
                  {        
                          if(value)
                          {
                                  if(this.ortho)
                                  {
                                          var w:Number = viewport.width / 2;
                                          var h:Number = viewport.height / 2;        
                                          _projection = createOrthoMatrix(-w, w, -h, h, -_far, _far);        
                                          _projection = Matrix3D.multiply(_orthoScaleMatrix, _projection);
                                  }
                                  else
                                          _projection = createPerspectiveMatrix(fov, viewport.width/viewport.height, this.focus, this.far);
                          }
                          else
                          {
                                  if(this.ortho)
                                          value = true;
                          }
                          super.useProjectionMatrix = value;
                  }
                  
                  
Sets the distance to the far plane. @param value The distance to the far plane

   
                  public override function set far(value:Number):void
                  {
                          if(value > this.focus)
                          {
                                  _far = value;
                                  this.update(this.viewport);
                          }
                  }
                  
                  
Sets the distance to the near plane (note that this is simply an alias for #focus). @param value The distance to the near plane

    
                  public override function set near(value:Number):void
                  {
                          if(value > 0)
                          {
                                  this.focus = value;
                                  this.update(this.viewport);
                          }
                  }
                  
                  
Sets the orthographic scale of the camera
parameter: value The value of the orthographic scale

  
  
                  public override function set orthoScale(value:Number):void
                  {
                          super.orthoScale = value;
                          this.useProjectionMatrix = this.useProjectionMatrix;
                          _prevOrtho = !this.ortho;
                          this.update(this.viewport);        
                  }
                  
                  
Creates a transformation that produces a parallel projection. @param left @param right @param bottom @param top @param near @param far @return Matrix3D

  
                  public static function createOrthoMatrix( left:Number, right:Number, bottom:Number, top:Number, near:Number, far:Number):Matrix3D
                  {
                          var tx:Number = (right+left)/(right-left);
                          var ty:Number = (top+bottom)/(top-bottom);
                          var tz:Number = (far+near)/(far-near);
                                  
                          var matrix:Matrix3D = new Matrix3D( [
                                  2/(right-left), 0, 0, tx,
                                  0, 2/(top-bottom), 0, ty,
                                  0, 0, -2/(far-near), tz,
                                  0, 0, 0, 1 
                          ] );
                          
                          matrix.calculateMultiply(Matrix3D.scaleMatrix(1,1,-1), matrix);
                          
                          return matrix;
                  }
                          
                  
Creates a transformation that produces a perspective projection. @param fov @param aspect @param near @param far @return Matrix3D

  
                  public static function createPerspectiveMatrix( fov:Number, aspect:Number, near:Number, far:Number ):Matrix3D
                  {
                          var fov2:Number = (fov/2) * (Math.PI/180);
                          var tan:Number = Math.tan(fov2);
                          var f:Number = 1 / tan;
                          
                          return new Matrix3D( [
                                  f/aspect, 0, 0, 0,
                                  0, f, 0, 0,
                                  0, 0, -((near+far)/(near-far)), (2*far*near)/(near-far),
                                  0, 0, 1, 0 
                          ] );
                  }
                  
                  private var _projection                                : Matrix3D;
                  private var _prevFocus                                : Number;
                  private var _prevZoom                                : Number;
                  private var _prevWidth                                : Number;
                  private var _prevHeight                                : Number;
                  private var _prevOrtho                                : Boolean;
                  private var _prevOrthoProjection        : Boolean;
                  private var _prevUseProjection                : Boolean;
                  private var _focusFix                                : Matrix3D;
          }
  }
  


(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.