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

Collada Import & Bone [Alternativa3D 7.6]

とりあえず、アニメシーケンス設定しない状態で読み込んだ、Bone付きSkinを読み込んで、直接bone(Joint)を操作したサンプルです。

7.5.0では、フリーの3Dツール、Blenderから吐き出したColladaファイル(Dae)は、Boneを設定すると正しくParse出来なかったのですが、7.5.1で、修正された模様です。
ローカルでテストする場合は、最新のSWCを入手してください。

なお、直接プリミティブを作成し、Boneを埋め込むテストもしてみましたが、残念ながらBoneとSkinの頂点関連付けにバグ?があるのか(はたまた、必要なメソッドが公開されてないのか・・・)で、現Ver7.5.1でもできませんでした:P

書ききれないので、ソースコード中のコメントに続くw

2011/01/12 7.5から7.6仕様に変更
Get Adobe Flash player
by narutohyper 23 Oct 2012
/**
 * Copyright narutohyper ( http://wonderfl.net/user/narutohyper )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/dJHS
 */

// forked from narutohyper's Alternativa3D 7.5 Template
package
{
    import alternativ7.engine3d.containers.ConflictContainer;
    import alternativ7.engine3d.controllers.SimpleObjectController;
    import alternativ7.engine3d.core.Debug;
    import alternativ7.engine3d.core.Sorting;
    import alternativ7.engine3d.loaders.ParserCollada;
    import alternativ7.engine3d.materials.FillMaterial;
    import alternativ7.engine3d.objects.Joint;
    import alternativ7.engine3d.objects.Mesh;
    import alternativ7.engine3d.objects.Skin;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    
    
    
    /**
     * Alternativa3D 7.5
     *
     * Collada(dae)ファイルの読み込み、パースとBoneの操作
     *
     * とりあえず、アニメシーケンス設定しない状態で読み込んだ、Bone付きSkinを読み込んで、直接bone(Joint)を操作したサンプルです。
     *
     * 7.5.0では、フリーの3Dツール、Blenderから吐き出したColladaファイル(Dae)は、
     * Boneを設定すると正しくParse出来なかったのですが、7.5.1で、修正された模様です。
     * ローカルでテストする場合は、最新のSWCを入手してください。
     *
     * なお、直接プリミティブを作成し、Boneを埋め込むテストもしてみましたが、
     * 残念ながらBoneとSkinの頂点関連付けにバグ?があるのか(はたまた、必要なメソッドが公開されてないのか・・・)で、
     * 現Ver7.5.1でもできませんでした:P
     *
     * 書き出しに使用した、Blenderファイル
     * 'http://marubayashi.net/archive/sample/alt3d7/bone/boxAndBone.blend'
     *
     * Blenderは、かなりクセがあるTOOLですが、現状フリーでBone付きアニメがColladaで書き出せるTOOLはこれだけなので、
     * なんとか使いこなして行きたいものです。(3DMaxは高すぎて買えないしw)
     * そのうち、Blenderからのalternativa3Dへの描き出しとか、ブログにあっぷします・・・たぶんw
     * なお、最新のBlenderのColladaプラグインでも、へっぽこデータしか出てこないので、以下kumaryu.netサイトから、
     * パッチを入手し充てておく必要あり
     * http://www.kumaryu.net/?(Blender)+COLLADA+Exporter
     *
     * kumaryu.net様に多謝
     * 
     * @author narutohyper
     */
    [SWF(backgroundColor="#000000", frameRate="100", width="800", height="600")]
    public class Main extends Sprite
    {
        
        private var loader:URLLoader;
        private var modelURL:String = 'http://marubayashi.net/archive/sample/alt3d7/bone/boxAndBone.dae';
        private const SCALE:Number = 5;
        
        public function Main():void    {
        
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }

        
        private function init(e:Event=null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
        
            //daeファイルの読み込み
            loader = new URLLoader();
            loader.addEventListener(Event.COMPLETE, onModelLoad);
            loader.load(new URLRequest(modelURL));
            
        }
        
        private function onModelLoad(e:Event):void {
            loader.removeEventListener(Event.COMPLETE, onModelLoad);
        
            //AlternativaTemplate作成
            var scene:AlternativaTemplate = new AlternativaTemplate(this);
            
            //Objectを格納するContainer(ObjectContainerでもいい気がするが・・・)
            var colladaContainer:ConflictContainer = new ConflictContainer();
            scene.container.addChild(colladaContainer);
            
            //  注意!!
            //Blenderが吐き出すDaeファイルでは、以下の置換が必要
            //Daeで直接書き直してもOKだが、ファイルエクスポートの度に書き直すのはめんどくさいので、置換
            var myPattern:RegExp = /IDREF/g;
            loader.data=loader.data.replace(myPattern, "Name");

            //----------------------------------------------------
            //Pars
            //----------------------------------------------------
            var collada:ParserCollada = new ParserCollada();
            collada.parse(XML(loader.data), modelURL);
            
            var objects:* = collada.objects;

            //----------------------------------------------------
            //objectの抜き出し
            //----------------------------------------------------
            var count:int = objects.length;
            var i:int;
            
            var testSkin:Skin;
            
            for (i = 0;  i < count; i++) {
                if (objects[i].name == 'Camera') {
                    //trace(objects[o].name,o)
                } else {
                    if (objects[i].constructor == Mesh) {
                    } else if (objects[i].constructor == Skin) {
                        //カメラや、ライトは、Object3Dとして書き出される。
                        //アーマチュアー(Bone)を関連付けされたMeshはSkinとして書き出される
                        //Boneが関連付けされていないMeshはMeshとして書き出される
                        testSkin = objects[i] as Skin;
                        //必ず、calculateBindingMatricesを実行。しないと、3Dモデルがつぶれます。(時に、ぐちゃぐちゃになる)
                        testSkin.calculateBindingMatrices();
                        testSkin.sorting = Sorting.AVERAGE_Z;
                        testSkin.scaleX = SCALE;
                        testSkin.scaleY = SCALE;
                        testSkin.scaleZ = SCALE;
                        colladaContainer.addChild(testSkin);
                    }
                    
                }
            }

            
            //読み込んだSkinからBone(Joint)を取り出す;
            //(Blenderが吐き出すBoneはJoint)
            testSkin.y = 0;
            var bones:Vector.<Joint> = new Vector.<Joint>;
            //rootBoneの取得
            bones[0] = testSkin.getJointAt(0);
            bones[1] = bones[0].getChildAt(0);
            //bones[1].rotationX=140*Math.PI/180

            //material
            var material:FillMaterial = new FillMaterial(0xCCCCFF,1,0,1);
            testSkin.setMaterialToAllFaces(material);
            
            //----------------------------------------------------
            // Camera controller
            //----------------------------------------------------
            var colladaController:SimpleObjectController = new SimpleObjectController(stage, colladaContainer, 200);
            colladaController.mouseSensitivity = 0.5;
            colladaController.unbindAll();

            scene.camera.debug = true;
            addChild(scene.camera.diagram);

            scene.camera.debug = true;
            scene.camera.addToDebug(Debug.BONES, Joint);
            //BlenderDaeはJointなので、Debug.BONESでは表示できない?
            //JointをBoneに変換も出来ず(頂点の関連付けが、現Verではどうやらバグがある?為)
            //scene.camera.addToDebug(Debug.BONES, bones[0]);
            //scene.camera.addToDebug(Debug.EDGES, Skin);
            
            
            //カメラの調整
            //カメラはControllerに関連付けている為、x,y,zで直接位置を指定できないので
            //SimpleController.setObjectPosXYZを使用
            scene.cameraController.setObjectPosXYZ(0, -100, 0);
            scene.cameraController.lookAtXYZ(0, 0, 0);

            var angle:Number = 0;
            var RADIAN:Number = Math.PI / 180;
            scene.onPreRender = function():void {
                //Boneをうねうね動かす。
                angle+=4;
                bones[1].rotationZ = (Math.cos(angle * RADIAN) * 60+180) * RADIAN;
                colladaController.update();
            }
            
            //描画開始
            scene.startRendering();
            
        }

    }
    
}






