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!