[Flash] Preloading Collada’s textures with Away3D
Well this post has been delayed for such a long time... First, six months ago I moved to Montreal which it is one the greatest thing I've done! But unfortunately just 2 months after, my health went really bad and I had to come back in France for 2 months and half (absolute need of family support)... Patiently took care of me, can't do something else...
Well now I'm back to Montreal, better than ever! Well almost
So it's time to a new blog post
So now if you wanted to know how to add a custom preload to your Collada's textures, you have found a solution here! By default the Collada's parser of Away3d autoload textures that your model need. Which is great, it's an easy way to quickly display your model. But now let see how to preload them and more change material declaration. (Away3d version used: 3.6.0)
-> View the example <-
Example source code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | /* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * <nomatter.me@gmail.com> wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return Nicolas Schiro * ---------------------------------------------------------------------------- */ package { import away3d.cameras.Camera3D; import away3d.cameras.TargetCamera3D; import away3d.cameras.lenses.PerspectiveLens; import away3d.containers.ObjectContainer3D; import away3d.containers.View3D; import away3d.core.base.Mesh; import away3d.core.render.Renderer; import away3d.lights.DirectionalLight3D; import away3d.lights.PointLight3D; import away3d.loaders.Collada; import away3d.loaders.data.MaterialData; import away3d.loaders.utils.MaterialLibrary; import away3d.materials.BitmapMaterial; import away3d.materials.ColorMaterial; import away3d.materials.ShadingColorMaterial; import away3d.materials.WhiteShadingBitmapMaterial; import away3d.primitives.Sphere; import br.com.stimuli.loading.BulkLoader; import br.com.stimuli.loading.BulkProgressEvent; import eu.nomatter.away3d.utils.ColladaContentUtils; import eu.nomatter.collada.Cinema4D; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.geom.Vector3D; import flash.net.URLLoader; import flash.net.URLRequest; import flash.utils.Dictionary; [SWF(width='1000', height='624', backgroundColor='#dedede', frameRate='30')] public class SampleColladaContentUtils extends Sprite { private var colladaLoader : URLLoader; private var collada : XML; private var progressTexturesBar : ProgressTexturesBar; private var colladaContentUtils : ColladaContentUtils; private var urlsTextures : Vector.<String> private var texturesLoader : BulkLoader; private var view : View3D; private var model : ObjectContainer3D; public function SampleColladaContentUtils() { // Load Collada this.colladaLoader = new URLLoader(); this.colladaLoader.addEventListener(Event.COMPLETE, this.completeColladaLoading ); this.colladaLoader.load( new URLRequest( "assets/nomatter_bake.dae" ) ); } private function completeColladaLoading( event : Event ) : void { // Get Collada this.collada = XML( this.colladaLoader.data ); this.colladaLoader.removeEventListener(Event.COMPLETE, this.completeColladaLoading ); this.colladaLoader = null; this.colladaContentUtils = new ColladaContentUtils(); this.urlsTextures = this.colladaContentUtils.getTextures( collada ); // ProgressBar this.progressTexturesBar = new ProgressTexturesBar(); this.progressTexturesBar.addEventListener(Event.COMPLETE, this.texturesComplete ); this.addChild( this.progressTexturesBar ); // Load textures this.texturesLoader = new BulkLoader( "TEXTURES_LOADER" ); for each( var url : String in urlsTextures ) { this.texturesLoader.add( "assets/"+url, {id:url} ); } this.texturesLoader.addEventListener( BulkProgressEvent.PROGRESS, this.texturesProgress ); this.texturesLoader.start( 3 ); } private function texturesProgress( event : BulkProgressEvent ) : void { this.progressTexturesBar.progress( event.percentLoaded ); } private function texturesComplete( event : Event ) : void { // Remove progressBar this.progressTexturesBar.removeEventListener( Event.COMPLETE, this.texturesComplete ); this.removeChild( this.progressTexturesBar ); this.progressTexturesBar = null; // get Texture var textures : Dictionary = new Dictionary( true ); for each( var id:String in urlsTextures ) { textures[ id ] = this.texturesLoader.getBitmapData( id, false ); } // Get the 3D model this.model = Collada.parse( this.collada, {autoLoadTextures:false} ); // Here it is! Add materials var ml : MaterialLibrary = this.model.materialLibrary; var m : MaterialData; var bitmap : BitmapData; for each( m in ml ) { bitmap = textures[ m.textureFileName ]; if( m.textureFileName == "floor.jpg" ) { m.material = new BitmapMaterial( bitmap ); } else { m.material = new WhiteShadingBitmapMaterial( bitmap, {smooth:true} ); } } // Recover cameras var cameras : Dictionary = this.colladaContentUtils.getCameras( this.collada ); var camera : Camera3D = cameras["cam"] as Camera3D; camera.lens = new PerspectiveLens(); camera.moveBackward( 1000 ); // View 3D this.view = new View3D( {x:this.stage.stageWidth/2, y:this.stage.stageHeight/2, camera:camera, renderer:Renderer.CORRECT_Z_ORDER } ); this.view.scene.addChild( this.model ); this.addChild( this.view ); var light : DirectionalLight3D = new DirectionalLight3D( {direction:new Vector3D(500,-300,200) } ); this.view.scene.addLight( light ); // Clear loader this.texturesLoader.clear(); this.texturesLoader = null; // Render textures = null; this.addEventListener( Event.ENTER_FRAME, this.render ); } private function render( event : Event ) : void { this.model.rotationY++; this.view.render(); } } } |
I've simply written a class that parse the collada's data and return all urls textures.
This class can get camera's as well (just Camera3D no TargetCamera3D)
ColladaContentUtils.as source code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | /* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * <nomatter.me@gmail.com> wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return Nicolas Schiro * ---------------------------------------------------------------------------- */ package eu.nomatter.away3d.utils { import away3d.cameras.Camera3D; import away3d.core.base.Object3D; import flash.display.*; import flash.events.Event; import flash.events.ProgressEvent; import flash.geom.Matrix3D; import flash.geom.Vector3D; import flash.net.URLLoader; import flash.net.URLRequest; import flash.utils.Dictionary; public class ColladaContentUtils { private static var numLoader:int = -1; private var texturesId:Dictionary; public function ColladaContentUtils() { this.texturesId = new Dictionary(); } public function getTextures( collada : XML ) : Vector.<String> { var colladaNoNamespace : XML = new XML( collada.toXMLString().replace(/\s+xmlns(:[^=]+)?="[^"]*"/g, "") ); var ids : Vector.<String> = new Vector.<String>(); var url:String; for each( var image:XML in colladaNoNamespace.library_images.image ) { url = image.init_from.toString(); if( Boolean( url ) ) { ids.push( url ); } } return ids; } // Camera Utils public function getCameras( collada : XML ) : Dictionary { var colladaNoNamespace : XML = new XML( collada.toXMLString().replace(/\s+xmlns(:[^=]+)?="[^"]*"/g, "") ); var cameras : Dictionary = new Dictionary; var camera:Camera3D; var id:String; var name:String; for each( var cameraXML:XML in colladaNoNamespace.library_cameras.camera ) { id = cameraXML.@id.toString(); name = cameraXML.@name.toString(); camera = new Camera3D(); camera.name = name; camera.transform = this.getCameraTransform( id, colladaNoNamespace ); cameras[ name ] = camera; } return cameras; } private function getCameraTransform( id:String, colladaNoNamespace : XML ) : Matrix3D { for each( var node:XML in colladaNoNamespace.library_visual_scenes.visual_scene.node ) { var result:XML = this.matchCameraId( node, id ); if( Boolean( result ) ) { var translate:Array = result.translate.toString().split( " " ); var rotationX:Number = Number( result.rotate.( @sid == "rotateX" ).toString().split( " " )[ 3 ] ); var rotationY:Number = Number( result.rotate.( @sid == "rotateY" ).toString().split( " " )[ 3 ] ); var rotationZ:Number = Number( result.rotate.( @sid == "rotateZ" ).toString().split( " " )[ 3 ] ); var object:Object3D = new Object3D(); object.rotateTo( rotationX, -rotationY+180, rotationZ ); object.position = new Vector3D( -translate[ 0 ], translate[ 1 ], translate[ 2 ] ); return object.transform; } } return null; } private function matchCameraId( rootNode:XML, id:String ) : XML { var idCamera:String = rootNode.instance_camera.@url.toString().split( "#" )[ 1 ]; if( Boolean( idCamera ) ) { if( id == idCamera ) { return rootNode; } } else if( rootNode.node.length() > 0 ) { for each( var node:XML in rootNode.node ) { var returnNode:XML = this.matchCameraId( node, id ); if( Boolean( returnNode ) ) { return returnNode; } } } return null; } } } |
Download ColladaContentUtils
Download Preloading Collada's Texture project
In a few month "MoleHill" will be released in the FP11 and this will be certainly totally obsolete!