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 PIYO.

2つのobjファイルを読み込んで、頂点アニメーションさせてみました。
カーソルキーの左右でカメラ位置をぐるっと一周できます。
Get Adobe Flash player
by ume 20 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/3KsE
 */

package  {
    import net.hires.debug.Stats;
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.display.Stage;
    import flash.ui.Keyboard;

    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;
    import flash.display.Stage;
    import flash.display.Stage3D;
    import flash.display.Loader;
    import flash.net.URLRequest;
    import flash.display3D.textures.Texture;
    import flash.display.BitmapData;
    import flash.display.Bitmap;
    import flash.geom.Rectangle;

    [SWF(width="465", height="465", frameRate="60")]
    
    public class VertexAnimation extends Sprite{
        private var context3D:Context3D;
        private var program:Program3D;
        private var vertexbuffer:VertexBuffer3D;
        private var normalbuffer:VertexBuffer3D;
        private var indexBuffer:IndexBuffer3D; 
        private var vertexbuffer2:VertexBuffer3D;
        private var normalbuffer2:VertexBuffer3D;
        private var constMatrix:Matrix3D;
        private var modelMatrix:Matrix3D;
        private var camera: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 objList:Vector.<OBJParser>;
        private var compCount:int=0;
        private var picLoader:Loader;
        private var _isPressLeft:Boolean = false;
        private var _isPressRight:Boolean = false;
        private const PIC_URL:String ="http://ciruelo.jp/assets/piyomap.png"; 
        private const OBJ_URL_1:String ="http://ciruelo.jp/assets/piyo_1.obj";
        private const OBJ_URL_2:String ="http://ciruelo.jp/assets/piyo_2.obj";
        
        private var polyCount:int;
        
        public function VertexAnimation() {
            Wonderfl.capture_delay( 10 );
            
            var stats:Stats = new Stats();
            stage.addChild(stats);
            msg = createTF();
            addChild(msg);
            stage.scaleMode = StageScaleMode.NO_SCALE;
            canRender = false;
            stage.stage3Ds[0].addEventListener( Event.CONTEXT3D_CREATE, onContext );
            stage.stage3Ds[0].requestContext3D();
        }
        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 onContext(e:Event):void{
            context3D = stage.stage3Ds[0].context3D;
            context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 1, true);
            addEventListener(Event.ENTER_FRAME, onRender);
            picLoader = new Loader();
            picLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,onCompLoadPic);
            picLoader.load(new URLRequest(PIC_URL));
        }
        private function onCompLoadPic(e:Event):void{
            picLoader.scaleX = picLoader.scaleY = 0.5;
            picLoader.y = stage.height - picLoader.height;
            addChild(picLoader);
            objList = new Vector.<OBJParser>();
            try{
                objList.push(new OBJParser(OBJ_URL_1,0xFFFFFF,1));
                objList.push(new OBJParser(OBJ_URL_2,0xFFFFFF,1));
                objList[0].compFunc = onComp;
                objList[1].compFunc = onComp;
                
            }catch(e:Error){
                msg.text = "@エラー:" + e.message;
            }
            
        }
        private function onComp():void{
            compCount++
            if(compCount!=objList.length){
                return;
            }
            setBuffer();
            setTexture();
            setProgram();
            
            constMatrix = new Matrix3D();
            modelMatrix = new Matrix3D();
            camera=new Camera();
            camera.lookAt(new Vector3D(0,2,8), new Vector3D(0,0,0), Vector3D.Y_AXIS);
            perspective = new PerspectiveMatrix3D();
            perspective.perspectiveFieldOfViewRH(45*Math.PI/180, movieWidth / movieHeight, 0.5, 1000.0);

            msg.text = "モデル読み込み完了\nポリゴン数:" + objList[1].rawIndexBuffer.length/3 +  "\nPOS:" + objList[0].mtlPosList + "\nPOLY:" + objList[0].mtlPolyList;
            this.canRender = true;
            objList[0].dispose();
            objList[1].dispose();
            
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKey);
            stage.addEventListener(KeyboardEvent.KEY_UP, onKey);
        }
        private function onKey(e:KeyboardEvent):void{
            var flg:Boolean = e.type==KeyboardEvent.KEY_DOWN;
            switch(e.keyCode){
                case Keyboard.LEFT:
                _isPressLeft = flg;
                break;
            case Keyboard.RIGHT:
                _isPressRight = flg;
                break;
            }
        }
        private function setTexture():void{
            var bmd:BitmapData = Bitmap(picLoader.content).bitmapData;
            var texture:Texture = context3D.createTexture(bmd.width, bmd.height, Context3DTextureFormat.BGRA, false);
            texture.uploadFromBitmapData(bmd);
            context3D.setTextureAt(0, texture);
        }
        private function setProgram():void{
            var vertexShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler(true);            
            
            vertexShaderAssembler.assemble( Context3DProgramType.VERTEX,
                "mul vt0, va0.xyz, vc11.xxx\n" +
                "mul vt1, va2.xyz, vc11.yyy\n" +
                "add vt0, vt0, vt1\n" +
                "mov vt0.w, vc11.w\n" +
                "m44 vt0, vt0, vc0\n" + 
                "mov op, vt0\n" +
                
                "mul vt0, va1.xyz, vc11.xxx\n" +
                "mul vt1, va3.xyz, vc11.yyy\n" +
                "add vt1, vt0, vt1\n" +
                "mov vt1.w, vc11.w\n" +
                "m44 vt1, vt1, vc4\n"    +                
                "dp3 vt2.x vt1, vc8\n" +                
                "sat vt2.x, vt2.x\n" +                    
                "mov vt2.xyzw, vt2.x\n" +
                "mov v0, vt2\n"    +
                
                "m44 vt0, va0, vc4\n" + 
                            
                "sub vt3, vc10, vt0\n" +                 
                "nrm vt3.xyz, vt3\n" +                    
                "mov vt3.w, vc11.w\n" +                     

                "dp3 vt3.x, vt3, vt1\n" +                 
                "sat vt3.x, vt3.x\n" +
                "mov v1, vt3\n" +
                
                "mov v2, vc12\n"
            );
            var fragmentShaderAssembler : AGALMiniAssembler= new AGALMiniAssembler(true);
            fragmentShaderAssembler.assemble( Context3DProgramType.FRAGMENT,
                
                "mov ft3, v0\n" +
                "mov ft3.y, v1.x\n" +
                "tex ft2, ft3, fs0 <2d,linear,nomip>\n" + 
                "mul ft2, ft2, v2\n" +
                
                "mov oc, ft2\n"
            );
            program = context3D.createProgram();
            program.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);
            context3D.setProgram(program);
        }
        
        private function setBuffer():void{
            var objData:OBJParser = objList[0];
            
            var vertices:Vector.<Number> = objData.rawVertexBuffer;
            var normals:Vector.<Number> = objData.rawNormalBuffer;
            var vertices2:Vector.<Number> = objList[1].rawVertexBuffer;
            var normals2:Vector.<Number> = objList[1].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);
            
            vertexbuffer2= context3D.createVertexBuffer(vertexLength, 3);
            vertexbuffer2.uploadFromVector(vertices2, 0, vertexLength);
            
            normalbuffer = context3D.createVertexBuffer(normalLength,3);
            normalbuffer.uploadFromVector(normals, 0, normalLength);
            
            normalbuffer2 = context3D.createVertexBuffer(normalLength,3);
            normalbuffer2.uploadFromVector(normals2, 0, normalLength);
            
            indexBuffer = context3D.createIndexBuffer(indexLength);            
            indexBuffer.uploadFromVector (objData.rawIndexBuffer, 0, indexLength);
            polyCount = int(objData.rawIndexBuffer.length/3);

            context3D.setVertexBufferAt(0, vertexbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
            //context3D.setVertexBufferAt(2, vertexbuffer, 3, Context3DVertexBufferFormat.FLOAT_2);
            context3D.setVertexBufferAt(1, normalbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
            // va2,va3にトランスフォーム後の頂点・法線情報をセット
            context3D.setVertexBufferAt(2, vertexbuffer2, 0, Context3DVertexBufferFormat.FLOAT_3);
            context3D.setVertexBufferAt(3, normalbuffer2, 0, Context3DVertexBufferFormat.FLOAT_3);
            
        }
        private function onRender(e:Event):void{
            if ( !context3D ) return;
            
            context3D.clear ( 1, 1, 1, 1 );
            

            modelMatrix.identity()
            if(_isPressLeft){
                camera.rotateY(5);
            }else if(_isPressRight){
                camera.rotateY(-5);
            }
            //modelMatrix.appendRotation(getTimer()/10,Vector3D.Y_AXIS);
            
            constMatrix.identity();
            constMatrix.append(modelMatrix);
            constMatrix.append(camera.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]));
            //vc10:カメラ座標
            context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX,10,Vector.<Number>([camera.from.x, camera.from.y, camera.from.z, camera.from.w]));
            //vc11:ブレンド比率
            var v:Number = (Math.cos(getTimer()/500) +1)/2;
            context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX,11,Vector.<Number>([v, 1-v, 1, 1]));
            
            
            /* フラグメントプログラムで使用する定数 */
            //なっしん
            
            
            //三角ポリゴン描画
            
            var posList:Array = this.objList[0].mtlPosList;
            var polyList:Array = this.objList[0].mtlPolyList;
            var colorList:Array = this.objList[0].mtlColorList;

            for(var i:int=0;i<posList.length;i++){
                var color:Vector3D = colorList[i];
                context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX,12,Vector.<Number>([color.x,color.y,color.z,1]));
                context3D.drawTriangles(indexBuffer,posList[i],polyList[i]);
            }
            context3D.present();
        }
    }
}

