forked from: forked from: 3D VOCALOID RUNS!

by tepe forked from forked from: 3D VOCALOID RUNS! (diff: 556)
♥0 | Line 303 | Modified 2014-06-27 10:48:05 | MIT License
play

ActionScript3 source code

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

// forked from tepe's forked from: 3D VOCALOID RUNS!
// forked from daniwell's 3D VOCALOID RUNS!
package  
{
    import alternativa.engine3d.core.Camera3D;
    import alternativa.engine3d.core.Object3D;
    import alternativa.engine3d.core.Resource;
    import alternativa.engine3d.core.View;
    import alternativa.engine3d.lights.AmbientLight;
    import alternativa.engine3d.lights.DirectionalLight;
    import alternativa.engine3d.lights.OmniLight;
    import alternativa.engine3d.materials.TextureMaterial;
    import alternativa.engine3d.primitives.Plane;
    import alternativa.engine3d.resources.BitmapTextureResource;
    import alternativa.engine3d.materials.TextureMaterial;
    import alternativa.types.Texture;
    import flash.display.*;
    import flash.display3D.Context3DRenderMode;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.geom.Point;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.ui.Keyboard;
    import flash.text.*;
    import flash.geom.*;
    
    public class ModelRun extends Sprite 
    {
        // MMD でモーション付けて、Blender のプラグインで読み込んで COLLADA 書き出しするだけ
        // 但しモーションに IK は使えない
        private const PATH_DAEIDLE :Array = ["http://aidn.jp/_wonderfl/vr/miku_idle.dae",    "http://aidn.jp/_wonderfl/vr/rin_idle.dae",    "http://aidn.jp/_wonderfl/vr/len_idle.dae"];
        private const PATH_DAERUN  :Array = ["http://aidn.jp/_wonderfl/vr/miku_run.dae",     "http://aidn.jp/_wonderfl/vr/rin_run.dae",     "http://aidn.jp/_wonderfl/vr/len_run.dae"];
        private const PATH_TEXTURE :Array = ["http://aidn.jp/_wonderfl/vr/miku_texture.png", "http://aidn.jp/_wonderfl/vr/rin_texture.png", "http://aidn.jp/_wonderfl/vr/len_texture.png"];
        
        //private const CAMERA_DISTANCE :Number = 600;
        private const BOX_NUMS        :int    = 30;
        private var camDis:Number= 600;
        
        private var _texture :BitmapData;
        private var _daeIdle :XML;
        private var _daeRun  :XML;
        
        private var _n :int = int(Math.random() * 3);//キャラ選択
        
        private var _stage3D :Stage3D;
        private var _camera  :Camera3D;
        private var _scene   :Object3D;
        
        private var _model    :ColladaModel;
        private var _shadow   :Plane;
        private var _boxes    :/*CustomBox*/Array = [];
        private var _keyFlags :/*Boolean*/Array = [];
        
        private var _t      :Number = 0;
        private var _rot    :Number = 0;
        private var _rotTmp :Number = -90;
        
        private var _cameraZ :Number = 50;
        
        private var _tfLoading :TextField;
        
        private var tf:TextField;
        
        public function ModelRun () {
            
            stage.scaleMode = "noScale";
            stage.align     = "TL";
            
            tf = new TextField();
            addChild(tf);
            tf.background = true;
            tf.text = "test\n";

            // Now Loading
            _tfLoading = addChild(new TextField()) as TextField;
            _tfLoading.defaultTextFormat = new TextFormat("_sans", 42, 0x999999, true);
            _tfLoading.autoSize = "left"; _tfLoading.text = "NOW LOADING...";
            stage.addEventListener(Event.ENTER_FRAME, _enterFrame);//メインループ

            // Stage3D
            _stage3D = stage.stage3Ds[0];
            _stage3D.addEventListener(Event.CONTEXT3D_CREATE, _contextCreate);// #01
            _stage3D.requestContext3D(Context3DRenderMode.AUTO);
            
            
        }
        
        // #01
        private function _contextCreate ( evt :Event ) :void {
            tf.appendText("1:contextCreate\n");
            _stage3D.removeEventListener(Event.CONTEXT3D_CREATE, _contextCreate);// #01
            
            // IDLE 時データ読み込み #02
            var ul :URLLoader = new URLLoader();
            ul.addEventListener(Event.COMPLETE, _loadCompleteIdle);
            ul.load(new URLRequest(PATH_DAEIDLE[_n]));
        }
        
        // #02 IDLE読み込み完了
        private function _loadCompleteIdle ( evt :Event ) :void  {
            tf.appendText("2:load Idle\n");
            _daeIdle = XML(URLLoader(evt.target).data);
            
            // RUN 時データ読み込み #03
            var ul :URLLoader = new URLLoader();
            ul.addEventListener(Event.COMPLETE, _loadCompleteRun);
            ul.load(new URLRequest(PATH_DAERUN[_n]));
        }
        
        // #03 RUN読み込み完了
        private function _loadCompleteRun ( evt :Event ) :void {
            tf.appendText("3:load Run\n");
            _daeRun = XML(URLLoader(evt.target).data);
            
            var l :Loader = new Loader();
            l.contentLoaderInfo.addEventListener(Event.COMPLETE, _loadCompleteTexture);// #04
            l.load(new URLRequest(PATH_TEXTURE[_n]), new LoaderContext(true));
        }
        
        // #04 テクスチャ読み込み完了
        private function _loadCompleteTexture ( evt :Event ) :void {
            tf.appendText("4:load Texture\n");
            _tfLoading.visible = false;
            _texture = Bitmap(evt.target.content).bitmapData;//テクスチャ画像
            initModel();
        }
        
        private var models:Array = new Array();
        
        // #05
        private function initModel():void{
            _scene  = new Object3D();//シーン
            _camera = new Camera3D(1, 10000);//カメラ
            
            _camera.view = new View(stage.stageWidth, stage.stageHeight);//ビュー
            _camera.view.hideLogo();//ロゴ非表示 
            addChild(_camera.view);//画面表示
            //addChild(_camera.diagram);//パフォーマンス表示
            
            //カメラ設定
            _camera.rotationX = MathUtil.toRad(-90);
            _camera.x = 0; _camera.y = 0; _camera.z = 250;
            _camera.fov = 1.8;
            
            _scene.addChild(_camera);
            
            tf.appendText("\n");

            
            // モデル
            _model = new ColladaModel(_stage3D, _scene);
            _model.init(_daeIdle, _texture, 0, 0, -300, 100);
            _model.addAnimation(_daeIdle, 0);//モーション1
            _model.addAnimation(_daeRun,  1);//モーション2
            
            for(var i:int=0;i<10;i++){
                var m:ColladaModel = new ColladaModel(_stage3D,_scene);
                m.init(_daeIdle,_texture,Math.random()*1000,Math.random()*1000,-300,Math.random()*200+50);
                m.x = Math.random()*10000;
                m.y = Math.random()*10000;
                m.z = -300;
                m.addAnimation(_daeIdle,0);
                m.addAnimation(_daeRun,1);
                models.push(m);
            }

            
            
            // 影
            var bmd :BitmapData = new BitmapData(128, 128, false, 0x0);
            var sp :Shape = new Shape(); sp.graphics.beginFill(0xffffff); sp.graphics.drawCircle(64, 64, 64); sp.graphics.endFill();
            bmd.draw(sp);
            
            var material :TextureMaterial = new TextureMaterial(new BitmapTextureResource(new BitmapData(128, 128, false, 0x333333)), new BitmapTextureResource(bmd));
            material.alphaThreshold = 1;
            
            _shadow = new Plane(100, 100);
            _shadow.setMaterialToAllSurfaces(material);
            _shadow.z = _model.z;
            _shadow.y = _model.y;
            _scene.addChild(_shadow);
            
            
            // ライティング
            var aLight :AmbientLight = new AmbientLight(0xffffff);//環境光
            aLight.intensity = 0.5;
            _scene.addChild(aLight);
            
            
            var oLight :OmniLight = new OmniLight(0xffffff, 1000, 10000);
            oLight.x = 100; oLight.y = 200; oLight.z = 200;
            _scene.addChild(oLight);
            
            
            var dLight :DirectionalLight = new DirectionalLight(0xffffff);
            dLight.x = 0; dLight.y = - 100; dLight.z = 100; dLight.intensity = 0.5; 
            _scene.addChild(dLight);
            
            
            // Resource
            for each (var resource :Resource in _scene.getResources(true)) resource.upload(_stage3D.context3D);
            
            
            // Event
            stage.addEventListener(KeyboardEvent.KEY_DOWN, _keyDown);
            stage.addEventListener(KeyboardEvent.KEY_UP,   _keyUp);
            
            stage.addEventListener(Event.RESIZE, _resize);
            _resize();
        }
        /* RESIZE */
        private function _resize ( evt :Event = null ) :void {
            _camera.view.width  = stage.stageWidth;
            _camera.view.height = stage.stageHeight;
        }
        /* KEY DOWN & KEY UP */
        private function _keyDown ( evt :KeyboardEvent ) :void { _keyFlags[evt.keyCode] =  true; if (evt.keyCode == Keyboard.UP) _model.changeAnimation(1, 1.8); }
        private function _keyUp   ( evt :KeyboardEvent ) :void { _keyFlags[evt.keyCode] = false; if (evt.keyCode == Keyboard.UP) _model.changeAnimation(0, 1.4); }
        
//メインループ
        private function _enterFrame ( evt :Event ) :void {
            // loading
            if (! _scene) {
                _tfLoading.visible = ! _tfLoading.visible;
                return;
            }
            
            if (_keyFlags[Keyboard.LEFT])  _model.rotationZ += MathUtil.toRad(5);//左旋回
            if (_keyFlags[Keyboard.RIGHT]) _model.rotationZ -= MathUtil.toRad(5);//右旋回
            
            if (_keyFlags[Keyboard.UP]) {//キャラ前進
                
                _model.moveFront(16);
                
                var p :Point, n :int = 0;
                var l :int = _boxes.length;

                _shadow.x = _model.x;
                _shadow.y = _model.y;
            }
            
            _model.updataAnimation();//キャラのモーション
            for(var i:int=0;i<models.length;i++){
                models[i].updataAnimation();
            }

            // カメラの回転
                 if (_keyFlags[Keyboard.A]) _rotTmp  += 8;
            else if (_keyFlags[Keyboard.D]) _rotTmp  -= 8;
            else if (_keyFlags[Keyboard.W]) _cameraZ += 20;
            else if (_keyFlags[Keyboard.S]) _cameraZ -= 20;
            else if(_keyFlags[Keyboard.Z]) camDis *= 1.02;
            else if(_keyFlags[Keyboard.X]) camDis *= 0.98;
            _updateCameraPosition();//カメラ位置更新
            _camera.render(_stage3D);//描画
        }
        
        
        //カメラ位置更新
        private function _updateCameraPosition ( ) :void {
            
            _rot += (_rotTmp - _rot) / 6;
            
            var px :Number = _model.x + camDis * Math.cos(MathUtil.toRad(_rot));
            var py :Number = _model.y + camDis * Math.sin(MathUtil.toRad(_rot));
            
            _camera.x += (px - _camera.x) / 6;
            _camera.y += (py - _camera.y) / 6;
            _camera.z += (_cameraZ - _camera.z) / 6;
            
            _camera.x += Math.sin(_t / 210) * 11;
            _camera.y += Math.sin(_t / 300) * 9;
            _t += 11;
            
            var p :Point, n :int = 0;
            var l :int = _boxes.length;

            _camera.lookAt(_model.x, _model.y, _model.z);//対象方向に向ける
        }
    }//class
}//package



