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

Hello pot.

メタセコイアから書き出した.OBJ形式のファイルを超ざっくり読み込んでパースし、表示してみました。

とりあえずライティングは頂点シェーダー側ですべて行っています。
Get Adobe Flash player
by ume 16 Dec 2011
    Embed
/**
 * Copyright ume ( http://wonderfl.net/user/ume )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/jf5p
 */

package  {
    import net.hires.debug.Stats;

    import flash.display.Sprite;
    import flash.text.TextField;
    
    import com.adobe.utils.*;
    import flash.utils.getTimer;
    import flash.events.*;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;

    import flash.display3D.*;
    import flash.geom.Matrix3D;
    import flash.geom.Vector3D;

    [SWF(width="465", height="465", frameRate="60")]
    
    public class HelloPot extends Sprite{
        //3Dコンテクスト
        private var context3D:Context3D;
        private var program:Program3D;
        //頂点・法線・インデックス
        private var vertexbuffer:VertexBuffer3D;
        private var normalbuffer:VertexBuffer3D;
        private var indexBuffer:IndexBuffer3D; 
        //WVP
        private var constMatrix:Matrix3D;
        private var modelMatrix:Matrix3D;
        private var cameraMatrix:Camera;
        private var perspective:PerspectiveMatrix3D;
        //もろもろ
        private var movieWidth:Number = 465;
        private var movieHeight:Number = 465;
        private var msg:TextField;
        private var canRender:Boolean;
        private var objData:OBJParser; 
        
        public function HelloPot() {
            
            //スタッツ等配置
            var stats:Stats = new Stats();
            stage.addChild(stats);
            msg = createTF();
            addChild(msg);
            
            //サイズ固定
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;    
                        
            //レンダリングフラグ初期化
            canRender = false;
            
            //3D準備
            stage.stage3Ds[0].addEventListener( Event.CONTEXT3D_CREATE, onContext );
            stage.stage3Ds[0].addEventListener( ErrorEvent.ERROR, onErrContext );
            stage.stage3Ds[0].requestContext3D();
        }
        private function onErrContext(e:ErrorEvent):void{
            msg.text = "err:" + e.text;
        }
        //テキストボックス準備
        private function createTF():TextField{
            var msg:TextField = new TextField();
            msg.multiline = true;
            msg.width = 150;
            msg.height = 100;
            msg.border = true;
            msg.x = stage.stageWidth - msg.width - 5;
            msg.y = stage.stageHeight - msg.height - 5;
            msg.text = "Hello";
            return msg
        }
        //モデル読み込み完了時イベントハンドラメソッド
        private function onComp():void{
            msg.text = "OBJ読み込み完了";
            
            //頂点情報セット
            setBuffer();
            msg.text = "頂点セット完了";
            //プログラムセット
            setProgram();
            msg.text = "プログラムセット完了";
            //マトリクス初期化
            constMatrix = new Matrix3D();
            modelMatrix = new Matrix3D();
            cameraMatrix=new Camera();
            cameraMatrix.InitView(new Vector3D(0,5,10), new Vector3D(0,0,0), Vector3D.Y_AXIS);
            perspective = new PerspectiveMatrix3D();
            perspective.perspectiveFieldOfViewRH(45*Math.PI/180, movieWidth / movieHeight, 0.1, 1000.0);

            msg.text = "モデル読み込み完了\nポリゴン数:" + objData._rawIndexBuffer.length/3 + "\n頂点数:" + objData._rawVertexBuffer.length/3 + "\n法線数:" + objData._rawNormalBuffer.length/3 + "\n頂点共有してません><;"
            this.canRender = true;
            //OBJ解放
            objData.dispose();
            objData = null;
        }
        // コンテキスト準備完了時
        private function onContext(e:Event):void{
            msg.text = "コンテクスト準備完了";
            context3D = stage.stage3Ds[0].context3D;
            context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 1, true);
            addEventListener(Event.ENTER_FRAME, onRender);
            //モデルデータ読み込み
            try{
                objData = new OBJParser("http://ciruelo.jp/assets/teapot.obj",0xFFFFFF,0.01);
                //objData = new OBJParser("teapot.obj",0xFFFFFF,0.01);
                msg.text = "OBJ読み込開始";
            }catch(e:Error){
                msg.text = "@エラー:" + e.message;
            }
            objData.compFunc = onComp;
        }

        //プログラムセット
        private function setProgram():void{
            //頂点シェーダーを生成 今回は頂点側でライティング計算まで行う
            var vertexShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler(true);            
            
            vertexShaderAssembler.assemble( Context3DProgramType.VERTEX,
                //頂点出力
                "m44 vt0, va0, vc0\n" +                 
                "mov op, vt0\n" +                        
                //ディフューズとアンビエント計算 最適化を考えずに地道に計算中
                "m44 vt1, va1, vc4\n"    +                
                "dp3 vt2.x vt1, vc8\n" +                
                "sat vt2.x, vt2.x\n" +                    
                "add vt2.x, vt2.x, vc11.z\n" +
                "mul vt2.xyz, vt2.xxx, vc9.xyz\n" +        
                "mov vt2.w vc9.w\n" +                     
                //スペキュラ計算
                "sub vt3, vc10, vt0\n" +                 
                "nrm vt3.xyz, vt3\n" +                    
                "mov vt3.w, vc9.w\n" +                     
                "add vt3.xyz, vt3.xyz, vt1.xyz\n" +        
                "nrm vt3.xyz, vt3\n" +                    
                "mov vt3.w, vc9.w\n" +     
                "dp3 vt4.x, vt3, vt1\n" +                 
                "sat vt4.x, vt4.x\n" +                    
                "pow vt4.x, vt4.x, vc11.y\n" +            
                "mul vt4.x, vt4.x, vc11.w\n" +            
                "mul vt5.xyz, vt4.xxx, vc12\n" +
                //色を出力
                "add vt2.xyz, vt2.xyz, vt5.xyz\n" +        
                "mov vt2.w vc9.w\n" + 
                "mov v0, vt2"                             
            );
    
            //フラグメントシェーダー(ピクセルシェーダー)今回はお仕事なっしん
            var fragmentShaderAssembler : AGALMiniAssembler= new AGALMiniAssembler(true);
            fragmentShaderAssembler.assemble( Context3DProgramType.FRAGMENT,
                "mov oc, v0\n" 
            );
            //プログラムを生成・セット
            program = context3D.createProgram();
            program.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);
            context3D.setProgram(program);
        }
        
        //頂点等セット
        private function setBuffer():void{
            //頂点・法線
            var vertices:Vector.<Number> = objData._rawVertexBuffer;
            var normals:Vector.<Number> = objData._rawNormalBuffer;
            //頂点数・法線数・インデックス数を算出
            var vertexLength:int = objData._rawVertexBuffer.length/3;
            var normalLength:int = objData._rawNormalBuffer.length/3;
            var indexLength:int = objData._rawIndexBuffer.length;    
            // 頂点バッファを作成・アップロード
            vertexbuffer = context3D.createVertexBuffer(vertexLength, 3);
            vertexbuffer.uploadFromVector(vertices, 0, vertexLength);
            // 法線バッファを作成・アップロード
            normalbuffer = context3D.createVertexBuffer(normalLength,3);
            normalbuffer.uploadFromVector(normals, 0, normalLength);
            // インデックスバッファを作成・アップロード
            indexBuffer = context3D.createIndexBuffer(indexLength);            
            indexBuffer.uploadFromVector (objData._rawIndexBuffer, 0, indexLength);

            // 頂点・対応する法線をレジスタva0・va1にセット
            context3D.setVertexBufferAt(0, vertexbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
            context3D.setVertexBufferAt(1, normalbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
        }
        
        // レンダリング
        private function onRender(e:Event):void{
            if ( !context3D ) return;
            
            context3D.clear ( 0.3, 0.3, 0.3, 1 );
            
            //変換マトリクス生成
            //モデル回転
            modelMatrix.identity()
            modelMatrix.appendRotation(getTimer()/10,Vector3D.Y_AXIS);
            
            constMatrix.identity();
            constMatrix.append(modelMatrix);
            constMatrix.append(cameraMatrix.matrix);
            constMatrix.append(perspective);
            
            constMatrix.appendTranslation(0,-2,0);
            
            /* 頂点プログラムで使用する定数 */
            //vc0-vc3:WVPマトリクス
            context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0,constMatrix, true);
            //vc4-vc7:ワールド座標変換用マトリクス
            context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 4,modelMatrix, true);
            //vc8:ライトの法線
            context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 8,Vector.<Number>([0.5773502691896258, 0.5773502691896258, 0.5773502691896258, 1]));
            //vc9:ベースカラー いわゆるマテリアルの色
            context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX,9,Vector.<Number>([0.6,0,0,1]));
            //vc10:カメラ座標 0,5,10固定で
            context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX,10,Vector.<Number>([0, 5, 10, 1]));
            //vc11:反射係数, power値
            context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX,11,Vector.<Number>([1, 30, 0.25, 0.5]));
            //vc12:スペキュラ色(白)
            context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX,12,Vector.<Number>([1, 1, 1, 1]));
            
            /* フラグメントプログラムで使用する定数 */
            //今回はありませぬ。
            
            //三角ポリゴン描画
            context3D.drawTriangles(indexBuffer);
            //取り出して画面に反映
            context3D.present();
        }
    }
}

