Models and Animations

It is possible to create a 3D object from the ground up using basic elements like vertices, triangle faces, Sprite3D objects, and segments. However, creating each element manually in code is not practical for more complex models. While the classes from the away3d.primitives package offer a solution by providing a way to quickly create some standard shapes, advanced applications will need to display more complex shapes. For those situations where these standard primitive shapes do not provide enough fexibility, Away3D can load and display 3D models created by external 3D modeling applications.

3D modeling applications are specifcally designed to provide a visual environment in which 3D models can be manipulated. It is certainly much more convenient to create or edit a 3D mesh in one of these applications than it is to build up a mesh in code using ActionScript.

Away3D can directly load a wide range of 3D formats. The process of exporting a 3D mesh into a fle that can be used with Away3D will be covered for the following 3D modeling applications:

3ds Max: A popular commercial modeling, animation, and rendering application which runs on Windows.

Blender: A free and open source modeling application, which is available on a number of platforms, including Windows, Linux, and MacOS.

Milkshape: A commercial low-polygon modeler which runs on Windows that was originally designed for the game Half-Life.

Sketch-up: A free 3D modeling application provided by Google. A commercial version is also available that includes a number of additional features. Sketch-up runs on Windows and MacOS.

Actually creating a model in these 3D modeling applications is outside the scope of this article. However, 3D models are provided that can be loaded and then exported from these applications, which will allow you run through the procedure without having to know how to make a 3D model from scratch.

3D formats supported by Away3D

Away3D includes classes that can load a wide range of 3D model fle formats. All the supported formats can be used to load a static 3D model, while a smaller number can be used to load animated models. The following table lists the 3D model formats supported by Away3D, their common extensions, whether they can load animated 3D models, and the Away3D class that is used to load and parse them.

Exporting 3D models

The following instructions show you how to export a Collada fle from a number of different 3D modeling applications. Collada is an open, XML-based format that has been designed to provide a way to exchange data between 3D applications. Away3D supports loading both static and animated 3D models from the Collada format.

Exporting from 3ds Max

3ds Max is a commercial 3D modeling application. At the time of writing, the latest version of the ColladaMax plugin, which is the plugin that we will use to export the 3D model, was 3.05C. This version supports 3ds Max 2008, 3ds Max 9, 3ds Max 8 SP3, or 3ds Max 7 SP1. Note that this version does not support 3ds Max 2010 or 2011.

A trial version of 3ds Max 9 is available, although it can be diffcult to fnd. You should be able to fnd a copy if you search the Internet for Autodesk3dsMax2009_ENU_TrialDownload.exe, which is the name of fle that will install the trial version of 3ds Max 9.

Click File | Open. Select the MAX file you wish to open and click on the Open button.

Click File | Export from within 3ds Max.

Select COLLADA (*.DAE) from the Save as type drop-down list.

Select the same directory where the original MAX fle was located.

Type a fle name for the exported fle in the File name textbox, and click on the Save button.

In the ColladaMax Export dialog box make sure the following checkboxes are enabled:

Relative Paths

Normals

Triangulate

If you want to export animations, enable the Enable export checkbox.

If you want to export a specifc range of frames, enable the Sample animation checkbox and enter the required values in the Start and End textboxes.

Click on the OK button to export the fle.

Exporting from MilkShape

The Collada exporter supplied with MilkShape does not export animations. So even if the MilkShape MS3D file we are loading contains an animated model, the exported Collada DAE file will be a static mesh. A trial version of MilkShape can be downloaded and installed from its website at http://chumbalum.swissquake.ch/.

Click File | Open. Select the MS3D file you wish to open and click on the Open button.

Click File | Export | COLLADA….

Select the same directory where the original MS3D file was located.

Type a flename for the exported fle in the File name textbox and click the Save button.

Exporting from Sketch-Up

Like Milkshape, Sketch-up does not support exporting animated Collada fles. Sketch-Up can be downloaded for free from http://sketchup.google.com/.

Click File | Open. Select the SKP file you wish to open and click on the Open button.

Click File | Export | 3D Model….

Select Collada File (*.dae) from the Export type combobox.

Select an appropriate directory, and type a filename for the exported file in the File name textbox.

Click on the Options... button.