import alternativa.engine3d.animation.AnimationClip;
import alternativa.engine3d.animation.AnimationController;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.loaders.ParserCollada;
import alternativa.engine3d.materials.TextureMaterial;
import alternativa.engine3d.materials.VertexLightTextureMaterial;
import alternativa.engine3d.objects.Mesh;
import alternativa.engine3d.primitives.Box;
import alternativa.engine3d.resources.BitmapTextureResource;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Stage3D;
import flash.geom.*;
import mx.core.BitmapAsset;


/* -----------------------------------------------------------------
 * ColladaModel
     メッシュデータ
     テクスチャ
     モーションデータ
     座標
     移動
     
 */
class ColladaModel extends Object3D{
    private var _stage3D  :Stage3D;
    private var _material :TextureMaterial;
    
    private var _animationController :AnimationController;
    private var _animationClips      :/*AnimationClip*/Array = [];
    
    private var _textureResources :/*BitmapTextureResource*/Array = [];
    
    private var _pre :Point;
    
    public function ColladaModel ( stage3D :Stage3D, parent :Object3D = null )  {
        _stage3D = stage3D;
        if (parent) parent.addChild(this);
    }

    //モデルデータ, テクスチャ, x, y, z, scale
    public function init ( dae :*, texture :*, x :Number = 0, y :Number = 0, z :Number = 0, scale :Number = 1 ) :void {
        
        if (! (dae is XML)) dae = new XML(dae);
        if (texture is Bitmap || texture is BitmapAsset) texture = texture.bitmapData;
        
        this.x = x; this.y = y; this.z = z;
        scaleX = scaleY = scaleZ = scale;
        _pre = new Point(x, y);
        
        // Parser
        var parser :ParserCollada = new ParserCollada();
        parser.parse(dae);
        
        // Texture
        var texResource :BitmapTextureResource = new BitmapTextureResource(texture);
        texResource.upload(_stage3D.context3D);
        var txtRes :BitmapTextureResource = texResource;
        _material = new TextureMaterial(txtRes);
        
        // Mesh
        for each (var obj :Object3D in parser.objects) {
            var mesh :Mesh = obj as Mesh;
            if (mesh) { mesh.setMaterialToAllSurfaces(_material); addChild(obj); }
        }
    }
    
