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

simple 3D 03 (not using PV3D)

PV3Dとかを使わない3D表現その3
カメラの移動を追加。
座標計算は行列&ベクトルに変更。
Matrix3DとVector3Dは自作のを。

ボールはx軸回転。
カメラはマウスの位置によってY軸周りを動きます。
カメラが動いてるってのが分かりにくいかも。

カメラの動きはこちらのものを拝借させてもらってます。
http://wonderfl.net/c/lBrO
Get Adobe Flash player
by sakef 28 Oct 2010
/**
 * Copyright sakef ( http://wonderfl.net/user/sakef )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/hMDD
 */

/*
    PV3Dとかを使わない3D表現その3
    カメラの移動を追加。
    座標計算は行列&ベクトルに変更。
    Matrix3DとVector3Dは自作のを。

    ボールはx軸回転。
    カメラはマウスの位置によってY軸周りを動きます。
    カメラが動いてるってのが分かりにくいかも。
    
    カメラの動きはこちらのものを拝借させてもらってます。
    http://wonderfl.net/c/lBrO
*/
package
{
    import net.wonderfl.utils.SequentialLoader;
    import net.hires.debug.Stats;
    import flash.display.Loader;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.display.StageQuality;
    import flash.events.Event;
    import flash.filters.BlurFilter;
    import flash.geom.Point;
    
    [SWF(width="465", height="465", backgroundColor="0xffffff", frameRate="30")]
    public class simple3d_03 extends Sprite
    {
        // 画像のURL
        private const imgURL:String="http://assets.wonderfl.net/images/related_images/6/64/643a/643a412effc1d96e4df242ad7590fe90fa7a56c1";
        
        // 3Dボール用
        private static const RADIUS:Number=180;
        private static const N_POINT1:int=10;
        private static const N_POINT2:int=10;
        private static const RADIAN:Number=Math.PI / 180;
        private static const SIN2:Number=Math.sin(RADIAN * 2);
        private static const COS2:Number=Math.cos(RADIAN * 2);
        
        // 被写界深度画像用
        private static const N_BLUR_IMG:int=20;
        private static const BLUR_RANGE:int=140;
        private static const STEP:Number=BLUR_RANGE / N_BLUR_IMG;
        
        // 幅・高さ・中心
        private static const CENTER_X:int=465 >> 1;
        private static const CENTER_Y:int=465 >> 1;
        private static const W:int=465;
        private static const H:int=465;
        
        // 上を示すベクトル・中心を示すベクトル・フォーカス
        private var UP_VECTOR:MyVector3D=new MyVector3D(0, 1, 0);
        private var CENTER_VECTOR:MyVector3D=new MyVector3D(0, 0, 0);
        private var FOCUS:Number=360;
        
        // 3Dボールを保持する配列・画像を保持する配列・3DBallの数を保持する変数
        private var ballAry:Array;
        private var imgAry:Array;
        private var n_balls:int;
        
        // カメラ用
        private var camera:MyVector3D;
        private var camera_radius:int;
        private var theta:Number;
        private var camera_calc_flug:int;
        
        // 画像ロード用
        private var imgs:Array;
        
        // コンストラクタ
        public function simple3d_03()
        {
            imgs=[];
            SequentialLoader.loadImages([imgURL], imgs, onLoaded);
        }

        
        // 初期化用関数
        public function onLoaded():void
        {
            // 画像の読み込み
            var ldr:Loader=imgs.pop();
            var ballImg:BitmapData=(ldr.content as Bitmap).bitmapData;    
            
            // ステージ設定、マウス関係停止。
            stage.quality=StageQuality.LOW;
            mouseChildren=false;
            mouseEnabled=false;
            
            // Stats追加
            addChild(new Stats());
           
            // 変数の初期化
            var i:int, j:int;
            theta=n_balls=0;
            camera_calc_flug=1;
            camera_radius=360;
            ballAry=[];
            imgAry=[];
            camera=new MyVector3D(0, 0, FOCUS);
            
            // ブラー付きのBitmapDataを先に作っておくべ。
            var p:Point=new Point();
            for(i=0; i < N_BLUR_IMG; i++)
            {
                var tmp:BitmapData=ballImg.clone();
                tmp.applyFilter(tmp, tmp.rect, p, new BlurFilter(0.6 * i, 0.6 * i));
                imgAry[i]=tmp;
            }
            
            // 各点の初期位置を計算
            for(i=0; i < N_POINT1; i++)
            {
                var theta1:Number=(360 / N_POINT1) * i * RADIAN;
                var start:int=(i == 0) ? (0) : (1);
                for(j=start; j < N_POINT2; j++)
                {
                    var theta2:Number=((180 / N_POINT2) * j - 90) * RADIAN;
                    var xx:Number=RADIUS * Math.cos(theta2) * Math.sin(theta1);
                    var yy:Number=RADIUS * Math.sin(theta2);
                    var zz:Number=RADIUS * Math.cos(theta2) * Math.cos(theta1);
                    var ball:MyBall3D=new MyBall3D(ballImg, xx, yy, zz);
                    ballAry[n_balls]=ball;
                    addChild(ball);
                    n_balls++;
                }
            }
            
            // 更新用関数追加
            addEventListener(Event.ENTER_FRAME, onFrame);
        }
        
        // 計算更新用関数
        private function onFrame(e:Event):void
        {
            // カメラの移動
            theta+=10 * (mouseX / stage.stageWidth - 0.5);
            camera.x=camera_radius * Math.sin(RADIAN * theta);
            camera.z=camera_radius * Math.cos(RADIAN * theta);
            
            // 半径計算 (大きくなったり小さくなったり)
            if (camera_calc_flug == 1)
            {
                camera_radius+=2;
                if (camera_radius > 600) camera_calc_flug=0;
            }
            else
            {
                camera_radius-=2;
                if (camera_radius < 250) camera_calc_flug=1;
            }
            
            // Center - Eye ベクトルの作成と正規化
            var n:MyVector3D=CENTER_VECTOR.subtract(camera);
            n.normalize();
            
            // up×nを計算 (外積)
            var u:MyVector3D=UP_VECTOR.crossProduct(n);
            u.normalize();
            
            // n×uを計算 (外積)
            var v:MyVector3D=n.crossProduct(u);
            v.normalize();
            
            // dの計算
            var dx:Number=-camera.innerProduct(u);
            var dy:Number=-camera.innerProduct(v);
            var dz:Number=-camera.innerProduct(n);
            
            // ビューイング変換行列
            var Mview:MyMatrix3D=new MyMatrix3D(u.x, u.y, u.z, dx, v.x, v.y, v.z, dy, n.x, n.y, n.z, dz, 0, 0, 0, 1);
            
            // モデリング変換変換行列 (X軸回転)
            var Mmodel:MyMatrix3D=new MyMatrix3D(1, 0, 0, 0, 0, COS2, -SIN2, 0, 0, SIN2, COS2, 0, 0, 0, 0, 1);
            
            // モデルビュー変換行列
            var Mmodeview:MyMatrix3D=Mview.productMatrix(Mmodel);
            
            // 各ボールに座標変換を適用
            var ball:MyBall3D;
            var position:MyVector3D;
            var eyeCord_position:MyVector3D;
            var scale:Number;
            var screenX:int, screenY:int;
            var blurIndex:int;
            for(var i:int=0; i < n_balls; i++)
            {
                ball=ballAry[i]as MyBall3D;
                position=ball.position;
                
                // 座標変換
                position=Mmodel.productVector(position);
                eyeCord_position=Mmodeview.productVector(position);
                
                // カメラとの距離計算
                ball.sortNumber=eyeCord_position.distance(CENTER_VECTOR);
                
                // 3D→2D変換 
                scale=FOCUS / ball.sortNumber;
                screenX=((eyeCord_position.x)) * scale + CENTER_X;
                screenY=-((eyeCord_position.y)) * scale + CENTER_Y;
                
                // 計算反映
                ball.scaleX=ball.scaleY=scale;
                ball.x=screenX;
                ball.y=screenY;
                
                // BitmapDataの更新
                blurIndex=((FOCUS - ball.sortNumber) / STEP) >> 0;
                blurIndex=(blurIndex ^ (blurIndex >> 31)) - (blurIndex >> 31)
                blurIndex=(blurIndex >= N_BLUR_IMG) ? (N_BLUR_IMG - 1) : (blurIndex);
                ball.bitmapData=imgAry[blurIndex]as BitmapData;
                
                // 座標の保存
                ball.position=position;
            }
            
            // zソート
            ballAry.sortOn("sortNumber", Array.NUMERIC | Array.DESCENDING);
            for(i=0; i < n_balls; i++)
            {
                ball=ballAry[i]as MyBall3D;
                setChildIndex(ball, i)
            }
        }
    }
}