import flash.geom.Matrix3D;
import flash.geom.Vector3D;
/*
なんちゃってカメラ
*/
class Camera {
    private var _view:Matrix3D;

    public function Camera() {  
        _view = new Matrix3D();
    }
    //右手系でいわゆるlookat
    public function InitView( from:Vector3D, at:Vector3D, up:Vector3D ) : void {
        var vz:Vector3D = from.subtract( at );
        vz.normalize();
        var vx:Vector3D = up.crossProduct( vz );
        vx.normalize();
        var vy:Vector3D = vz.crossProduct( vx );
        vy.normalize();
        var vtx:Number = vx.dotProduct( from ) * -1;
        var vty:Number = vy.dotProduct( from ) * -1;
        var vtz:Number = vz.dotProduct( from ) * -1;
        
        _view.identity();
        _view.rawData = Vector.<Number>([
            vx.x, vy.x, vz.x, 0,
            vx.y, vy.y, vz.y, 0,
            vx.z, vy.z, vz.z, 0,
            vtx,  vty,  vtz,  1,
        ]);        
    }
    public function get matrix():Matrix3D {
        return _view;
    }
}

import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.events.SecurityErrorEvent;
import flash.events.IOErrorEvent;
import flash.system.Security;


/*
とりあえず、.objを読み込んでみて、頂点・法線・インデックスだけをパースするクラス
*/
class OBJParser{
    
