Wavefront OBJをPaperVision3Dで表示

Wavefront OBJをPaperVision3Dで表示してみました。
どうにもググってもそれっぽい情報がなくてしかたなく自作してみました。
こんな感じ
http://moeten.info/flex/20081016_fp10Test2/bin-release/test20.html

複数のobjファイルには対応してません。テクスチャが変です。
細かいことは気にしないでください(+_+)
Flashで3Dデーターの簡単なビューアーができるといいね。
参考リンク

ソースはこちら

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="absolute" creationComplete="init3D()"
    backgroundGradientColors="[0xffffff,0xcccccc]"
    width="800" height="800"
    >
<mx:Script>
<![CDATA[
//PaperVision3D
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.render.QuadrantRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.core.geom.renderables.Triangle3D;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.geom.TriangleMesh3D;
import org.papervision3d.core.geom.Lines3D;
import org.papervision3d.core.geom.renderables.Line3D;
import org.papervision3d.core.utils.MeshUtil;
import org.papervision3d.core.math.NumberUV;
import org.papervision3d.core.proto.MaterialObject3D;
import org.papervision3d.materials.special.LineMaterial;
import org.papervision3d.materials.BitmapFileMaterial;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.BitmapMaterial;
//BMPDecoder
import com.voidelement.images.BMPDecoder;
//
private var scene    : Scene3D;
private var viewport : Viewport3D;
private var renderer : BasicRenderEngine;
private var camera   : Camera3D;
private var cameraTarget : DisplayObject3D;
private var bd:BitmapData;
//初期化
private function init3D():void{
    //pv3d
    setupScene();
    setupCamera();
    setupListeners();
    setupLine();
    cBox.selectedIndex = 0;
    //load obj
    setTexture();
}
//シーンの作成
private function setupScene():void{
    viewport = new Viewport3D( myUI.width , myUI.height , true , false , true , true );
    myUI.addChildAt(viewport , 0);
    renderer = new BasicRenderEngine();
//    renderer = new QuadrantRenderEngine();
    scene    = new Scene3D();
}
//カメラ設定
private function setupCamera():void{
    cameraTarget = new DisplayObject3D();
    camera   = new Camera3D();
    camera.z = - 100;
    camera.y = 10;
}
//イベントリスナー設定
private function setupListeners():void{
    addEventListener(Event.ENTER_FRAME, onRenderTick);
    addEventListener(Event.RESIZE, onResize);
    this.addEventListener(MouseEvent.MOUSE_WHEEL , onWheel );
}
//マウスホイール
private function onWheel(e:MouseEvent):void{
    distance.value -= e.delta;
}
//xyz作成
private function setupLine():void{
    var lines:Lines3D = new Lines3D();
    var size:int = 50;
    lines.addLine( new Line3D( lines , new LineMaterial(0xff0000,1) , 1 , new Vertex3D(0,0,-size),new Vertex3D( 0,0,size ) ) );
    lines.addLine( new Line3D( lines , new LineMaterial(0x00ff00,1) , 1 , new Vertex3D(0,-size,0),new Vertex3D(0,size,0 ) ) );
    lines.addLine( new Line3D( lines , new LineMaterial(0x0000ff,1) , 1 , new Vertex3D(-size,0,0),new Vertex3D(size,0,0 ) ) );
    scene.addChild( lines );
}
//Load Texture FIle
private function setTexture():void{
    var textureFile:String = cBox.selectedItem.texture;
    txtNameT.text = textureFile;
    // texture file is BMP ? or JPG,PNG,GIF
    if( textureFile.split(".")[1]=="bmp"){
        //BMP
        var loader:URLLoader = new URLLoader();
        loader.dataFormat = URLLoaderDataFormat.BINARY;
        loader.addEventListener(Event.COMPLETE, function(event:Event):void {
            var bmpLoader:URLLoader = event.target as URLLoader;
            var decoder:BMPDecoder = new BMPDecoder();
            bd = decoder.decode(bmpLoader.data);
            //show Image
            myImage.source = new Bitmap(bd);
            //make obj
            setMesh();
            txtFilesizeT.text = "" + loader.bytesTotal + " bytes";
            txtWHsizeT.text = "" + bd.width + "x" + bd.height;
        });
        loader.load(new URLRequest(textureFile));
    }else{
        //JPG,PNG,GIF
        var loader2:Loader = new Loader();
        loader2.contentLoaderInfo.addEventListener(Event.COMPLETE,function():void{
            bd = Bitmap(loader2.content).bitmapData;
            //show Image
            myImage.source = new Bitmap( bd );
            //make obj
            setMesh();
            txtFilesizeT.text = "" + loader2.contentLoaderInfo.bytesTotal + " bytes";
            txtWHsizeT.text = "" + bd.width + "x" + bd.height;
        });
        loader2.load(new URLRequest(textureFile));
    }
}
//make obj
private function setMesh():void{
    var objFile:String = cBox.selectedItem.object;
    var loader:URLLoader = new URLLoader();
    scene.removeChildByName("myObject");
    loader.addEventListener(Event.COMPLETE , function():void{
        // file to array
        var line:Array = String(loader.data).split("\n");
        var len = line.length;
        var lineArr:Array = new Array();
        var vArr:Array    = new Array();
        var vtArr:Array   = new Array();
        var fArr:Array    = new Array();
        for( var i:int = 0 ; i < len ; i ++ ){
            // split to v , vt , f
            lineArr = String(line[i]).split(" ");
            if( lineArr[0] == "v" ){
                vArr.push( new Array( lineArr[1],lineArr[2],lineArr[3] ) );
            }else if( lineArr[0] == "vt" ){
                vtArr.push( new Array( Number(lineArr[1]),Number(lineArr[2]) ) );
            }else if( lineArr[0] == "f" ){
                if( lineArr.length == 4 ){
                    fArr.push( new Array( lineArr[1],lineArr[2],lineArr[3] ) );
                }else{
                    fArr.push( new Array( lineArr[1],lineArr[2],lineArr[3],lineArr[4] ) );
                }
            }
        }
        txtVertexO.text   = "" + vArr.length;
        txtMeshO.text     = "" + fArr.length;
        txtTextureO.text  = "" + vtArr.length;
        txtNameO.text     = objFile;
        txtLineO.text     = "" + line.length;
        txtFilesizeO.text = "" + loader.bytesTotal + " bytes";
        //make TriagnleMesh
        var mesh:TriangleMesh3D = new TriangleMesh3D( null , new Array(), new Array(), null );
        len = fArr.length;
        //texture
        var mat:BitmapMaterial = new BitmapMaterial( bd );
        mat.doubleSided = true;
        for( i = 0 ; i < len ; i ++ ){
            var len2:int = fArr[i].length;
            var vertex3DArr:Array = new Array();
            var texture3DArr:Array = new Array();
            for( var j:int = 0 ; j < len2 ; j ++ ){
                //face triangle
                var index:int = String( fArr[i][j]).split("/")[0] - 1;
                var vertex3D:Vertex3D = new Vertex3D( vArr[index][0] , vArr[index][1] , vArr[index][2] );
                mesh.geometry.vertices.push( vertex3D );
                vertex3DArr[j]  = vertex3D;
                //texture uv
                var index2:int = String( fArr[i][j]).split("/")[1] - 1;
                texture3DArr[j] =     new NumberUV( vtArr[index2][0] ,  1-vtArr[index2][1] );
            }
            // make Triangle
            mesh.geometry.faces.push( new Triangle3D( mesh,
                                                        new Array( vertex3DArr[0], vertex3DArr[1], vertex3DArr[2]),
                                                        mat,
                                                        new Array( texture3DArr[0] ,  texture3DArr[1] ,  texture3DArr[2] )
                                    ));
            // if vertex is 4. add triangle
            if( len2 == 4 ){
                mesh.geometry.faces.push( new Triangle3D( mesh,
                                                            new Array(  vertex3DArr[3], vertex3DArr[0], vertex3DArr[2]),
                                                            mat,
                                                            new Array( texture3DArr[3] ,  texture3DArr[0] ,  texture3DArr[2] )
                                        ));
            }
        }
        mesh.geometry.ready = true;
        scene.addChild(mesh , "myObject");
    });
    loader.load(new URLRequest(objFile));
}
//レンダリング+マウス操作
protected function onRenderTick(e:Event):void {
    var reach:Number = 0.01;
    var ease:Number = 0.1;
    var cameraDistance:Number = distance.value;
    camera.x += (Math.sin(mouseX * reach) *   cameraDistance - camera.x) * ease;
    camera.z += (Math.cos(mouseX * reach) * - cameraDistance - camera.z) * ease;
    camera.y += (Math.sin(mouseY * reach) *   cameraDistance - camera.y) * ease;
    camera.lookAt(cameraTarget);
    renderer.renderScene(scene, camera, viewport);
}
//リサイズイベント
private function onResize(e : Event) : void {
}
]]>
</mx:Script>
<mx:Style>
.myTitle{
    backgroundColor:#D9D9D9;
    paddingLeft:5px;
}
.myTitle2{
    color:#ffffff;
    backgroundColor:#333333;
}
GridItem{
    borderColor:#000000;
    borderStyle:solid;
    borderThickness:1;
}
</mx:Style>
<mx:UIComponent id="myUI" width="100%" height="100%" />
<mx:HBox width="100%" height="100%"  paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10">
    <mx:VBox>
        <mx:ComboBox id="cBox" change="setTexture()" labelField="object" prompt="オブジェクトリスト" selectedIndex="0">
            <mx:dataProvider>
                <mx:Array>
                    <mx:Object object="assets/obj/haruhi_0.obj" texture="assets/obj/haruhi_texture.bmp" />
                    <mx:Object object="assets/obj/nyaunPage.obj" texture="assets/obj/txTPCover.jpg" />
                </mx:Array>
            </mx:dataProvider>
        </mx:ComboBox>
        <mx:HBox>
        <mx:Grid width="100%" horizontalGap="0" verticalGap="0">
            <mx:GridRow width="100%" height="100%">
                <mx:GridItem width="100%" height="100%" styleName="myTitle2">
                    <mx:Label text="オブジェクト"/>
                </mx:GridItem>
                <mx:GridItem width="100%" height="100%" styleName="myTitle2">
                </mx:GridItem>
            </mx:GridRow>
            <mx:GridRow width="100%" height="100%">
                <mx:GridItem width="100%" height="100%" styleName="myTitle">
                    <mx:Label text="ファイル名"/>
                </mx:GridItem>
                <mx:GridItem width="100%" height="100%">
                    <mx:Label id="txtNameO"/>
                </mx:GridItem>
            </mx:GridRow>
            <mx:GridRow width="100%" height="100%">
                <mx:GridItem width="100%" height="100%" styleName="myTitle">
                    <mx:Label text="容量"/>
                </mx:GridItem>
                <mx:GridItem width="100%" height="100%">
                    <mx:Label id="txtFilesizeO"/>
                </mx:GridItem>
            </mx:GridRow>
            <mx:GridRow width="100%" height="100%">
                <mx:GridItem width="100%" height="100%" styleName="myTitle">
                    <mx:Label text="頂点数"/>
                </mx:GridItem>
                <mx:GridItem width="100%" height="100%">
                    <mx:Label id="txtVertexO"/>
                </mx:GridItem>
            </mx:GridRow>
            <mx:GridRow width="100%" height="100%">
                <mx:GridItem width="100%" height="100%" styleName="myTitle">
                    <mx:Label text="テクスチャ数"/>
                </mx:GridItem>
                <mx:GridItem width="100%" height="100%">
                    <mx:Label id="txtTextureO"/>
                </mx:GridItem>
            </mx:GridRow>
            <mx:GridRow width="100%" height="100%">
                <mx:GridItem width="100%" height="100%" styleName="myTitle">
                    <mx:Label text="面数"/>
                </mx:GridItem>
                <mx:GridItem width="100%" height="100%">
                    <mx:Label id="txtMeshO"/>
                </mx:GridItem>
            </mx:GridRow>
            <mx:GridRow width="100%" height="100%">
                <mx:GridItem width="100%" height="100%" styleName="myTitle">
                    <mx:Label text="行数"/>
                </mx:GridItem>
                <mx:GridItem width="100%" height="100%">
                    <mx:Label id="txtLineO"/>
                </mx:GridItem>
            </mx:GridRow>
            <mx:GridRow width="100%" height="100%">
                <mx:GridItem width="100%" height="100%" styleName="myTitle2">
                    <mx:Label text="テクスチャ"/>
                </mx:GridItem>
                <mx:GridItem width="100%" height="100%" styleName="myTitle2">
                </mx:GridItem>
            </mx:GridRow>
            <mx:GridRow width="100%" height="100%">
                <mx:GridItem width="100%" height="100%" styleName="myTitle">
                    <mx:Label text="ファイル名"/>
                </mx:GridItem>
                <mx:GridItem width="100%" height="100%">
                    <mx:Label id="txtNameT"/>
                </mx:GridItem>
            </mx:GridRow>
            <mx:GridRow width="100%" height="100%">
                <mx:GridItem width="100%" height="100%" styleName="myTitle">
                    <mx:Label text="容量"/>
                </mx:GridItem>
                <mx:GridItem width="100%" height="100%">
                    <mx:Label id="txtFilesizeT"/>
                </mx:GridItem>
            </mx:GridRow>
            <mx:GridRow width="100%" height="100%">
                <mx:GridItem width="100%" height="100%" styleName="myTitle">
                    <mx:Label text="サイズ"/>
                </mx:GridItem>
                <mx:GridItem width="100%" height="100%">
                    <mx:Label id="txtWHsizeT"/>
                </mx:GridItem>
            </mx:GridRow>
        </mx:Grid>
        <mx:Image id="myImage" width="200" height="200"/>
        </mx:HBox>
    </mx:VBox>
</mx:HBox>
<mx:VSlider id="distance" value="100" minimum="0" maximum="1000" height="500" width="20" right="10" toolTip="10"/>
</mx:Application>