Make sure the Triangulate All Faces checkbox is enabled.

If the Export Texture Maps option is enabled, Sketch-Up will export the textures along with the DAE file.

Click on the OK button to save the options.

Click on the Export button to export the file.

Exporting from Blender

The latest version of the Collada exporter for Blender, which is version 0.3.162 at the time of writing, does support exporting animations. However, in most cases Away3D will not load these animations correctly. It is recommended that only static meshes be exported from Blender to a Collada fle.

Click File | Open.... Select the BLEND file you wish to open and click on the Open button.

Click File | Export | COLLADA1.4 (*.dae) ....

Type a flename for the exported fle in the directory where the original BLEND fle was located in the Export File textbox.

Make sure the Triangles and Use Relative Paths buttons are pressed.

Click on the Export and Close button.

A note about the Collada exporters

Despite being free and open standard, exporting to a Collada fle that can be correctly parsed by Away3D can be a hit-and-miss affair. The Collada exporters for 3ds Max are a good example. During testing, neither the built-in Collada exporter included with 3ds Max, nor the third-party OpenCollada exporter from http://opencollada.org (version 1.2.5 was the latest version at the time of writing) would export an animated Collada fle that Away3D could read. At best Away3D would display a static mesh, and at worst it would throw an exception when reading the DAE fle. Likewise, neither of the Collada exporters that come with Blender (which was at version 2.49b at the time of writing) would consistently export an animated Collada mesh that was compatible with Away3D.

It is important to be aware that just because a 3D modeling application says that it can export to a Collada fle, this is no guarantee that the resulting fle can be read correctly by Away3D.

Use the load() function from the respective model loading class to create a Loader3D object

Add the Loader3D object to the scene

Assign a function to respond to the Loader3DEvent.LOAD_SUCCESS event.

Manually apply a material if needed

Play the desired animation for those models that support animations

Animated models

The Collada DAE, Quake 2 MD2, and ActionScript AS model formats are unique in that they can be used to load animated 3D objects. But there are a number of subtle differences between the classes used to load and animate each of these formats, especially with the option of embedding the resources or loading them from external files.

MD2—Loading an embedded file

MD2 is the model format used by Quake 2. These models are ideal for use with Away3D because they have a low polygon count and support animations. Let's create an application called MD2EmbeddedDemo that demonstrates how a MD2 file can be embedded and loaded.