    private const LINE_FEED:String = String.fromCharCode(10);
    private const SPACE:String = String.fromCharCode(32);
    private const SLASH:String = "/";
    private const VERTEX:String = "v";
    private const NORMAL:String = "vn";
    private const INDEX_DATA:String = "f";

    private var _loader:URLLoader;
    private var _color:uint;
        
    //3種類の一時的バッファ
    private var _vertexTemp:Array;
    private var _normalTemp:Array;
    private var _indexTemp:Array;
        
    //3種類のアップロード用バッファ
    public var _rawIndexBuffer:Vector.<uint> = new Vector.<uint>();
    public var _rawVertexBuffer:Vector.<Number> = new Vector.<Number>();
    public var _rawNormalBuffer:Vector.<Number> = new Vector.<Number>();
        
    //スケール
    private var _scale:Number;
        
    //読み込み完了後のハンドラ用
    public var compFunc:Function;

    public function OBJParser(path:String, defaultColor:uint = 0xFFFFFF ,scale:Number = 0.01){
        Security.loadPolicyFile("http://ciruelo.jp/assets/crossdomain.xml");
        _color = defaultColor;
        _scale = scale;
            
        var req:URLRequest = new URLRequest(path);
        _loader = new URLLoader(req);
        _loader.addEventListener(Event.COMPLETE, _onLoadComp);
        _loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,_onErr);
    }
        
    //読み込みエラー
    private function _onErr(e:SecurityErrorEvent):void{
        var err:Error = e as Error;
        throw err;
    }

    //読み込み完了
    private function _onLoadComp(e:Event):void{
        // 1行ごと取り出して読み込む
        var data:String = String(_loader.data);
            
        this._indexTemp = [];
        this._vertexTemp = [];
        this._normalTemp = [];
            
        var lines:Array = data.split(LINE_FEED);
        var loop:int = lines.length;
        for (var i:int = 0; i < loop; ++i){
            parseLine(lines[i]);
        }            
        //バッファ用データに変換
        _rawIndexBuffer = new Vector.<uint>();
        _rawVertexBuffer = new Vector.<Number>();
        _rawNormalBuffer = new Vector.<Number>();
            
        parseBuffer();
            
        //コールバック実行
        compFunc();
    }
        
    //バッファ用データに変換
    private function parseBuffer():void{
        var vIndex:int = 0;
        var nIndex:int = 0;
            
        for(var i:int=0;i<this._indexTemp.length;i++){
            //3つインデックスデータを取り出す
            var poly1:Array = _indexTemp[i][0];
            var poly2:Array = _indexTemp[i][1];
            var poly3:Array = _indexTemp[i][2];
            var v:int=3;
                
            _rawVertexBuffer.push(
                    _vertexTemp[poly1[0]*v], _vertexTemp[poly1[0]*v+1], _vertexTemp[poly1[0]*v+2],
                    _vertexTemp[poly2[0]*v], _vertexTemp[poly2[0]*v+1], _vertexTemp[poly2[0]*v+2],
                    _vertexTemp[poly3[0]*v], _vertexTemp[poly3[0]*v+1], _vertexTemp[poly3[0]*v+2]
                                 );
                
            _rawNormalBuffer.push(
                    _normalTemp[poly1[2]*v], _normalTemp[poly1[2]*v+1], _normalTemp[poly1[2]*v+2],
                    _normalTemp[poly2[2]*v], _normalTemp[poly2[2]*v+1], _normalTemp[poly2[2]*v+2],
                    _normalTemp[poly3[2]*v], _normalTemp[poly3[2]*v+1], _normalTemp[poly3[2]*v+2]
                                 );
            //インデックスバッファ作成
            _rawIndexBuffer.push(i*3, i*3+1, i*3+2);
        }
    }
    //1行ごとの処理
    private function parseLine(line:String):void{
        // スペースごとに区切る
        var words:Array = line.split(SPACE);

        if (words.length > 0){
            var data:Array = words.slice(1);
        }else{
            return;
        }
        var firstWord:String = words[0];
        switch (firstWord){
            case VERTEX :
                parseVertex(data);
                break;
            case NORMAL :
                parseNormal(data);
                break;
            case INDEX_DATA :
                parseIndex(data);
                break;
        }
    }
    //頂点
    private function parseVertex(data:Array):void{
        var loop:int = 3;
        for (var i:uint = 0; i < loop; i++){
            var element:String = data[i];
            _vertexTemp.push(Number(element)*_scale);
        }
    }
    //法線
    private function parseNormal(data:Array):void{
        var loop:int = 3;
        for (var i:uint = 0; i < loop; i++){
            var element:String = data[i];
            _normalTemp.push(Number(element));
        }
    }
    //面
    private function parseIndex(data:Array):void{
        var poly:Array = [];
        var loop:int = 3;
            
        for(var i:int=0;i<loop;i++){
            var v:Array = [];
            var element:Array = data[i].split(SLASH);
            for(var j:int=0;j<loop;j++){
                //objの番号は、「1」から始まるのでひとつ減算
                v.push(Number(element[j])-1)
            }
            poly.push(v);
        }
        _indexTemp.push(poly);
    }
    
    //データ解放
    public function dispose():void{
        _vertexTemp = _normalTemp = _indexTemp = null;
        _rawVertexBuffer = _rawNormalBuffer = null;
        _rawIndexBuffer = null;
    }
}