In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

3D Trickart

ある一点から見ると一枚の絵に見えるけど視点を移動すると……
* 
* 画面ドラッグでカメラを回転できます。
* 画像をロードするとそのときのカメラ位置で投影するので
* 色々なカメラアングルでロードしてみると面白いと思います。
* 
* 画像はこちらからお借りしました。
* http://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%8A%E3%83%BB%E3%83%AA%E3%82%B6
* 
* 参考サイト
* http://www.c3.club.kyutech.ac.jp/gamewiki/index.php?3D%BA%C2%C9%B8%CA%D1%B4%B9
Get Adobe Flash player
by poiasd 29 Jun 2010
    Embed
/**
 * Copyright poiasd ( http://wonderfl.net/user/poiasd )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/cnho
 */

/**
 * ある一点から見ると一枚の絵に見えるけど視点を移動すると……
 * 
 * 画面ドラッグでカメラを回転できます。
 * 画像をロードするとそのときのカメラ位置で投影するので
 * 色々なカメラアングルでロードしてみると面白いと思います。
 * 
 * 画像はこちらからお借りしました。
 * http://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%8A%E3%83%BB%E3%83%AA%E3%82%B6
 * 
 * 参考サイト
 * http://www.c3.club.kyutech.ac.jp/gamewiki/index.php?3D%BA%C2%C9%B8%CA%D1%B4%B9
 */
