nomatter
15mai/110

[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!

Remplis sous: AS3, Away3d Aucun commentaire