/*
3Dボールクラス
*/
import flash.display.Bitmap;
import flash.display.BitmapData;

final class MyBall3D extends Bitmap
{
    public var position:MyVector3D;
    public var sortNumber:Number;
    private var bmpd_w:Number;
    private var bmpd_h:Number;
    
    public function MyBall3D(material:BitmapData, x:Number=0, y:Number=0, z:Number=0)
    {
        position=new MyVector3D(x, y, z);
        sortNumber=0;
        bitmapData=material;
        bmpd_w=material.width >> 1;
        bmpd_h=material.height >> 1;
    }
    
    override public function set x(value:Number):void
    {
        super.x=value - bmpd_w;
    }
    
    override public function set y(value:Number):void
    {
        super.y=value - bmpd_h;
    }
}



/*
行列演算用クラス
*/
final class MyMatrix3D
{
    // 行列の要素
    public var v11:Number, v12:Number, v13:Number, v14:Number;
    public var v21:Number, v22:Number, v23:Number, v24:Number;
    public var v31:Number, v32:Number, v33:Number, v34:Number;
    public var v41:Number, v42:Number, v43:Number, v44:Number;
    
    // コンストラクタ
    public function MyMatrix3D(v11:Number=1, v12:Number=0, v13:Number=0, v14:Number=0, 
                               v21:Number=0, v22:Number=1, v23:Number=0, v24:Number=0, 
                               v31:Number=0, v32:Number=0, v33:Number=1, v34:Number=0, 
                               v41:Number=0, v42:Number=0, v43:Number=0, v44:Number=1)
    {
        this.v11=v11; this.v12=v12; this.v13=v13; this.v14=v14;
        this.v21=v21; this.v22=v22; this.v23=v23; this.v24=v24;
        this.v31=v31; this.v32=v32; this.v33=v33; this.v34=v34;
        this.v41=v41; this.v42=v42; this.v43=v43; this.v44=v44;
    }
    