package{

The parsed 3D object will be returned to us as a Mesh.

import away3d.core.base.Mesh;

We will use the static functions provided by the Cast class to cast objects between types.

import away3d.core.utils.Cast;

The class that will load the MD2 ﬁles is called Md2.

import away3d.loaders.Md2;

We will apply a BitmapMaterial to the 3D object.

import away3d.materials.BitmapMaterial;

The AnimationData class contains the functions we will use to animate the 3D object once it is loaded.

import away3d.loaders.data.AnimationData;

MD2 models can be embedded, but because the ActionScript compiler has no understanding of the MD2 format, they need to be embedded as a raw data file (that is, with a MIME type of application/octet-stream).

By default, the textures for MD2 models are in the PCX format, which is not supported by Away3D. Here we have converted the original PCX image file to a JPG image, which is then embedded. We don't need to specify a MIME type, because the ActionScript compiler understands the format of a JPG image.

[Embed(source="ogre.jpg")] protected var MD2Material:Class;

The Mesh representing the 3D object is referenced by md2Mesh property.

protected var md2Mesh:Mesh;

The constructor calls the base Away3DTemplate class constructor, which will initialize the Away3D engine.

public function MD2EmbeddedDemo() { super(); }

The initScene() function is overridden to load the MD2 file and to add the resulting 3D object to the scene.

protected override function initScene():void { super.initScene();

First, we create a new BitmapMaterial object from the embedded image file.

The parse() function from the Md2 class is used to load an embedded MD2 file, which is converted to a ByteArray using the bytearray() function from the Cast class. The parse() function will return a Mesh object, which is then assigned to the md2Mesh property.

md2Mesh = Md2.parse(Cast.bytearray(MD2Model), {

We specify the init object parameters necessary to scale, position, and rotate the 3D object within the scene so it will be displayed nicely on the screen.

scale: 0.01, z: 100, rotationY: -90 } );

The material is then assigned to the 3D object via the material property.

Unlike the primitive 3D objects we have used previously, materials assigned via the material init object parameter will not be applied to the 3D object we are loading using the Md2 class. The section The problem with init and Init objects below explains why this is the case.

md2Mesh.material = modelMaterial;

The 3D object is added to the scene to make it visible.

scene.addChild(md2Mesh);

Mos t MD2 models define a number of animations like stand, run, attack, and jump. These animation names correspond to the actions of the characters in the game Quake 2. While these animation names are common, they are not guaranteed to be included in an MD2 model file. Before we play the desired animation, we first check to see if it is included in the loaded 3D object.

If the animationData variable is not null then the loaded 3D object includes the desired animation.

if (animationData != null)

The animation can then be played by calling the play() function.

animationData.animator.play(); }

MD2—Loading an external file

The process for loading an external MD2 file is much the same as loading an embedded one. Let's create a call called MD2ExternalDemo to load and display an external MD2 file and see how it differs from the MD2EmbeddedDemo above.

package{ import away3d.core.base.Mesh;

We need to register a function to be called when the 3D object is loaded, so we can play the initial animation. This function will take a Loader3DEvent object as a parameter.

import away3d.events.Loader3DEvent;

Instead of returning a Mesh, the Md2 class will instead return a Loader3D object, which is used as a placeholder while the 3D object is loaded.

When the Loader3D.LOAD_SUCCESS event is dispatched, the 3D object has been loaded and parsed, and is ready to be used. We will want to set the initial animation at this point, so we register the onLoadSuccess() function to be called when the event is triggered.

In the onLoadSuccess() function, we get a reference to the loaded 3D object.

mesh = event.loader.handle as Mesh;

The Md2 class does have the ability to create its own material from the texture information in the MD2 file. Since Flash has no support for the PCX format, which is the default format used by MD2 models, it will attempt to load a JPG image with the same name as the PCX file referenced in the MD2 file. The new extension can be changed from the default of JPG to another image format supported by Flash like PNG or GIF by specifying the pcxConvert init object parameter that is supplied to the Md2 load() function.

However, quite often the texture file referenced by the MD2 file is incorrect, or includes a long path like quake2/baseq2/players/modelname/texture.pcx. This unpredictability in texture filenames is best avoided by creating a new BitmapFileMaterial instance, passing the URL of the texture file to its constructor, and specifying it at the material to be used by the loaded 3D object via the material property.

Collada—Loading an embedded file

Loa ding an embedded Collada model file is quite similar to the process of loading an embedded MD2 file: the model file and the textures are embedded, and a 3D object is created using the parse() function from the model loading class (named Collada in this case).

The models in a Collada file can use a number of separate materials to achieve their final appearance. The Collada file used in this example only references one material, but the logic is still the same. We define an init object parameter called materials, and to that we assign another init object that maps Away3D materials to the material names defined in the Collada file. In this example, the single material defined in the Collada file is called monster.

{ materials: { monster: modelMaterial },

The 3D object is then rotated, so it will be displayed nicely on the screen.

rotationY: 90 } );

The scale of the 3D object is increased to make it easier to see on the screen.

Collada—Loading an external file

Loading an external Collada file is much the same as loading an embedded file. The big differences are that we don't need to manually assign any materials, and the animations are played once an event has been dispatched indicating that the model has been loaded.

package{

Loading external files is an asynchronous process, and the Loader3DEvent class is used by the function registered to the Loader3DEvent.LOAD_SUCCESS event that lets us know that the file has been loaded successfully.

import away3d.events.Loader3DEvent; import away3d.loaders.Collada;

The Loader3D class is used as a placeholder while the Collada file is being loaded.

Here we use the static load() function from the Collada class. This function takes the URL of the Collada file to be loaded (remember to add a slash to the URL, even for files in the same folder as the SWF file), and returns a Loader3D object. We don't need to worry about supplying any information about the materials to be used, as the Collada class will create the materials for us by loading the image files referenced in the DAE file.

AS—Loading a converted model

Models can also be defined in an ActionScript class. You may recall the Sea Turtle "primitive" from Chapter 2, Creating and Displaying Primitives, which was an example of a complex model that could be created by instantiating the SeaTurtle class.

The Collada DAE and Quake 2 MD2 formats were both demonstrated being loaded from external files and from an embedded resource. Because of the nature of an ActionScript class, loading it from an external file does not make sense, which is why there is only one application shown here demonstrating the use of models stored in an AS file.

For this application, we will use a class called Ogre, which has been converted from the MD2 model used in the MD2ExternalDemo and MD2EmbeddedDemo classes above. The process of creating a class like Ogre is explained in the following section Converting a loaded model to an ActionScript class.

Just like a primitive 3D object, the Ogre model is created by instantiating a standard ActionScript class. There is no need to use an intermediary class like Collada or Md2 to load or parse a file.

You will note that we have passed in the scaling init object parameter, and then set the material and position directly via the properties exposed by the Mesh class. This is because the tool that was used to create this particular AS3 class only reads the scaling init object parameter, and does not pass the init object down to the underlying Mesh class constructor. This behavior is dependent on the particular way that a modeling application exports an AS3 Away3D model class, so this is not a universal rule.

Static models

The 3DS, AWD, KMZ, ASE, or OBJ model formats can all be used to load and display static 3D objects. The following samples presented show you how to load embedded and external files from all of these formats.

3DS—Loading an embedded file

The 3DS model format has been around for over a decade, and is widely supported by 3D authoring applications and 3D engines alike. While many formats claim to offer a "universal" standard, the 3DS format can almost be thought of as a de-facto standard, thanks to its popularity.

When embedding a 3D model file it does not make sense for the Max3DS class to try and load the materials from external image files. Indeed, if the Max3DS class does try to load materials from external images that don't exist an error will be displayed in place of the 3D object that you are trying to load. You can see an example of this error in the image below.

To prevent the Max3DS class from trying to load external image files we set the autoLoadTextures init object parameter to false.

autoLoadTextures: false, z: 200 } );

