Hi everyone,

I recently updated to the latest revisions of Away3D, and I lost the ability to set an object's material at runtime.

This may or may not be obvious to others, but I wanted to share how this works in the latest versions. Many of the examples I've seen are either for loading a mesh (Collada, 3DS, BSP, etc) and relying on Away3D's built in loader for textures, or they use an Away3D primitive (Cube, Plane, Sphere, etc) and set the material property. Personally, I prefer to either load textures myself, or embed them in my classes (the Embed meta tag is blocked in Flash Professional, but should work with FlashDevelop or Flash Builder). Either way, I like to apply textures at runtime myself.

Doing this before was pretty simple. It looked like this:


var object:Object3D = Collada.parse (Mesh, { material: Texture } );


If Mesh and Texture were classes, containing embedded geometry and bitmap data, Away3D would put them together automatically. Of course, if you wanted to use a different material, or customize it a bit more, you could also pass your own material, like these examples:


var object:Object3D = Collada.parse (Mesh, { material: new BitmapMaterial (Cast.bitmap (Texture), { smooth: true } ) } );

var object:Object3D = Collada.parse (Mesh, { material: new WireColorMaterial () } );



However, in the latest versions of Away3D, this no longer works. It will ignore the material property entirely, loading either the default flat texture, or using the built-in loader to try and download and display an image texture. That doesn't work for me, so I went looking around for how I could (again) merge my meshes and textures like I wanted. Here's how:


var parser:Collada = new Collada ( { material: new WireColorMaterial () } );
var object:Object3D = parser.parseGeometry (Mesh);


That will override all the materials defined in the Collada, and replace it with a new material. If you need more control over the process, you can also do something like this:


var parser:Collada = new Collada ();
var object:Object3D = parser.parseGeometry (Mesh);

object.materialLibrary.getMaterial ("lambert1").material = new WireColorMaterial ();

for each (var materialData:MaterialData in object.materialLibrary) {
        
        if (materialData.name == "lambert1") {
                
                materialData.material = new WireColorMaterial (0xFF0000);
                
        } else {
                
                materialData.material = new WireColorMaterial (0x00FF00);
                
        }
        
}



One of the things I like most about setting either a single material at runtime, or iterating through the material library is that you don't need to remember the names of all your materials. If you have five models which need the same material, you don't need to remember if one was named "lambert1" and the other was named "lambert2".

All in all, I like this way of parsing better than how I did it before. This feels closer to Away3DLite, and it makes it easy to swap out the parser. Since my old approach used the public static method to parse, it meant that I needed to know beforehand which format the mesh was in. However, with the new approach, I could easily create a loader that supports multiple model formats, like this:


public function loadObject (mesh:Class, material:Material, parser:Class):Object3D {
        
        return new parser ( { material: material } ).parseGeometry (mesh);
        
}



So that's that! I know I was a little stuck figuring out how to do this, both the first time, and the second time. I hope this helps someone!

Reply via email to