Alternativa3D / Zoom to object's face

by liquid.cow
Alternativa3D 7.6

@author liquid.cow

- testing "camera.matrix.pointAt" method (see render method)
- change the camera position and -target by clicking on an object's face or the stage.
- line 119 includes a small hack for the top view (no workaround yet)
♥2 | Line 168 | Modified 2012-10-23 16:11:40 | MIT License
play

ActionScript3 source code

/**
 * Copyright liquid.cow ( http://wonderfl.net/user/liquid.cow )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/pNAF
 */

package {
    import alternativ7.engine3d.containers.KDContainer;
    import alternativ7.engine3d.core.Camera3D;
    import alternativ7.engine3d.core.Face;
    import alternativ7.engine3d.core.MouseEvent3D;
    import alternativ7.engine3d.core.Object3D;
    import alternativ7.engine3d.core.RayIntersectionData;
    import alternativ7.engine3d.core.View;
    import alternativ7.engine3d.materials.FillMaterial;
    import alternativ7.engine3d.primitives.Box;

    import gs.*;
    import gs.easing.Sine;

    import flash.display.Sprite;
    import flash.display.Stage;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix3D;
    import flash.geom.Vector3D;
    import flash.geom.Point;
    
    /**
     *
     * Alternativa3D 7.6
     *
     * Camera3D, Matrix3D, pointAt
     *
     * @author liquid.cow
     */
    [SWF(backgroundColor="#FFFFFF", frameRate="100", width="800", height="600")]
    public class Test extends Sprite
    {
        private static const V_CAMERA_INIT  : Vector3D = new Vector3D(0, 3000, -4000);
        private static const CAM_DISTANCE   : Number = 1100;
        private static const RAD2DEG        : Number = 180 / Math.PI;
        private static const DEG2RAD        : Number = Math.PI / 180;
        
        private var _container      : KDContainer;
        private var _camera         : Camera3D;
        private var _vCam           : Vector3D;
        private var _vCamTarget     : Vector3D;
        private var _cameraMatrix   : Matrix3D;
        private var _camRotationY   : Number;
        private var _vMouse3D       : Vector3D;
        private var _clickedFace    : Face;
        
        
        public function Test() : void {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event=null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            
            _camera = new Camera3D();
            _camera.view = new View(stage.stageWidth, stage.stageHeight);
            //_camera.view.interactive = true;
            addChild(_camera.view);
            
            _container = new KDContainer();
            _container.resolveByAABB = true;
            _container.resolveByOOBB = true;
            _container.addChild(_camera);
            
            _vCamTarget = new Vector3D();
            _vCam = V_CAMERA_INIT.clone();
            _camRotationY = 0;
            
            var positions:Vector.<Vector3D> = new Vector.<Vector3D>();
            positions.push(new Vector3D(-500, 0, -500), new Vector3D(500, 0, -500), new Vector3D(0, 0, 500));
            
            var rotations:Vector.<Number> = new Vector.<Number>();
            rotations.push(45 * DEG2RAD, -45 * DEG2RAD, 0);
            
            var material:FillMaterial = new FillMaterial(0xeeeeee, 1, 0, 0x0);
            
            for (var i:int = 0; i<3; i++) {
                var box:Box = new Box(200, 100, 300, 1, 1, 1);
                box.x = positions[i].x;
                box.y = positions[i].y;
                box.z = positions[i].z;
                box.rotationY = rotations[i];
                box.setMaterialToAllFaces(material);
                box.addEventListener(MouseEvent3D.CLICK, onClick);
                _container.addChild(box);
            }
            
            _camera.render();
            
            stage.addEventListener(Event.RESIZE, onResize);
            _camera.view.addEventListener(MouseEvent.CLICK, onStageClick);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            addEventListener(Event.ENTER_FRAME, render);
            onResize();
        }
        
        private function onClick(e:MouseEvent3D):void
        {
            var camRotationY:Number;
            var tempObject:Object3D = e.target as Object3D;
            var vPos:Vector3D = new Vector3D(tempObject.x, tempObject.y, tempObject.z);
            var data:RayIntersectionData = tempObject.intersectRay(e.localOrigin, e.localDirection);
            _clickedFace = data.face;
            
            var distance:Number = 1100;
            
            var v : Vector3D = _clickedFace.normal.clone();
            v.scaleBy(distance);
            v = v.add(new Vector3D(_clickedFace.normal.x * tempObject.boundMaxX, _clickedFace.normal.y * tempObject.boundMaxY, _clickedFace.normal.z * tempObject.boundMaxZ));
            
            var objectTransform:Matrix3D = tempObject.matrix.clone();
            v = objectTransform.transformVector(v);
            v.z -= _clickedFace.normal.y != 0 ? .01 : 0; // Hack for parallel view to up vector
            
            camRotationY = _clickedFace.normal.y != 0 ? tempObject.rotationY : 0;
            moveCamera(vPos, v, camRotationY);
        }
        
        private function moveCamera(vTarget : Vector3D, vCam : Vector3D, camRotationY_:Number) : void 
        {
            TweenLite.killTweensOf(_vCamTarget);
            TweenLite.to(_vCamTarget, 1, {x:vTarget.x, y:vTarget.y, z:vTarget.z, ease:Sine.easeInOut});

            TweenLite.killTweensOf(this);
            TweenLite.to(this, 1, {camRotationY:camRotationY_, ease:Sine.easeInOut});

            TweenLite.killTweensOf(_vCam);
            TweenLite.to(_vCam, 1, {x:vCam.x, y:vCam.y, z:vCam.z, ease:Sine.easeInOut});
        }

        private function render( event:Event ) : void 
        {
            _cameraMatrix = new Matrix3D();
            _cameraMatrix.identity();
            _cameraMatrix.appendTranslation(_vCam.x, _vCam.y, _vCam.z);
            _cameraMatrix.appendRotation(_camRotationY * RAD2DEG, Vector3D.Y_AXIS, _vCamTarget);
            _cameraMatrix.pointAt(new Vector3D(_vCamTarget.x, _vCamTarget.y, _vCamTarget.z), Vector3D.Z_AXIS, Vector3D.Y_AXIS);
            
            _camera.matrix = _cameraMatrix;
            _camera.render();
        }
        
        public function onResize(event:Event = null) :void
        {
            _camera.view.width = stage.stageWidth;
            _camera.view.height = stage.stageHeight;
            _camera.fov = 2 * Math.atan2(Math.sqrt(_camera.view.width * _camera.view.width + _camera.view.height * _camera.view.height) / 2, 1100);  
        }
        
        private function onStageClick(event : MouseEvent) : void 
        {
            var a:Array = _camera.view.getObjectsUnderPoint(new Point(_camera.view.mouseX, _camera.view.mouseY));
            if (a.length==0) {
                _clickedFace = null;
                moveCamera(new Vector3D(), V_CAMERA_INIT.clone(), 0);
            }
            
        }
        
        private function onMouseMove(event : MouseEvent) : void {
            if (event.target is Stage) {
                
                var origin:Vector3D = new Vector3D();
                var directionA:Vector3D = new Vector3D();
                var directionB:Vector3D = new Vector3D();
                
                _camera.calculateRay(origin, directionA, _camera.view.width / 2, _camera.view.height / 2);
                _camera.calculateRay(origin, directionB, stage.mouseX, stage.mouseY);
    
                var pos : Vector3D = intersectionPoint(origin, directionB, new Vector3D(0, 0, 0), new Vector3D(0, 1, 0));
                _vMouse3D = new Vector3D(pos.x, pos.y, pos.z);
            }
        }
        
        public static function intersectionPoint(lineStart:Vector3D, lineDirection:Vector3D, planePosition:Vector3D, planeNormal:Vector3D):Vector3D {
            
            var result:Vector3D = new Vector3D();
            var w:Vector3D = lineStart.subtract(planePosition);
            var d:Number = planeNormal.dotProduct(lineDirection);
            var n:Number = -planeNormal.dotProduct(w);
            
            var sI:Number = n / d;
            
            result.x = lineStart.x + (lineDirection.x * sI);
            result.y = lineStart.y + (lineDirection.y * sI);
            result.z = lineStart.z + (lineDirection.z * sI);

            return result;
        }

        public function get camRotationY() : Number {
            return _camRotationY;
        }

        public function set camRotationY(camRotationY : Number) : void {
            _camRotationY = camRotationY;
        }

        public function get vCamTarget() : Vector3D {
            return _vCamTarget;
        }

        public function set vCamTarget(vCamTarget : Vector3D) : void {
            _vCamTarget = vCamTarget;
        }

        public function get vCam() : Vector3D {
            return _vCam;
        }

        public function set vCam(vCam : Vector3D) : void {
            _vCam = vCam;
        }
    }
}

Forked