import flash.geom.Matrix3D;
import flash.geom.Vector3D;
/*
なんちゃってカメラ
*/
class Camera {
    private var _view:Matrix3D;
    private var _from:Vector3D;
    private var _at:Vector3D;
    private var _up:Vector3D;
    
    private var _degree:Number = 0;
    private const n:Number = Math.PI/180;
    
    public function Camera() {  
        _view = new Matrix3D();
        _from = new Vector3D();
        _at = new Vector3D();
        _up = new Vector3D();
    }
    public function lookAt( from:Vector3D, at:Vector3D, up:Vector3D ) : void {
        _from.x=from.x;_from.y=from.y;_from.z=from.z;
        _at.x=at.x;_at.y=at.y;_at.z=at.z;
        _up.x=up.x;_up.y=up.y;_up.z=up.z;
        
        
        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 rotateY(deg:Number):void{
        _degree += deg;
        _from.x = Math.sin(_degree*n)*8;
        _from.z = Math.cos(_degree*n)*8;
        lookAt( _from, _at, _up ) 
    }
    public function get matrix():Matrix3D {
        return _view;
    }
    public function get from():Vector3D{
        return _from;
    }
}

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を読み込んでみて、頂点・法線・インデックス・UVをパースするクラス
*/
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 UV:String = "vt";
    private const NORMAL:String = "vn";
    private const INDEX_DATA:String = "f";
    private const MATERIAL:String = "usemtl";