The parse() function will return a ObjectContainer3D object. The children held by this ObjectContainer3D object represent the 3D objects we have loaded from the 3DS file. We loop through each child, applying the material we created from the embedded texture.

If the autoLoadTextures parameter is not set to false, you may see an error as in the following screenshot:

3DS—Loading an external file

Loading a model from an external 3DS file is very easy. We simply supply the location of the 3DS file to the Max3DS load() function, and it will load the model and any materials referenced by the 3DS file.

T he parse() function will return an Object3D object. In this case, this object is actually an instance of the ObjectContainer3D class. So we use the as statement to cast the returned Object3D object to an ObjectContainer3D object.

T he AWData class will attempt to load the materials referenced in the AWD file from external images using the BitmapFileMaterial class. There is no option that can be set to stop this behavior, which means that you may see an exception thrown if the SWF does not have the correct permissions to access the file. However this is not a big problem, as only the debug versions of the Adobe Player will display these exceptions, so the vast majority of end users will not see the warning.

You can work around this by removing any reference to external image files from the AWD file. Since the AWD format is ASCII-based format, you can open it in a regular text editor.

The following image is of the original AWD file. The text monster.jpg has been highlighted on line 7.

In this next image the text monster.jpg has been removed.

If this new AWD file, with the reference to the JPG file removed, is embedded and loaded, the AWData class will not try to load any external image files. This in turn stops an exception from being thrown.

AWD—Loading an external file.

When loading an external AWD file, we don't have to worry about the materials like we did with the embedded AWD file. We simply use the AWData class to load and apply any textures that are referenced within the AWD file.

KMZ

The KMZ format is used by Google Sketch-Up. The Kmz class from the away3d. loaders package should load KMZ files, but due to a bug in Away3D version 3.6 this class cannot be used. Referencing the Kmz class in any way will lead to the following error:

ASE—Loading an embedded file

The ASE file format is used by 3ds Max. It uses ASCII characters (unlike the binary 3DS format), meaning it is readable if opened using a regular text editor.

Working with an embedded ASE file is quite straightforward. In fact, when loading embedded model files in the other 3D model formats we need to be aware of how textures that are referenced in the file are loaded from external files by default. But with the Ase class, there are no workarounds or special init object parameters to deal with when loading an embedded model file.