package {
    
    import com.bit101.components.PushButton;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Graphics;
    import flash.display.Loader;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix;
    import flash.geom.Matrix3D;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.geom.Vector3D;
    import flash.net.FileFilter;
    import flash.net.FileReference;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    
    [SWF (width = "465", height = "465", frameRate = "30", backgroundColor = "0xFFFFFF")]
    
    public class Main extends Sprite {
        
        private const _URL:String = "http://assets.wonderfl.net/images/related_images/9/9f/9f8a/9f8a11bc3f4602c960dee21db5f64ec3ba3c112b";
        
        private var _loader:Loader;
        private var _fileReference:FileReference;
        private var _fileFilter:FileFilter;
        private var _loadButton:PushButton;
        
        private var _stageWidth:Number;
        private var _stageHeight:Number;
        private var _centerX:Number;
        private var _centerY:Number;
        private var _camera:Camera3D;
        private var _focalLength:Number;
        private var _viewport:Sprite;
        private var _planes:Vector.<Plane>;
        private var _sortedIndices:Vector.<int>;
        private var _plainImage:BitmapData;
        
        public function Main() {
            _init();
        }
        
        private function _init():void {
            stage.scaleMode = "noScale";
            stage.align = "LT";
            _stageWidth = stage.stageWidth;
            _stageHeight = stage.stageHeight;
            _centerX = _stageWidth  * 0.5;
            _centerY = _stageHeight * 0.5;
            graphics.beginFill(0xEEEEEE);
            graphics.drawRect(0, 0, _stageWidth, _stageHeight);
            graphics.endFill();
            
            _camera = new Camera3D(stage);
            _camera.fov = 30;
            _camera.distance = 1400;
            _camera.azimuth = -45;
            _camera.elevation = -30;
            _focalLength = _camera.focalLength;
            
            _viewport = addChild(new Sprite()) as Sprite;
            
            _plainImage = _createPlainImage();
            _planes = new Vector.<Plane>(6, true);
            _planes[0] = new Plane(   0, -200,    0, 400, 400, new Vector3D(-90,   0, 0), _plainImage);
            _planes[1] = new Plane(   0,    0, -200, 400, 400, new Vector3D(  0,   0, 0), _plainImage);
            _planes[2] = new Plane( 200,    0,    0, 400, 400, new Vector3D(  0, -90, 0), _plainImage);
            _planes[3] = new Plane(   0,  200,    0, 400, 400, new Vector3D( 90,   0, 0), _plainImage);
            _planes[4] = new Plane(   0,    0,  200, 400, 400, new Vector3D(  0, 180, 0), _plainImage);
            _planes[5] = new Plane(-200,    0,    0, 400, 400, new Vector3D(  0,  90, 0), _plainImage);
            
            _sortedIndices = Vector.<int>([0, 1, 2, 3, 4, 5]);
            _sortedIndices.fixed = true;
            
            _fileReference = new FileReference();
            _fileFilter = new FileFilter("Images(JPEG, GIF, PNG)", "*.jpg;*.jpeg;*.gif;*.png");
            _fileReference.addEventListener(Event.SELECT, _selectHandler);
            _fileReference.addEventListener(Event.COMPLETE, _completeHandler);
            
            _loadButton = new PushButton(this, 0, 0, "LOAD", _clickHandler);
            _loadButton.width = 80;
            _loadButton.draw();
            
            _loader = new Loader();
            _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _loaderCompleteHandler);
            _loader.load(new URLRequest(_URL), new LoaderContext(true));
            
            stage.addEventListener(MouseEvent.MOUSE_DOWN, _mouseDownHandler);
            stage.addEventListener(MouseEvent.MOUSE_UP, _mouseUpHandler);
        }
        
        private function _loaderCompleteHandler(event:Event):void {
            _loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, _loaderCompleteHandler);
            var images:Array = _createImages(Bitmap(_loader.content).bitmapData);
            for (var i:int = 0; i < 6; i++) {
                _planes[i].image = images[i];
            }
            _render();
        }
        
        private var _preMousePos:Point = new Point();
        
        private function _mouseDownHandler(event:MouseEvent):void {
            if (event.target is PushButton) return;
            _preMousePos.x = stage.mouseX;
            _preMousePos.y = stage.mouseY;
            stage.addEventListener(MouseEvent.MOUSE_MOVE, _mouseMoveHandler);
        }
        
        private function _mouseMoveHandler(event:MouseEvent):void {
            var dx:Number = (stage.mouseX - _preMousePos.x) * 0.5;
            var dy:Number = (stage.mouseY - _preMousePos.y) * 0.5;
            var el:Number = _camera.elevation - dy;
            el = (el + 180) % 360;
            el += el < 0 ? 180 : -180;
            _camera.up.y = Math.abs(el) <= 90 ? -1 : 1;
            _camera.azimuth += dx * _camera.up.y;
            _camera.elevation = el;
            _project();
            _render();
            _preMousePos.x = stage.mouseX;
            _preMousePos.y = stage.mouseY;
        }
        
        private function _mouseUpHandler(event:MouseEvent):void {
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, _mouseMoveHandler);
        }
        
        private function _selectHandler(event:Event):void {
            _fileReference.load();
        }
        
        private function _completeHandler(event:Event):void {
            _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _loaderCompleteHandler);
            _loader.loadBytes(_fileReference.data);
        }
        
        private function _clickHandler(event:MouseEvent):void {
            _fileReference.browse([_fileFilter]);
        }
        
        private var _matrix3D:Matrix3D = new Matrix3D();
        
        private function _project():void {
            _matrix3D.identity();
            _matrix3D.append(_camera.viewMatrix);
            for each (var plane:Plane in _planes) {
                var vectors:Vector.<Vector3D> = plane.vectors;
                var tvectors:Vector.<Vector3D> = plane.transformedVectors;
                var pverts:Vector.<Number> = plane.projectedVerts;
                var v:Vector3D;
                var total:Number = 0;
                for (var i:int = 0, j:int = 0; i < 4; i++) {
                    tvectors[i] = v = _matrix3D.transformVector(vectors[i]);
                    var t:Number = 1 / v.z;
                    pverts[j++] = _centerX + v.x * _focalLength * t;
                    pverts[j++] = _centerY + v.y * _focalLength * t;
                    plane.uvtData[i * 3 + 2] = t;
                    total += v.z;
                }
                plane.centerZ = total * 0.25;
            }
        }
        
        private function _render():void {
            _sortedIndices.sort(function(m:int, n:int):Number {
                return _planes[n].centerZ - _planes[m].centerZ;
            });
            var g:Graphics = _viewport.graphics;
            g.clear();
            //g.lineStyle(0, 0xFFFFFF, 0.2);
            for (var i:int = 0; i < 6; i++) {
                var plane:Plane = _planes[_sortedIndices[i]];
                g.beginBitmapFill(plane.image, null, false, true);
                g.drawTriangles(plane.projectedVerts, plane.indices, plane.uvtData);
                g.endFill();
            }
        }
        
        private function _createImages(material:BitmapData):Array {
            _project();
            var list:Array = _getPositivePlaneIndices();
            var rect:Rectangle = _getRect(list);
            var offset:Number = 0;
            if (material.width <= material.height) {
                rect.height = material.height * rect.width / material.width;
            } else {
                var temp:Number = rect.width;
                rect.width = material.width * rect.height / material.height;
                offset = ((rect.width - temp) * 0.5) / rect.width;
            }
            
            var images:Array = [_plainImage, _plainImage, _plainImage, _plainImage, _plainImage, _plainImage];
            var shape:Shape = new Shape();
            var g:Graphics = shape.graphics;
            var vertices:Vector.<Number> = Vector.<Number>([0, 0, 400, 0, 0, 400, 400, 400]);
            var indices:Vector.<int> = Vector.<int>([0, 1, 2, 1, 3, 2]);
            var uvtData:Vector.<Number> = new Vector.<Number>();
            var pverts:Vector.<Number>;
            for (var i:int = 0; i < list.length; i++) {
                var index:int = list[i];
                pverts = _planes[index].projectedVerts;
                for (var j:int = 0, k:int = 0; j < 4; j++) {
                    uvtData[j * 3]     = (pverts[k++] - rect.x) / rect.width + offset;
                    uvtData[j * 3 + 1] = (pverts[k++] - rect.y) / rect.height;
                    uvtData[j * 3 + 2] = _planes[index].uvtData[11 - j * 3];
                }
                g.clear();
                g.beginBitmapFill(material, null, false, true);
                g.drawTriangles(vertices, indices, uvtData);
                g.endFill();
                var image:BitmapData = new BitmapData(400, 400, false, 0xFFFFFF);
                image.draw(shape);
                images[index] = image;
            }
            
            return images;
        }
        
        private function _createPlainImage():BitmapData {
            var shape:Shape = new Shape();
            var g:Graphics = shape.graphics;
            g.beginFill(0x111111, 0.6);
            g.drawRect(0, 0, 400, 400);
            g.beginFill(0xFFFFFF, 0.2);
            g.drawRect(0, 0, 400, 400);
            g.drawRect(1, 1, 398, 398);
            g.beginFill(0xFFFFFF);
            g.drawRect(180, 198, 40, 4);
            g.beginFill(0xFFFFFF);
            g.drawRect(198, 180, 4, 40);
            g.endFill();
            var plainImage:BitmapData = new BitmapData(400, 400, true, 0xFFFFFF);
            plainImage.draw(shape);
            return plainImage;
        }
        
        private function _getPositivePlaneIndices():Array {
            var list:Array = [];
            for (var i:int = 0; i < 6; i++) {
                var pverts:Vector.<Number> = _planes[i].projectedVerts;
                var v1:Vector3D = new Vector3D(pverts[2] - pverts[0], pverts[3] - pverts[1], 0);
                var v2:Vector3D = new Vector3D(pverts[4] - pverts[0], pverts[5] - pverts[1], 0);
                var cross:Vector3D = v1.crossProduct(v2);
                if (cross.z > 0) list.push(i);
            }
            return list;
        }
        
        private function _getRect(list:Array):Rectangle {
            var rect:Rectangle = new Rectangle(_stageWidth, _stageHeight, -_stageWidth, -_stageHeight);
            for (var i:int = 0; i < list.length; i++) {
                var pverts:Vector.<Number> = _planes[list[i]].projectedVerts;
                for (var j:int = 0; j < 4; j++) {
                    var x:Number = pverts[j * 2];
                    var y:Number = pverts[j * 2 + 1];
                    rect.left = x < rect.left ? x : rect.left;
                    rect.right = x > rect.right ? x : rect.right;
                    rect.top = y < rect.top ? y : rect.top;
                    rect.bottom = y > rect.bottom ? y : rect.bottom;
                }
            }
            return rect;
        }
        
    }
    
}

