package away3d.cameras { import away3d.arcane; import away3d.core.base.*; import away3d.core.draw.*; import away3d.core.math.*; import away3d.core.render.*; import away3d.core.utils.*; import away3d.events.CameraEvent; import flash.utils.*; use namespace arcane; /** * Dispatched when the focus or zoom properties of a camera update. * * @eventType away3d.events.CameraEvent * * @see #focus * @see #zoom */ [Event(name="cameraUpdated",type="away3d.events.CameraEvent")] /** * Basic camera used to resolve a view. * * @see away3d.containers.View3D */ public class Camera3D extends Object3D { private var _aperture:Number = 22; private var _dof:Boolean = false; private var _flipY:MatrixAway3D = new MatrixAway3D(); private var _focus:Number; private var _zoom:Number; private var _fov:Number; private var _view:MatrixAway3D = new MatrixAway3D(); private var _screenVertex:ScreenVertex = new ScreenVertex(); private var _vtActive:Array = new Array(); private var _vtStore:Array = new Array(); private var _vt:MatrixAway3D; private var _cameraupdated:CameraEvent; private var _x:Number; private var _y:Number; private var _z:Number; private var _sz:Number; private var _persp:Number; private function notifyCameraUpdate():void { if (!hasEventListener(CameraEvent.CAMERA_UPDATED)) return; if (_cameraupdated == null) _cameraupdated = new CameraEvent(CameraEvent.CAMERA_UPDATED, this); dispatchEvent(_cameraupdated); } public var invView:MatrixAway3D = new MatrixAway3D(); /** * Dictionary of all objects transforms calulated from the camera view for the last render frame */ public var viewTransforms:Dictionary; public function createViewTransform(node:Object3D):MatrixAway3D { if (_vtStore.length) _vtActive.push(_vt = viewTransforms[node] = _vtStore.pop()); else _vtActive.push(_vt = viewTransforms[node] = new MatrixAway3D()); return _vt } public function clearViewTransforms():void { viewTransforms = new Dictionary(true); _vtStore = _vtStore.concat(_vtActive); _vtActive = new Array(); } /** * Used in DofSprite2D. * * @see away3d.sprites.DofSprite2D */ public function get aperture():Number { return _aperture; } public function set aperture(value:Number):void { _aperture = value; DofCache.aperture = _aperture; } /** * Used in DofSprite2D. * * @see away3d.sprites.DofSprite2D */ public function get dof():Boolean { return _dof; } public function set dof(value:Boolean):void { _dof = value; if (_dof) enableDof(); else disableDof(); } /** * A divisor value for the perspective depth of the view. */ public function get focus():Number { return _focus; } public function set focus(value:Number):void { _focus = value; DofCache.focus = _focus; notifyCameraUpdate(); } /** * Provides an overall scale value to the view */ public function get zoom():Number { return _zoom; } public function set zoom(value:Number):void { _zoom = value; notifyCameraUpdate(); } /** * Defines the field of view of the camera in a vertical direction. */ public function get fov():Number { return _fov; } public function set fov(value:Number):void { _fov = value; } /** * Used in DofSprite2D. * * @see away3d.sprites.DofSprite2D */ public var maxblur:Number = 150; /** * Used in DofSprite2D. * * @see away3d.sprites.DofSprite2D */ public var doflevels:Number = 16; /** * Creates a new Camera3D object. * * @param init [optional] An initialisation object for specifying default instance properties. */ public function Camera3D(init:Object = null) { super(init); zoom = ini.getNumber("zoom", 10); focus = ini.getNumber("focus", 100); aperture = ini.getNumber("aperture", 22); maxblur = ini.getNumber("maxblur", 150); doflevels = ini.getNumber("doflevels", 16); dof = ini.getBoolean("dof", false); var lookat:Number3D = ini.getPosition("lookat"); _flipY.syy = -1; if (lookat != null) lookAt(lookat); } /** * Used in DofSprite2D. * * @see away3d.sprites.DofSprite2D */ public function enableDof():void { DofCache.doflevels = doflevels; DofCache.aperture = aperture; DofCache.maxblur = maxblur; DofCache.focus = focus; DofCache.resetDof(true); } /** * Used in DofSprite2D * * @see away3d.sprites.DofSprite2D */ public function disableDof():void { DofCache.resetDof(false); } /** * Returns the transformation matrix used to resolve the scene to the view. * Used in the ProjectionTraverser class * * @see away3d.core.traverse.ProjectionTraverser */ public function get view():MatrixAway3D { invView.multiply(sceneTransform, _flipY); _view.inverse(invView); return _view; } /** * Returns a ScreenVertex object describing the resolved x and y position of the given Vertex object. * * @param object The local object for the Vertex. If none exists, use the Scene3D object. * @param vertex The vertex to be resolved. * * @see away3d.containers.Scene3D */ public function screen(object:Object3D, vertex:Vertex = null):ScreenVertex { if (vertex == null) vertex = new Vertex(0,0,0); createViewTransform(object).multiply(view, object.sceneTransform); project(viewTransforms[object], vertex, _screenVertex); return _screenVertex } /** * Projects the vertex to the screen space of the view. */ public function project(viewTransform:MatrixAway3D, vertex:Vertex, screenvertex:ScreenVertex):void { _x = vertex.x; _y = vertex.y; _z = vertex.z; _sz = _x * viewTransform.szx + _y * viewTransform.szy + _z * viewTransform.szz + viewTransform.tz; /*/ //modified var wx:Number = x * view.sxx + y * view.sxy + z * view.sxz + view.tx; var wy:Number = x * view.syx + y * view.syy + z * view.syz + view.ty; var wz:Number = x * view.szx + y * view.szy + z * view.szz + view.tz; var wx2:Number = Math.pow(wx, 2); var wy2:Number = Math.pow(wy, 2); var c:Number = Math.sqrt(wx2 + wy2 + wz*wz); var c2:Number = (wx2 + wy2); persp = c2? projection.focus*(c - wz)/c2 : 0; sz = (c != 0 && wz != -c)? c*Math.sqrt(0.5 + 0.5*wz/c) : 0; //*/ //end modified if (isNaN(_sz)) throw new Error("isNaN(sz)"); if (_sz*2 <= -focus) { screenvertex.visible = false; return; } else { screenvertex.visible = true; } _persp = zoom / (1 + _sz / focus); screenvertex.x = (_x * viewTransform.sxx + _y * viewTransform.sxy + _z * viewTransform.sxz + viewTransform.tx) * _persp; screenvertex.y = (_x * viewTransform.syx + _y * viewTransform.syy + _z * viewTransform.syz + viewTransform.ty) * _persp; screenvertex.z = _sz; /* projected.x = wx * persp; projected.y = wy * persp; */ } /** * Rotates the camera in its vertical plane. * * Tilting the camera results in a motion similar to someone nodding their head "yes". * * @param angle Angle to tilt the camera. */ public function tilt(angle:Number):void { super.pitch(angle); } /** * Rotates the camera in its horizontal plane. * * Panning the camera results in a motion similar to someone shaking their head "no". * * @param angle Angle to pan the camera. */ public function pan(angle:Number):void { super.yaw(angle); } /** * Duplicates the camera's properties to another Camera3D object. * * @param object [optional] The new object instance into which all properties are copied. * @return The new object instance with duplicated properties applied. */ public override function clone(object:Object3D = null):Object3D { var camera:Camera3D = (object as Camera3D) || new Camera3D(); super.clone(camera); camera.zoom = zoom; camera.focus = focus; return camera; } /** * Default method for adding a cameraUpdated event listener * * @param listener The listener function */ public function addOnCameraUpdate(listener:Function):void { addEventListener(CameraEvent.CAMERA_UPDATED, listener, false, 0, false); } /** * Default method for removing a cameraUpdated event listener * * @param listener The listener function */ public function removeOnCameraUpdate(listener:Function):void { removeEventListener(CameraEvent.CAMERA_UPDATED, listener, false); } } }