    // 行列との積 (自分をA、引数をBとするとA*B)
    public function productMatrix(m:MyMatrix3D):MyMatrix3D
    {
        var newMat:MyMatrix3D=new MyMatrix3D();
        
        newMat.v11=v11 * m.v11 + v12 * m.v21 + v13 * m.v31 + v14 * m.v41;
        newMat.v12=v11 * m.v12 + v12 * m.v22 + v13 * m.v32 + v14 * m.v42;
        newMat.v13=v11 * m.v13 + v12 * m.v23 + v13 * m.v33 + v14 * m.v43;
        newMat.v14=v11 * m.v14 + v12 * m.v24 + v13 * m.v34 + v14 * m.v44;
        
        newMat.v21=v21 * m.v11 + v22 * m.v21 + v23 * m.v31 + v24 * m.v41;
        newMat.v22=v21 * m.v12 + v22 * m.v22 + v23 * m.v32 + v24 * m.v42;
        newMat.v23=v21 * m.v13 + v22 * m.v23 + v23 * m.v33 + v24 * m.v43;
        newMat.v24=v21 * m.v14 + v22 * m.v24 + v23 * m.v34 + v24 * m.v44;
        
        newMat.v31=v31 * m.v11 + v32 * m.v21 + v33 * m.v31 + v34 * m.v41;
        newMat.v32=v31 * m.v12 + v32 * m.v22 + v33 * m.v32 + v34 * m.v42;
        newMat.v33=v31 * m.v13 + v32 * m.v23 + v33 * m.v33 + v34 * m.v43;
        newMat.v34=v31 * m.v14 + v32 * m.v24 + v33 * m.v34 + v34 * m.v44;
        
        newMat.v41=v41 * m.v11 + v42 * m.v21 + v43 * m.v31 + v44 * m.v41;
        newMat.v42=v41 * m.v12 + v42 * m.v22 + v43 * m.v32 + v44 * m.v42;
        newMat.v43=v41 * m.v13 + v42 * m.v23 + v43 * m.v33 + v44 * m.v43;
        newMat.v44=v41 * m.v14 + v42 * m.v24 + v43 * m.v34 + v44 * m.v44;
        
        return newMat;
    }
    
    // ベクトルとの積
    public function productVector(v:MyVector3D):MyVector3D
    {
        var newVec:MyVector3D=new MyVector3D();
        
        newVec.x=v11 * v.x + v12 * v.y + v13 * v.z + v14;
        newVec.y=v21 * v.x + v22 * v.y + v23 * v.z + v24;
        newVec.z=v31 * v.x + v32 * v.y + v33 * v.z + v34;
        
        return newVec;
    }
}


/*
ベクトル演算用クラス
*/
final class MyVector3D
{
    // x、y、z座標を保存する変数
    public var x:Number;
    public var y:Number;
    public var z:Number;
    public var w:Number;
    
    // コンストラクタ
    public function MyVector3D(x:Number=0, y:Number=0, z:Number=0)
    {
        this.x=x;
        this.y=y;
        this.z=z;
        this.w=1;
    }
    
    // 距離
    public function distance(v:MyVector3D):Number
    {
        return Math.sqrt((v.x - x) * (v.x - x) + (v.y - y) * (v.y - y) + (v.z - z) * (v.z - z));
    }
    
    // 差
    public function subtract(v:MyVector3D):MyVector3D
    {
        var newVec:MyVector3D=new MyVector3D();
        
        newVec.x=x - v.x;
        newVec.y=y - v.y;
        newVec.z=z - v.z;
        
        return newVec;
    }
    
    // 正規化
    public function normalize():void
    {
        var len:Number=Math.sqrt(x * x + y * y + z * z);
        x/=len;
        y/=len;
        z/=len;
    }
    
    // 内積
    public function innerProduct(v:MyVector3D):Number
    {
        return (x * v.x + y * v.y + z * v.z);
    }
    
    // 外積(クロス積) (自分をA、引数をBとすると、A×Bを計算)
    public function crossProduct(v:MyVector3D):MyVector3D
    {
        var newVec:MyVector3D=new MyVector3D();
        
        newVec.x=y * v.z - z * v.y;
        newVec.y=z * v.x - x * v.z;
        newVec.z=x * v.y - y * v.x;
        
        return newVec;
    }
}