The second step is to manually load the materials. The Ase class does not parse any material information from the ASE file format. To accommodate this, the onLoadSuccess() function ha s been registered through the Loader3D addOnSuccess() function to be called when the Loader3DEvent.LOAD_SUCCESS event is dispatched.

OBJ—Loading an embedded file

The OBJ file format was first developed by Wavefront Technologies for its Advanced Visualizer animation package, which has since been incorporated into the Maya 3D modeling application. It is an ASCII-based format, meaning it can be read with a regular text editor. OBJ files are usually partnered with a second MTL file that defines the materials.

Setting the useMtl init object parameter to false is important when using an embedded OBJ model file. If useMtl is set to true, which it is by default, an attempt will be made to load the MTL file that usually accompanies an OBJ model file. Attempting to load a nonexistent MTL file may result in an error being displayed within the scene (like in the following screenshot), or an exception may be thrown.

useMtl: false } ) as Mesh;

Due to the way the Obj class constructs the 3D object from the embedded OBJ file, we need to set the material that is applied to each Face in the 3D object rather than assigning a material to the Mesh material property.

The following image shows an example of the error you may see if the useMtl init object parameter is not set to false.

OBJ—Loading an external file

When loading an external OBJ file, the Obj class will attempt to load the materials defined in the MTL class with the same name as the OBJ class. Otherwise, loading an external OBJ file is quite straightforward.

The Obj class will not parse the MTL file properly if its lines are prefixed with whitespace characters like spaces or tabs. Some exporters, like the one included with 3ds Max, will add these whitespace characters to the MTL file. You can manually remove them using a regular text editor.

The problem with init and Init objects

Init objects are usually created using object literal notation. While they are related to the Init class, they are not the same thing.

Instances of the Init class maintain a reference to an init object, and provide a number of functions that can be used to easily read the properties of the init object. So, an init object (notice the lower case "i") contains a number of properties that define the initial values or settings to be applied to an object. An Init object (with the uppercase "I") is an instance of the Init class that provides a convenient way to read the properties of an init object.

So far we have not had to use the Init class directly, but understanding how it works allows us to understand some of the differences between how materials are applied to 3D objects loaded from embedded files and how they were applied to the primitive 3D objects created in (download code ch:2)Creating and Displaying Primitives. You may have noticed that when using model loading classes (like the Md2 class) we have applied the material directly via the Mesh material property, whereas in Creating and Displaying Primitives, we apply materials of the primitive 3D objects using the material init object parameter.

To explain this difference, we first need to know how the Init class works. Let's take a look at the getMaterial() function provided by the Init class.

The logic used by the getMaterial() function is similar to the other "get" functions provided by the Init class. It will first check for the existence of the requested property in the init object, referenced by the init property. If it does not exist, null is returned. If it does exist, the property is cast to a Material. Before the material is returned, the init object property that was just accessed is deleted.

Because the init object property is deleted once it is read, calls to the Init class "get" functions in effect consume the requested property. This means if two objects share the same init object, the first one to read a specific init object property (via an Init object) is the only one to get the value assigned to that property. This consumption of init object properties is important when you see how many classes an init object will pass through. The following list shows a selection of the classes and functions the init object supplied to the Md2 parse() function will pass through:

Md2.parse

Loader3D.parse

LoaderCube constructor

Loader3D constructor

ObjectContainer3D constructor

Mesh constructor

Object3D constructor

Md2 constructor

AbstractParser constructor and more...

As you can see, the init object you supply to the Md2 parse() function changes hands quite a bit, and each time it does there is a chance that a property of that init object will be consumed. This is exactly what happens to the material init object property. It is consumed in step 6, where it is used to define the material that will be applied to the Cube primitive that is used as a place holder while the MD2 file is downloaded and parsed. The material property is then requested a second time in step 9, where it is used to define the material that is applied to the loaded 3D object. Of course, by this time the material property has been consumed and is no longer available.

The problem here is that a number of Away3D classes request the same property from an init object, and the order in which they consume these properties is not immediately obvious. In the case of the Md2 class, the material init object property is consumed by the Mesh constructor to be applied to the place holder Cube primitive, and not the AbstractParser constructor , which would apply the material to the loaded 3D object (which is the effect that you may expect when providing the material init object parameter).

