InteractiveCamera3D test
Mouse controlled PV3D camera class (collada room forked from tkinjo)
*
* CTRL + mouse drag - rotate
* SHIFT + drag (up/down) - zoom
* ALT + drag - move (x/y)
*
/**
* Copyright yonatan ( http://wonderfl.net/user/yonatan )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/uWAM
*/
// 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();
}
}
}