/**
 * BasicTemplate for Alternativa3D 7.5
 * Alternativa3D 7.5を扱いやすくするためのテンプレートです
 * @author narutohyper & clockmaker
 *
 */
import alternativ7.engine3d.containers.BSPContainer;
import alternativ7.engine3d.containers.ConflictContainer;
import alternativ7.engine3d.containers.DistanceSortContainer;
import alternativ7.engine3d.containers.KDContainer;
import alternativ7.engine3d.containers.LODContainer;
import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.core.View;
import flash.display.DisplayObject;

import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;

import flash.events.Event;

class AlternativaTemplate extends Sprite
{
    /**
     * 子オブジェクトを最適な方法でソートするコンテナ
     * (ConflictContainer)
     */
    public static const CONFLICT:String = 'conflict';
    /**
     * 子オブジェクトをBSP(バイナリ空間分割法)によってソートするコンテナ
     * (BSPContainer)
     */
    public static const BSP:String = 'bsp';
    
    /**
     * 子オブジェクトをカメラからのZ値でソートするコンテナ
     * (DistanceSortContainer)
     */
    public static const ZSORT:String = 'zsort';
    /**
     * KDツリー(http://ja.wikipedia.org/wiki/Kd%E6%9C%A8)によってソートするコンテナ
     * (KDContainer)
     */
    public static const KD:String = 'kd';
    /**
     * detalizationと子オブジェクトの距離でソートするコンテナ(詳細は調査中)
     * (LODContainer)
     */
    public static const LOD:String = 'lod';
    