The workaround to this issue is to simply assign the value to the specified property directly. This is why we have assigned the required material to the Mesh material property directly in a number of the examples presented in this chapter.

Converting a loaded model to an ActionScript class

The Mesh object has a function called asAS3Class(), which can be used to dump a 3D object to an ActionScript class.

The following initScene() function could be used in the MD2EmbeddedDemo from the MD2—Embedded File example. It creates a new Mesh object from a MD2 file, and then uses the trace function to output the string returned by the asAS3Class() function.

The asAS3Class() function can output many megabytes of data for complex models. You may find a tool like Vizzy Flash Tracer (http://code.google.com/p/flash-tracer/) easier to use than your authoring tool when dealing with such large trace dumps.

Converting 3D models into an ActionScript class offers some degree of copy protection by making it harder for your models to be extracted and used by a third party. And because the resulting ActionScript class only includes the data required by Away3D, it can result in smaller model files by stripping some of the extraneous data present in some 3D file formats (although this is not always the case—see Chapter 13, Performance Tips, for a more detailed look at the benefits of saving 3D objects as ActionScript classes).

Animations are not exported when using the asAS3Class() function in Away3D version 3.6. This functionality is expected to be included in later versions of Away3D.

Alternatively, you can use a tool like Prefab to import a 3D model file and then export an AS class. Prefab is a free tool that runs on the Adobe AIR platform, and can be downloaded from http://www.closier.nl/prefab/.

The following instructions show you how to convert a 3D model file into an ActionScript class using Prefab:

Click File | Import 3D model.

Select the 3D model file you wish to import and click on the OK button.

At this point, you will see a Geometry integrity report window. Click on the Close button to return to the main window.

Select the imported model by clicking on it. When selected, the model should be surrounded by a blue box.

Click Export | Export to Away3D AS3 class.

Select the Selected Object and Only Geometry options.

Type in a name for the class in the ClassName textbox.

You can leave the Package textbox empty, or you can optionally specify the package that the class should reside in.

Click on the Save File button.

Select a location to save the file (you will most likely want to save it in the same location as other source code files) and click on the Save button.

These instructions are valid for Prefab version 1.336. Prefab is an active project that is updated on a regular basis, and so some of these steps may change in later versions.

Summary

While it is possible to create simple 3D objects manually or through the primitive 3D objects supplied with Away3D, it is very common to display 3D models created and exported from 3D authoring applications. We have seen how these 3D models can be exported from a number of 3D modeling applications, such as 3ds Max, Blender, Milkshape, and Sketch-Up.

We have covered the differences in embedding the 3D model files directly into the final SWF file and loading them as external files. Sample applications were presented that demonstrate how the different formats supported by Away3D, which include 3DS, AWD, MD2, Collada, OBJ, ASE, and ActionScript, can be loaded, parsed, and displayed.

Finally, we saw how we can use the functionality in the Mesh class to convert a loaded 3D object into an ActionScript class, which provides a degree of copy protection and optimization.

Alerts & Offers

Series & Level

We understand your time is important. Uniquely amongst the major publishers, we seek to develop and publish the broadest range of learning and information products on each technology. Every Packt product delivers a specific learning pathway, broadly defined by the Series type. This structured approach enables you to select the pathway which best suits your knowledge level, learning style and task objectives.

Learning

As a new user, these step-by-step tutorial guides will give you all the practical skills necessary to become competent and efficient.

Beginner's Guide

Friendly, informal tutorials that provide a practical introduction using examples, activities, and challenges.

Essentials

Fast paced, concentrated introductions showing the quickest way to put the tool to work in the real world.

Cookbook

A collection of practical self-contained recipes that all users of the technology will find useful for building more powerful and reliable systems.

Blueprints

Guides you through the most common types of project you'll encounter, giving you end-to-end guidance on how to build your specific solution quickly and reliably.

Mastering

Take your skills to the next level with advanced tutorials that will give you confidence to master the tool's most powerful features.

Starting

Accessible to readers adopting the topic, these titles get you into the tool or technology so that you can become an effective user.

Progressing

Building on core skills you already have, these titles share solutions and expertise so you become a highly productive power user.