    /* 前進 */
    public function moveFront ( d :Number ) :void {
        _pre.x = this.x;
        _pre.y = this.y;
        
        var radZ :Number = this.rotationZ;
        this.x += d * Math.sin(radZ);
        this.y -= d * Math.cos(radZ);
    }
    
    /* アニメーションのアップデート */
    public function updataAnimation ( ) :void { 
        _animationController.update();
    }
    
    /* アニメーションを追加 */
    public function addAnimation ( dae :*, id :int ) :void {
        if (! (dae is XML)) dae = new XML(dae);
        
        // Animation Clip
        var animationClip :AnimationClip = ParserCollada.parseAnimation(dae);
        animationClip.attach(this, true);
        
        _animationClips[id] = animationClip;
        
        // Animation Controller
        if (! _animationController) {
            _animationController      =  new AnimationController();
            _animationController.root = animationClip;
        }
    }
    /* アニメーションの切り替え */
    public function changeAnimation ( id :int, speed :Number = 1.0, loop :Boolean = true ) :void {
        _animationClips[id].speed = speed;
        _animationClips[id].loop  = loop;
        _animationController.root = _animationClips[id];
    }
    
    public function get prePosition ( ) :Point {
        return _pre;
    }
}

/* -----------------------------------------------------------------
 * MathUtil
 */