    /**
     * 3dオブジェクト格納するコンテナインスタンス。
     */
    public var container:Object3DContainer;

    /**
     * ビューインスタンスです。
     */
    public var view:View;
    
    /**
     * カメラインスタンスです。
     */
    public var camera:Camera3D;
    
    /**
     * カメラコントローラーです。
     */
    public var cameraController:SimpleObjectController;
    
    private var _mc:DisplayObjectContainer;
    private var _viewWidth:int;
    private var _viewHeight:int;
    private var _scaleToStage:Boolean;
    private var _containerType:String;
    
    /**
     * 新しい Alternativa3DTemplate インスタンスを作成します。
     * @param    mc
     * @param    containerType
     * @param    viewWidth
     * @param    viewHeight
     * @param    scaleToStage
     */
    public function AlternativaTemplate(mc:DisplayObjectContainer,containerType:String=CONFLICT,viewWidth:int=640, viewHeight:int=480, scaleToStage:Boolean = true)
    {
        
        _mc = mc;
        _mc.addChild(this);

        _containerType = containerType;
        _viewWidth = viewWidth;
        _viewHeight = viewHeight;
        _scaleToStage = scaleToStage;
        
        if (stage) init();
        else addEventListener(Event.ADDED_TO_STAGE, init);
    }


    /**
     * 初期化されたときに実行されるイベントです。
     * 初期化時に実行したい処理をオーバーライドして記述します。
     */
    protected function atInit():void {}


    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング前に実行したい処理をオーバーライドして記述します。
     */
    protected function atPreRender():void {}
    
    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング前に実行したい処理をオーバーライドして記述します。
     */
    private var _onPreRender:Function = function():void{};
    public function get onPreRender():Function { return _onPreRender; }
    public function set onPreRender(value:Function):void
    {
        _onPreRender = value;
    }
    
    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング後に実行したい処理をオーバーライドして記述します。
     */
    protected function atPostRender():void {}
    
    /**
     * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
     * レンダリング後に実行したい処理を記述します。
     */
    private var _onPostRender:Function = function():void{};
    public function get onPostRender():Function { return _onPostRender; }
    public function set onPostRender(value:Function):void
    {
        _onPostRender = value;
    }
    
    
    /**
     * レンダリングを開始します。
     */
    public function startRendering():void
    {
        addEventListener(Event.ENTER_FRAME, onRenderTick);
    }

    /**
    * レンダリングを停止します。
    */
    public function stopRendering():void
    {
        removeEventListener(Event.ENTER_FRAME, onRenderTick);
    }

    /**
     * シングルレンダリング(レンダリングを一回だけ)を実行します。
     */
    public function singleRender():void
    {
        onRenderTick();
    }

    /**
     * @private
     */
    private function init(e:Event = null):void
    {
        removeEventListener(Event.ADDED_TO_STAGE, init);
        // entry point
        stage.scaleMode = StageScaleMode.NO_SCALE;
        stage.align = StageAlign.TOP_LEFT;
        stage.quality = StageQuality.HIGH;
        
        //Root objectの作成
        if (_containerType == CONFLICT) {
            container = new ConflictContainer();
        } else if (_containerType == BSP) {
            container = new BSPContainer();
        } else if (_containerType == ZSORT) {
            container = new DistanceSortContainer();
        } else if (_containerType == KD) {
            container = new KDContainer();
        } else if (_containerType == LOD) {
            container = new LODContainer();
        }
        //Viewの作成
        view = new View(stage.stageWidth, stage.stageHeight);
        _mc.addChild(view);

        //cameraの作成
        camera = new Camera3D();
        camera.view = view;
        camera.x = 0;
        camera.y = -500;
        camera.z = 0;
        container.addChild(camera);
        
        // Camera controller
        cameraController = new SimpleObjectController(stage, camera, 10);
        cameraController.mouseSensitivity = 0;
        cameraController.unbindAll();
        cameraController.lookAtXYZ(0, 0, 0);
        
        onResize();
        stage.addEventListener(Event.RESIZE, onResize);
        
        atInit();
    }
    
    /**
     * @private
     */    
    private function onResize(e:Event = null):void 
    {
        if (_scaleToStage)
        {
            view.width = stage.stageWidth;
            view.height = stage.stageHeight;
        } 
        else
        {
            view.width = _viewWidth;
            view.height = _viewHeight;
        }
    }
    
    /**
     * @private
     */    
    private function onRenderTick(e:Event = null):void 
    {
        atPreRender();
        _onPreRender();
        cameraController.update();
        camera.render();
        atPostRender();
        _onPostRender();
    }
    
    
}