import flash.display.BitmapData;
import flash.display.Stage;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;

class Plane {
    
    public var vectors:Vector.<Vector3D>;
    public var transformedVectors:Vector.<Vector3D>;
    public var projectedVerts:Vector.<Number>;
    public var indices:Vector.<int>;
    public var uvtData:Vector.<Number>;
    public var centerZ:Number;
    public var image:BitmapData;
    
    public function Plane(x:Number, y:Number, z:Number, width:Number, height:Number, rotation:Vector3D, image:BitmapData) {
        width *= 0.5, height *= 0.5;
        var m:Matrix3D = new Matrix3D();
        m.appendRotation(rotation.x, Vector3D.X_AXIS);
        m.appendRotation(rotation.y, Vector3D.Y_AXIS);
        m.appendRotation(rotation.z, Vector3D.Z_AXIS);
        m.appendTranslation(x, y, z);
        vectors = new Vector.<Vector3D>(4, true);
        transformedVectors = new Vector.<Vector3D>(4, true);
        var list:Array = [-1, -1, 1, -1, -1, 1, 1, 1];
        for (var i:int = 0; i < 4; i++) {
            var v:Vector3D = new Vector3D();
            v.x = list[i * 2] * width;
            v.y = list[i * 2 + 1] * height;
            v.z = 0;
            v.w = 1;
            transformedVectors[i] = vectors[i] = m.transformVector(v);
        }
        projectedVerts = new Vector.<Number>(8, true);
        indices = Vector.<int>([0, 1, 2, 1, 3, 2]);
        indices.fixed = true;
        uvtData = Vector.<Number>([0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1]);
        uvtData.fixed = true;
        this.image = image;
    }
    
}

