// forked from tkinjo's Collada /* * Mouse controlled PV3D camera class (collada room forked from tkinjo) * * CTRL + mouse drag - rotate * SHIFT + drag (up/down) - zoom * ALT + drag - move (x/y) * */ package { import flash.display.Sprite; import org.papervision3d.core.proto.CameraObject3D; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.objects.parsers.DAE; import org.papervision3d.scenes.Scene3D; import org.papervision3d.view.AbstractView; import org.papervision3d.view.BasicView; [SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "#000000")] /** * Papervision3D で COLLADA オブジェクトを表示する。 * * まあ、ただ単に Blender とのコラボをやってみたかっただけで。 * * モデルデータは 3DCG ソフトの Blender のみです。 * テクスチャもレンダーベイキング機能で作成。 * * @author tkinjo */ public class Main extends BasicView { /** * */ public function Main() { stage.quality = "low"; _camera = new InteractiveCamera3D( viewport ); var dae:DAE = new DAE(); dae.scale = 200; dae.load( "http://cross.gentenzero.com/wonderfl/assets/collada/room.dae" ); scene.addChild( dae ); startRendering(); } } } import flash.events.*; import org.papervision3d.cameras.*; import org.papervision3d.view.Viewport3D; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.core.math.*; import org.papervision3d.core.log.PaperLogger; /** * InteractiveCamera3D is a mouse controlled camera. */ class InteractiveCamera3D extends Camera3D { /** * Constructor. * * @param viewport The viewport, used for mouse interaction * @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 InteractiveCamera3D( viewport3D:Viewport3D, // TODO: stage/viewport?? fov:Number=60, near:Number=10, far:Number=5000, useCulling:Boolean=false, useProjection:Boolean=false ) { super( fov, near, far, useCulling, useProjection ); this.viewport3D = viewport3D; viewport3D.stage.addEventListener( MouseEvent.MOUSE_DOWN, mouseDown ); } protected var targetDistance:Number = 1000; protected var viewport3D:Viewport3D; public override function set target(object:DisplayObject3D):void { PaperLogger.error("You tried to set an InteractiveCamera3D's target property. " + "Don't do that! (you can use lookAt instead)"); } public override function lookAt( targetObject:DisplayObject3D, upAxis:Number3D=null ):void { targetDistance = distanceTo( targetObject ); super.lookAt( targetObject, upAxis ); } public static const SPIN:uint = 1; public static const MOVE:uint = 2; public static const ZOOM:uint = 3; public static const INACTIVE:uint = 0; protected var _state:uint = INACTIVE; public function get state():uint { return _state; } // these hold values from when interaction was started protected var initialTransform:Matrix3D; protected var initialMouseX:Number; protected var initialMouseY:Number; protected var enterFrame:Function; protected function startInteraction( type:uint, listener:Function ):void { if( state != INACTIVE ) { stopInteraction(); } if( _transformDirty ) { updateTransform(); } initialTransform = Matrix3D.clone( this.transform ); initialMouseX = viewport3D.stage.mouseX; initialMouseY = viewport3D.stage.mouseY; _state = type; enterFrame = listener; viewport3D.stage.addEventListener( Event.ENTER_FRAME, enterFrame ); viewport3D.stage.addEventListener( MouseEvent.MOUSE_UP, stopInteraction ); } protected function stopInteraction( e:Event = null ):void { viewport3D.stage.removeEventListener( Event.ENTER_FRAME, enterFrame ); viewport3D.stage.removeEventListener( MouseEvent.MOUSE_UP, stopInteraction ); _state = INACTIVE; } protected function spinHandler( e:Event ):void { // calculate axis - perpendicular to mouse vector, swap x and y var p:Number3D = new Number3D( (initialMouseY - viewport3D.stage.mouseY) / viewport3D.stage.height * 3, (initialMouseX - viewport3D.stage.mouseX) / viewport3D.stage.width * 3, 0 ); // calculate angle (radians) var rad:Number = -p.modulo * Math.PI; // rotate axis (compensate for cam rotation) Matrix3D.rotateAxis( initialTransform, p ); // create a target object (from targetDistance) var target:DisplayObject3D = new DisplayObject3D; target.copyTransform( initialTransform ); target.moveForward( targetDistance ); var refPoint:Number3D = new Number3D( target.x, target.y, target.z ); // rotate cam around axis copyTransform( Matrix3D.multiply( Matrix3D.rotationMatrixWithReference( p, rad, refPoint ), initialTransform ) ); } protected function moveHandler( e:Event ):void { var x:Number = initialMouseX - viewport3D.stage.mouseX; var y:Number = initialMouseY - viewport3D.stage.mouseY; copyTransform( initialTransform ); moveDown( y ); moveRight( x ); } // TODO: rewrite this. targetdistance is no good without a real target object protected function zoomHandler( e:Event ):void { var y:Number = (initialMouseY - viewport3D.stage.mouseY) / viewport3D.stage.height; var dist:Number = 0; dist = targetDistance * y * 10; if( targetDistance - dist > focus ) { copyTransform( initialTransform ); moveForward( dist ); } } public function interactiveSpin():void { startInteraction( SPIN, spinHandler ); } public function interactiveMove():void { startInteraction( MOVE, moveHandler ); } public function interactiveZoom():void { startInteraction( ZOOM, zoomHandler ); } protected function mouseDown( e:MouseEvent ):void { if( e.ctrlKey ) { interactiveSpin(); } else if ( e.altKey ) { interactiveMove(); } else if ( e.shiftKey ) { interactiveZoom(); } } } InteractiveCamera3D test