Wavefront OBJをPaperVision3Dで表示
Wavefront OBJをPaperVision3Dで表示してみました。
どうにもググってもそれっぽい情報がなくてしかたなく自作してみました。
こんな感じ
http://moeten.info/flex/20081016_fp10Test2/bin-release/test20.html
複数のobjファイルには対応してません。テクスチャが変です。
細かいことは気にしないでください(+_+)
Flashで3Dデーターの簡単なビューアーができるといいね。
参考リンク
- libwave - Wavefront/GL rendering library
- geometry.facesn.uv
- 3December
- PV3DのQuadTreeを試してみました
- 江ノ電…のようなものをダウンロード可能にしました。
- Wavefront OBJについて
ソースはこちら
<?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>