class Camera3D {
    
    private var _stage:Stage;
    private var _target:Vector3D;
    private var _up:Vector3D;
    private var _fov:Number;
    private var _focalLength:Number;
    private var _distance:Number;
    private var _azimuth:Number = 0;
    private var _elevation:Number = 0;
    private var _x:Number;
    private var _y:Number;
    private var _z:Number;
    
    public function Camera3D(stage:Stage) {
        _stage = stage;
        target = new Vector3D();
        up = new Vector3D(0, -1, 0);
        fov = 55;
        distance = 1000;
    }
    
    public function get target():Vector3D {
        return _target;
    }
    
    public function set target(value:Vector3D):void {
        _target = value;
    }
    
    public function get up():Vector3D {
        return _up;
    }
    
    public function set up(value:Vector3D):void {
        _up = value;
    }
    
    public function get fov():Number {
        return _fov;
    }
    
    public function set fov(value:Number):void {
        _fov = value;
        var size:int = Math.min(_stage.stageWidth, _stage.stageHeight);
        _focalLength = 0.5 * size / Math.tan(0.5 * _fov * Math.PI / 180);
    }
    
    public function get focalLength():Number {
        return _focalLength;
    }
    
    public function set distance(value:Number):void {
        _distance = value;
        _rectangular();
    }
    
    public function get distance():Number {
        return _distance;
    }
    
    public function set azimuth(value:Number):void {
        _azimuth = value;
        _rectangular();
    }
    
    public function get azimuth():Number {
        return _azimuth;
    }
    
    public function set elevation(value:Number):void {
        _elevation = value;
        _rectangular();
    }
    
    public function get elevation():Number {
        return _elevation;
    }
    
    public function set x(value:Number):void {
        _x = value;
        _polar();
    }
    
    public function get x():Number {
        return _x;
    }
    
    public function set y(value:Number):void {
        _y = value;
        _polar();
    }
    
    public function get y():Number {
        return _y;
    }
    
    public function set z(value:Number):void {
        _z = value;
        _polar();
    }
    
    public function get z():Number {
        return _z;
    }
    
    public function get viewMatrix():Matrix3D {
        var eye:Vector3D = new Vector3D(x, y, z);
        var zaxis:Vector3D = new Vector3D(_target.x - x, _target.y - y, _target.z - z);
        zaxis.normalize();
        var xaxis:Vector3D = zaxis.crossProduct(_up);
        xaxis.normalize();
        var yaxis:Vector3D = zaxis.crossProduct(xaxis);
        var trans:Vector3D = new Vector3D(-xaxis.dotProduct(eye), -yaxis.dotProduct(eye), -zaxis.dotProduct(eye));
        var v:Vector.<Number> = Vector.<Number>([xaxis.x, yaxis.x, zaxis.x, 0,
                                                 xaxis.y, yaxis.y, zaxis.y, 0,
                                                 xaxis.z, yaxis.z, zaxis.z, 0,
                                                 trans.x, trans.y, trans.z, 1]);
        return new Matrix3D(v);
    }
    
    private function _rectangular():void {
        var az:Number = _azimuth / 180 * Math.PI;
        var el:Number = _elevation / 180 * Math.PI;
        var adj:Number = _distance * Math.cos(el);
        _x = Math.cos(az) * adj;
        _y = Math.sin(el) * _distance;
        _z = Math.sin(az) * adj;
    }
    
    private function _polar():void {
        _distance = Vector3D.distance(new Vector3D(_x, _y, _z), _target);
        var el:Number = Math.asin(_y / _distance);
        var adj:Number = _distance * Math.cos(el);
        _azimuth = Math.asin(_z / adj) / Math.PI * 180;
        _elevation = el / Math.PI * 180;
    }
    
}