class MathUtil
{
    /* min ~ max の範囲で乱数生成 */
    public static function rand ( min :Number, max :Number ) :Number { return Math.random() * ( max - min ) + min; }
    /* 角度からラジアンに変換 */
    public static function toRad ( deg :Number ) :Number { return deg * Math.PI / 180; }
    
    /* 外積 */
    public static function intersect ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, p4x :Number, p4y :Number ) :Number {
        
        var n :Number = ((p1x - p2x) * (p3y - p1y) + (p1y - p2y) * (p1x - p3x)) * ((p1x - p2x) * (p4y - p1y) + (p1y - p2y) * (p1x - p4x));
        return n;
    }
    /* 任意の三角形の中に任意の点が内包されているかどうか */
    public static function triContainsPos ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, psx :Number, psy :Number ) :Boolean {
        
        if ((p1x - p3x) * (p1y - p2y) == (p1x - p2x) * (p1y - p3y)) return false;
        
        if (intersect(p1x, p1y, p2x, p2y, psx, psy, p3x, p3y) < 0) return false;
        if (intersect(p1x, p1y, p3x, p3y, psx, psy, p2x, p2y) < 0) return false;
        if (intersect(p2x, p2y, p3x, p3y, psx, psy, p1x, p1y) < 0) return false;
        
        return true;
    }
    /* 任意の四角形の中に任意の点が内包されているかどうか(凸のみ) */
    public static function boxContainsPos ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, p4x :Number, p4y :Number, psx :Number, psy :Number ) :Boolean {
        
        if (triContainsPos(p1x, p1y, p2x, p2y, p3x, p3y, psx, psy)) return true;
        if (triContainsPos(p1x, p1y, p3x, p3y, p4x, p4y, psx, psy)) return true;
        
        return false;
    }
    /* 線分の交差判定 */
    public static function intersectLineSegment ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, p4x :Number, p4y :Number) :Boolean {
        
        if (intersect(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) < 0)
            if (intersect(p3x, p3y, p4x, p4y, p1x, p1y, p2x, p2y) < 0) return true;
        return false;
    }
    /* 点から直線におろした垂線の交点の座標 */
    public static function getCrossPoint ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, psx :Number, psy :Number ) :Point {
        
        var a :Number = p2y - p1y;
        var b :Number = p1x - p2x;
        var c :Number = (p1y - p2y) * p1x + (p2x - p1x) * p1y;
        
        var d :Number = (a * psx + b * psy + c) / (a * a + b * b);
        
        var x :Number = psx - d * a;
        var y :Number = psy - d * b;
        
        return new Point(x, y);
    }
}