    private var _loader:URLLoader;
    private var _color:uint;
        
    private var _vertexTemp:Array;
    private var _normalTemp:Array;
    private var _indexTemp:Array;

    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 mtlPosList:Array = new Array();
    public var mtlPolyList:Array = new Array();
    public var mtlColorList:Array =  [new Vector3D(0.80000,0.80000,0.80000),new Vector3D(0.58039,0.73725,0.42039),new Vector3D(0.76178,0.67568,0.30832),new Vector3D(0.2,0.2,0.2),new Vector3D(0.80000,0.48000,0.29200)] //new Array();
    
    private var _indexCount:int=0;
    private var _polyCount:int=0;
        
    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]);
        }
        mtlPolyList.push(_polyCount);
        mtlPolyList.shift();
        
        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;
        
        var v:int=3;
        
        for(var i:int=0;i<this._indexTemp.length;i++){
            var poly1:Array = _indexTemp[i][0];
            var poly2:Array = _indexTemp[i][1];
            var poly3:Array = _indexTemp[i][2];
                
            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);
        }
    }

    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;
            case MATERIAL :
                parseMaterial(data);
                break;
        }
    }
    private function parseMaterial(data:Array):void{
        mtlPosList.push(_indexCount);
        mtlPolyList.push(_polyCount);
        _polyCount=0;
    }
    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++){
                v.push(Number(element[j])-1)
            }
            poly.push(v);
        }
        _indexTemp.push(poly);
        _indexCount+=3;
        _polyCount++;
    }

    public function dispose():void{
        _vertexTemp = _normalTemp = _indexTemp = null;
        rawVertexBuffer = rawNormalBuffer= null;
        rawIndexBuffer = null;
    }
}