Requirements     

               
Prerequisite knowledge
Prior experience programming with ActionScript 3 is required. A previous background working with 3D graphics is also recommended.
Required products
Flash Builder (Download trial)
Sample files
User level
All
   

Additional required other products

This article describes how to work with 3D-engine Alternativa3D version 8. It was developed by AlternativaPlatform and is designed to help you work with 3D-graphics. This 3D-engine leverages Molehill technology, enabling rendering via a graphics processor when working with 3D-graphics. Follow along with these instructions to learn the basics of using Alternativa3D version 8.

Working with Alternativa3D

To begin working with the engine, read the following theoretical basics and technical details. This information includes the concepts you need to know to start using Alternativa3D.

Understanding the 3D world of Alternativa3D

The 3D world of the Alternativa3D engine has many similarities with the flat Flash Stage environment. Consider the following shared attributes:

  • Both worlds are built on a hierarchical structure
  • All objects of each world (including the root object) have a single base class (DisplayObject and Object3d)
  • To make an object visible, it must be added to the hierarchy
  • You can make an object visible by calling the addChild() method
  • Almost any node of the hierarchy can be a parent container for objects
  • Each object exists in its own coordinate space
  • All child objects maintain their position in their parent's coordinate space
  • The properties used to set the object's position are standard (such as x and y). For example both use scaleX, rotationY, and so on
  • The coordinates of an object in its own space always equal 0, 0, 0 (including all visible parts)
  • You can create visual content using ActionScript code as well as loading external files or embedded assets

Also compare the differences between Alternativa3D and Flash:

  • The root object of the flat world is an application itself, but you must create a root object for the 3D world
  • The simplest DisplayObject can't have children, but a Object3d can (similar to the behavior of a DisplayObjectContainer)
  • The flat world is ready with an empty application but the 3D environment requires some preparation (to add a minimum set of created objects and calls)

To get a better understanding between the heart of 2D and 3D visual objects, consider that Flash graphics are built on points with straight or curved lines. 3D Objects can consist of strokes, fills, or both. Not all Object3d data is visual: the main visual object3d class is mesh. Mesh is also built on points called vertices, but a vertex can hold additional data (such as texture coordinates, normals, tangents, and so on) as well as its own coordinates. Another difference between Flash and Object3D is that verticies can be linked with direct lines only to make a triangle.

The sequence of these triangles form a surface for the 3D object. The surface is comparable to a normal Flash shape, which has a fill but does not have to be flat. The fill in the 3D world is associated with material. Material differs from a fill because each pixel of material can hold data information related to lighting. This information defines the behavior of an object exterior depending on the point of view, the disposition, and the features of lights presented in the 3D world. Some materials are more complex than others, and their complexity may require different sets of data to be successfully rendered.

The simplest material used to fill a 3D object is FillMaterial. This material acts like a solid fill in the Flash environment. FillMaterial does not need any additional data and the surfaces with this material will ignore light settings. The most complex and extensive material in the 3D Alternativa world is StandardMaterial. StandardMaterial requires the maximum additional data in textures as well as in vertex points.

In order for the Surface to work with StandardMaterial, it must contain the following vertex data:

  • Texture coordinates
  • Vertex normals
  • Complex data type, consisting of tangent and bi-normal

In addition to the vertex data and usual diffuse map used to define image surface fills, StandardMaterial requires a normal map. The texture defines deviations between geometry surface and surface respond to light calculations in order to make the surface look more detailed than its geometry. A flat surface can look rough due to an object's normal map.

To make the surface more attractive and realistic, you can also optionally set additional textures to StandardMaterial fills: glossiness map and specular map.

Types of Object3d

As mentioned previously, not all Object3d objects are visual. You can work with non-visual classes (including but not limited to working with Mesh). The visual classes are described below.

Visual classes:

Mesh:Static 3D object that consists of surfaces.

Primitives: (Box and GeoSphere): Subclasses of mesh which include built-in visual forms generated during the creation processs according to it's name.

Skin: Subclass of mesh which includes joints (bones) to help move and animate parts of solid object.

Decal:subclass of Mesh with a z-fighting suppression engine. Use Decals to add additional marks on top of existing mesh, such as bullet holes and blood splash that may occur as the game is played.

WireFrame:Stroke analogue in the 3D world which displays lines (such as edges of mesh or axis).

SkyBox:Cubic primitive designed to show the 3D environment. It has a few differences with Box because normals are turned inside and permanently exist at the "bottom layer" to ensure SkyBox does not overlap with any other object.

Sprite3d and AnimSprite: Flat pictures/animations which live in the 3D world but are always turned towards the camera; they cannot have any perspective distortion.

Non-visual classes:

Camera3D - Object3D: Determines the view displayed on screen: the point of view, field of view, and the camera's direction.

Light3D: Base class for all lights in Alternativa3D: OmniLight, DirectionalLight, and AmbientLight. Use Light3D to light surfaces with appropriate materials, such as VertexLightMaterial and StandardMaterial.

Joints: These are also known as bones. Use Joints to move (animate) Object3D parts of solid mesh. Joints act like container for a set of vertices but one vertex can be handled by up to 8 joints and each vertex includes a value of power to affect each joint.

Hardware API and resources

Flash Player 11 includes hardware acceleration for rendering 3D. In order to leverage this functionality, you must follow some guidelines in order to be compatible with the player.

A hardware-rendered image is not included in the classic DisplayTree. Instead, it exists in a special stage: stage3d. Any application can have four different stage3d elements, all placed as layers on top of each other but below the DisplayTree. This ensures that flat Flash objects will always overlap the 3D image.

When you work with the hardware API you must load all of the data required to render image with GPU into video memory. The rendering data is associated with resources in Alternativa3D. There are two general types of resources: vertex data and textures. Alternativa3D offers several different ways of dealing with resources. You can begin by using the simplest strategy: obtain all resources of the object and all its children by using the method getResources(true).

In some cases, when you use TexturesLoader to load textures from external files, you must also upload texture resources to video memory. When working with textures, remember that a texture's width and height should divisible by the power of 2. For example, 512 x 256 pixels is a good texture dimension, but there's no way to apply a texture as 200 x 300 pixels.

Application structure

When you build a normal Flash application, the project is inherited from the DisplayObject class, such as Sprite or MovieClip to add the necessary requirements. In contrast, when building an Alternativa application, you need to set up the 3D world and connect the parts with the flat screen.

First, create the root object of the 3D world. This can be an Object3D instance, named rootContainer.

rootContainer = new Object3D();

Next, add the Camera3D object in rootContainer hierarchy, like this:

camera = new Camera3D(10, 1000); rootContainer.addChild(camera);

When creating a camera instance, you'll pass two arguments: nearClipping and farClipping which determine the depth of the space the camera can observe, working with the z-buffer used in the hardware rendering engine. The rendering engine draws objects one by one and requires information if some parts of the already drawn objects are placed nearer than those parts that are being processed in the same part of the screen. These values determine areas that should be hidden, rather than drawn. In order to calculate the depth of the visible space, the engine maintains the distance to the camera while drawing each pixel. If the camera's distance value setting is close to a pixel's location, the rendering engine leaves this pixel as is.

GPU has a fixed memory size to keep its distance to the camera (called the z-buffer). As the depth of space increases between nearClipping and farClipping, the precision of distance becomes less accurate. For this reason, it is best to keep the nearClipping and farClipping values closest to each other. Attempts to render multiple objects placed close to each other can cause visual artifacts to occur (called Z-fighting). You can use the Decal class to avoid visual artifacts, because the overlapping marks should be very close to other surfaces.

Finally, you'll create a viewport for the camera. The view determines the size of the visible area, the color of the background, and other properties.

camera.view = new View(stage.stageWidth, stage.stageHeight, false, 0x404040, 0, 4);

The camera view must exist in the regular DisplayTree, so use the addChild method to call it, like this:

addChild(camera.view);

In order to see instances appear on the Stage, be sure to add the camera view to the rootContainer hierarchy too.

After combining the code snippets described above, you can use the full code example to create an application:

package { import alternativa.engine3d.core.Camera3D; import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.View; import flash.display.Sprite; [SWF(backgroundColor h3. "0x909090", width "800", height = "600")] public class HelloBox extends Sprite { private var camera:Camera3D; private var rootContainer:Object3D; public function Template() { camera = new Camera3D(0.01, 10000000000); camera.view = new View(stage.stageWidth, stage.stageHeight, false, 0x404040, 0, 4); addChild(camera.view); rootContainer = new Object3D(); rootContainer.addChild(camera); } } }

Whenever you create a new object, it uses the default coordinates of 0,0,0 which are associated with the origin of its parent. In the code example above, the camera was placed in the center of the rootContaner pointing upwards. Even if you added some geometry to rootContainer, the camera would not see anything since the new geometry is added to the center; it will surround the camera. All geometry in Alternativa3D has only one side and can not be seen from inside. (The visible side is determined by the normals of the surface but from the inside unlike from the outside it is invisible—SkyBox is an example of this). In order to see the elements of the project, you'll need to move and turn the camera. You can do so by setting the coordinates and rotation properties of the camera but most projects require other strategies to calculate these values. In many cases, the user may control the camera with the keyboard and the mouse as the application is running; in other projects you can set the camera to point at a given object. However, for the purposes of building a simple application like the one described here, you can use the SimpleObjectController class in Alternativa3D. This camera controls the camera position with the keyboard and mouse and includes a set of methods you can use to handle the camera with ActionScript code, such as the lookAt() method.

camera.x = -50; camera.y = -300; camera.z = 100; controller = new SimpleObjectController(stage, camera, 200); controller.lookAtXYZ(0,0,0);

Remember these two points when working with the controller:

  • Always update the controller whenever the camera position will change. You can accomplish this by calling the controller.update() method. If the camera is controlled with a keyboard and a mouse add this call to an enterFrame handler.
  • •If a controller performs a relative move such as step forward, the controller uses its stored coordinates. As a result, if you change the camera placement by setting its properties (such as x, y, and z), the camera position is dropped the next time controller.update() is called. To avoid issues, use the throughcontroller.setPosition() method to change the placement of the camera.

Leveraging GPU

In the previous section you learned how to set up the 3D world. In this section you'll learn how to integrate the application with GPU. To begin, you'll set up an instance of Stage3D and its property, context3D, which is associated with the video memory.

stage3D = stage.stage3Ds[0];

In order to use GPU, all resources must be loaded into the video memory. You can use the upload() method to get context3D as a parameter specifying the destination of this upload. You may be surprised that stage3D is not pre-configured to work context3D. You must create it, and then start to do something with context3D after it is initalized.

stage3D.addEventListener(Event.CONTEXT3D_CREATE, init); stage3D.requestContext3D();

After creating context3D, you can upload resources and start rendering the animation.

private function init(event:Event):void { for each (var resource:Resource in rootContainer.getResources(true)) { resource.upload(stage3D.context3D); } addEventListener(Event.ENTER_FRAME, enterFrameHandler) }

If the app requires rendering every frame, place the call to controller.update() in enterFrameHandler function, like this:

private function enterFrameHandler(event:Event):void { controller.update(); camera.render(stage3D); }

At this point, you've completed the base application. If desired, you can save a copy of this project to use as a clear template for your future projects. You can create a copy and reset the Template class name.

However, the template does not contain any visible objects yet. You can use the code snippet below to add a cube and rename the class to HelloBox.

box = new Box(); box.setMaterialToAllSurfaces(new FillMaterial(0x804080)); rootContainer.addChild(box);

Any object is invisible until you fill it with material. In the code example below you'll assign the FillMaterial fill to the surfaces (sides) of the cube:

package { import alternativa.engine3d.controllers.SimpleObjectController; import alternativa.engine3d.core.Camera3D; import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.Resource; import alternativa.engine3d.core.View; import alternativa.engine3d.materials.FillMaterial; import alternativa.engine3d.primitives.Box; import flash.display.Sprite; import flash.display.Stage3D; import flash.events.Event; [SWF(backgroundColor = "0x909090", width = "800", height = "600")] public class HelloBox extends Sprite { private var stage3D:Stage3D; private var camera:Camera3D; private var rootContainer:Object3D; private var controller:SimpleObjectController; private var box:Box; public function HelloBox() { camera = new Camera3D(0.01, 10000000000); camera.x = -50; camera.y = -300; camera.z = 100; controller = new SimpleObjectController(stage, camera, 200); controller.lookAtXYZ(0,0,0); camera.view = new View(stage.stageWidth, stage.stageHeight, false, 0x404040, 0, 4); addChild(camera.view); rootContainer = new Object3D(); rootContainer.addChild(camera); box = new Box(); box.setMaterialToAllSurfaces(new FillMaterial(0x804080)); rootContainer.addChild(box); stage3D = stage.stage3Ds[0]; stage3D.addEventListener(Event.CONTEXT3D_CREATE, init); stage3D.requestContext3D(); } private function init(event:Event):void { for each (var resource:Resource in rootContainer.getResources(true)) { resource.upload(stage3D.context3D); } addEventListener(Event.ENTER_FRAME, enterFrameHandler) } private function enterFrameHandler(event:Event):void { controller.update(); camera.render(stage3D); } } }

Setting up the development environment

In this section, you'll set up the development tools and connect to them to work with the Alternativa3D library.

Preparation of SDK

  1. Download Flash Player 11 file: playerglobal.swc.
  2. Navigate to the \frameworks\libs\player\ inside the SDK folder. If folder 11.0 does not exist, create a folder using that name and copy the playerglobal.swc file into it.

Setting of IDE and library connection

  1. Launch Adobe Flash Builder 4. The start window appears (see Figure 1):
The Flash Builder 4 Start window is displayed.
Figure 1. The Flash Builder 4 Start window is displayed.
 
  1. Create a new ActionScript project (File > New > ActionScript Project) as shown in Figure 2.
Use the menu to create a new ActionScript project.
Figure 2. Use the menu to create a new ActionScript project.
  1. In the window that appears, specify the basic parameters of the project (including its name, path to the working directory, and version of SDK). Enter the name of the project: HelloBox in the Project name field (see Figure 3).
Enter the basic settings to create the new project.
Figure 3. Enter the basic settings to create the new project.
  1. You must target SDK version 4.5 (or higher). If you haven't already done so, click the link to Configure Flex SDKs... The list of Installed Flex SDKs is displayed in the Preferences window. Click the Add button to add the path to the SDK (see Figure 4).
Click the Add button to add the path to the SDK.
Figure 4. Click the Add button to add the path to the SDK.

In the Add Flex SDK window that appears, click Browse and navigate to select the Flex SDK (see Figure 5).

Specifying the path to the SDK.
Figure 5. Specifying the path to the SDK.

After setting the path, click OK (see Figure 6).

Click OK.
Figure 6. Click OK.

To proceed to the next window, click Next (see Figure 7).

Click Next to proceed to the next screen in the New ActionScript Project window.
Figure 7. Click Next to proceed to the next screen in the New ActionScript Project window.
  1. Next, you'll specify additional parameters of the project. Click the Add SWC button to access the area where you can add a third-party library (see Figure 8).
To add third-party libraries, click the Add SWC button.
Figure 8. To add third-party libraries, click the Add SWC button.

Click the Browse button and navigate to the SWC file to specify the path to Alternativa3D 8 SWC file (see Figure 9).

Specify the path to the library for Alternativa3D 8.
Figure 9. Specify the path to the library for Alternativa3D 8.

Click Finish to complete the project creation process (see Figure 10).

After entering the parameters for the new project click Finish.
Figure 10. After entering the parameters for the new project click Finish.
  1. An empty ActionScript 3.0 project is displayed (see Figure 11).
The empty project is displayed in the code window of Flash Builder.
Figure 11. The empty project is displayed in the code window of Flash Builder.
  1. Next, you'll specify some additional properties related to the compilation. Right-click on the root folder for the project and use the context menu that appears to select Properties (see Figure 12).
Use the context menu to choose the Properties option.
Figure 12. Use the context menu to choose the Properties option.
  1. Use the ActionScript Compiler screen to specify the properties of the compiler:
    1. Specify the version of Flash Player that will play the SWF file: 11.0.0.
    2. In the Advanced compiler arguments field, enter: -swf version=13. The number 13 is the SWF version that corresponds to Flash Player 11. This field enables you to tell the runtime what version of the APIs the project will use (see Figure 13).
Update the settings in the ActionScript Compiler screen to specify the properties of the compiler.
Figure 13. Update the settings in the ActionScript Compiler screen to specify the properties of the compiler.
  1. Next, open and update the properties of HTML-environment, file index.template.html (see Figure 14).
Right-click the index.template.html file and choose Open with > Text Editor to edit the HTML environment properties.
Figure 14. Right-click the index.template.html file and choose Open with > Text Editor to edit the HTML environment properties.
  1. To enable hardware acceleration, you must set wmode to use the direct property. Add a line like this: params.wmode = "direct"; to set the wmode (see Figure 15):
Update the index.template.html file to set the wmode.
Figure 15. Update the index.template.html file to set the wmode.

At this point, everything is ready to go. Verify that the project is configured correctly by creating the red cube using the Red Box code described above. Use the article's example file as a template and compile it (see Figure 16).

The result of compiling the HelloBox project.
Figure 16. The result of compiling the HelloBox project.

When the project runs, you'll see a red rotating box; this indicates that everything is configured correctly and you are ready to move on to the next section.

Loading 3D models into applications

This section includes a training demo to illustrate how to load the provided 3D models into your Flash applications. If you haven't already, be sure to download the sample files provided at the beginning of this article.

Load Collada with Alternativa 3D

In the previous tests you animated a red rotating cube. The cube does not look very interesting at the moment. To display a more complex model, you'll load data from an external file. (You could also optionally choose to programmatically update the cube with ActionScript code, but it is a less common approach because it requires more work).

It doesn't matter how the model data is brought into to application: you can choose to embed it into the SWF file or load the file in at runtime. In this example you'll use the first option, in order to keep the code as clear and compact as possible.

[Embed("resources/model.dae", mimeType="application/octet-stream")] private static const ModelClass:Class;

Next, you'll convert the model data into a set of Alternativa3D's 3D objects. You can use a special parser class to accomplish this. Since the model is built in Collada, you'll use the ParserCollada method to make one:

var parser:ParserCollada = new ParserCollada();

And add the next command to parse the Collada file:

parser.parse(XML(new ModelClass()), "resources/images/", true);

The new ModelClass() method returns model data as a binary stream. You must cast it to XML since Collada is XML-based. The second argument is the path from your SWF file to the textures folder, so make sure that the textures are stored here. The third argument, trim path, is designed for situations when links to textures in the model file kept with a path do not correspond with their real placement.

The parser has indexed all of the 3D objects from inside the model now. You can get this data using the parser.objects property. Or, if you want to maintain the relationship of objects, use the parser.hierarchy property. This property holds root objects only, but all of the remaining objects exist within those root objects, so adding the root objects to the scene is sufficient.

To ensure that all of the model's objects are interacting at once, place them to separate a container:

modelContainer = new Object3D(); rootContainer.addChild(modelContainer); for each (object in parser.hierarchy) { modelContainer.addChild(object); }

Finally, the last thing to work with are the materials applied to the model. All surfaces created by the parser have been assigned the special ParserMaterial property. This material is used for debugging purposes, not for the final production. It is very similar to TextureMaterial, but it stores additional links to different maps such as ambient, emission, diffuse, specular, shininess, reflective, transparent, and bump. The ParserMaterial can use only one map at a time, but you can choose to use any of them. These maps can be used with the more complex StandardMaterial which utilizes all of them at once. To accomplish this, you'll iterate all surfaces and apply a StandardMaterial to each one, passing to this material all maps from the older material.

var object:Object3D; // Prepare objects materials for each (object in parser.objects) { var mesh:Mesh = object as Mesh; if (mesh != null) { for (var i:int = 0; i < mesh.numSurfaces; i++) { var surface:Surface = mesh.getSurface(i); if (surface.material != null) { var material:ParserMaterial = ParserMaterial(surface.material); surface.material = new StandardMaterial(material.textures["diffuse"], material.textures["bump"], material.textures["specular"], null, material.textures["transparent"]); } } } }

Place all of the code related to working with the model in the addModel() method to keep the project well-structured.

After preparing the model and the materials, you can use context3D to upload resources. Remember that models retain the links only, not the texture images. So you need to load the necessary image files and the TextureLoader class for the project. You can pass a list of ExternalTextureResources to the texturesLoader.loadResources() method. Since the TexturesLoader class uploads the recently loaded textures into the context3D, you can filter those resources while uploading the rest of the files, using this function:

private function onContextCreate(event:Event):void { // Upload resources var context3D:Context3D = stage3D.context3D; var textures:Vector.<ExternalTextureResource> = new Vector.<ExternalTextureResource>(); for each (var resource:Resource in rootContainer.getResources(true)) { if (resource is ExternalTextureResource) { textures.push(resource); } else { resource.upload(context3D); } } var texturesLoader:TexturesLoader = new TexturesLoader(stage3D.context3D); texturesLoader.loadResources(textures); addEventListener(Event.ENTER_FRAME, onEnterFrame); }

To make the animation more attractive, add a few lights to the scene:

private function addLights():void { ambient = new AmbientLight(0xc0d0f0); rootContainer.addChild(ambient); dLight = new DirectionalLight(0xFFFFFF); dLight.intensity = 1.5; dLight.y = -500; dLight.z = 500; dLight.lookAt(0, 0, 0); rootContainer.addChild(dLight); }

And make the animation more expressive by varying the color, intensity, and direction of the lights:

private function onEnterFrame(e:Event = null):void { modelContainer.rotationZ += .01; modelContainer.z = 30 * Math.sin (modelContainer.rotationZ * 3); dLight.rotationZ -= 0.01; var kappa:Number = .5 * (Math.sin(2 * dLight.rotationZ) + 1); dLight.color = 0xff0000 + ((kappa * 0xff) << 8) + (kappa * 0xff); dLight.intensity = .5 + kappa ; ambient.intensity = .5 + kappa; controller.update(); camera.render(stage3D); }

Here is the complete code example for the project:

package { import alternativa.engine3d.controllers.SimpleObjectController; import alternativa.engine3d.core.Camera3D; import alternativa.engine3d.core.Object3D; import alternativa.engine3d.core.Resource; import alternativa.engine3d.core.View; import alternativa.engine3d.lights.AmbientLight; import alternativa.engine3d.lights.DirectionalLight; import alternativa.engine3d.loaders.ParserCollada; import alternativa.engine3d.loaders.ParserMaterial; import alternativa.engine3d.loaders.TexturesLoader; import alternativa.engine3d.materials.StandardMaterial; import alternativa.engine3d.objects.Mesh; import alternativa.engine3d.objects.Surface; import alternativa.engine3d.resources.ExternalTextureResource; import flash.display.Sprite; import flash.display.Stage3D; import flash.display3D.Context3D; import flash.events.Event; [SWF(width = 800, height = 800, backgroundColor = 0x303030, frameRate = 100)] public class GorgylDemo extends Sprite { [Embed("resources/model.dae", mimeType="application/octet-stream")] private static const ModelClass:Class; private var stage3D:Stage3D; private var rootContainer:Object3D = new Object3D(); private var controller:SimpleObjectController; private var camera:Camera3D; private var dLight:DirectionalLight; private var ambient:AmbientLight; private var modelContainer:Object3D; public function GorgylDemo() { camera = new Camera3D(10, 100000); camera.view = new View(stage.stageWidth, stage.stageHeight, false, stage.color, 1, 4); addChild(camera.view); camera.y = -500; controller = new SimpleObjectController(stage, camera, 100); controller.lookAtXYZ(0,0,-50); rootContainer.addChild(camera); addLights(); addModel(); stage3D = stage.stage3Ds[0]; stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate); stage3D.requestContext3D(); } private function addLights():void { ambient = new AmbientLight(0xc0d0f0); rootContainer.addChild(ambient); dLight = new DirectionalLight(0xFFFFFF); dLight.intensity = 1.5; dLight.y = -500; dLight.z = 500; dLight.lookAt(0, 0, 0); rootContainer.addChild(dLight); } private function addModel():void { var parser:ParserCollada = new ParserCollada(); parser.parse(XML(new ModelClass()), "resources/images/", true); var object:Object3D; // Prepare objects materials for each (object in parser.objects) { var mesh:Mesh = object as Mesh; if (mesh != null) { for (var i:int = 0; i < mesh.numSurfaces; i++) { var surface:Surface = mesh.getSurface(i); if (surface.material != null) { var material:ParserMaterial = ParserMaterial(surface.material); surface.material = new StandardMaterial(material.textures["diffuse"], material.textures["bump"], material.textures["specular"], null, material.textures["transparent"]); } } } } modelContainer = new Object3D(); rootContainer.addChild(modelContainer); for each (object in parser.hierarchy) { modelContainer.addChild(object); } } private function onContextCreate(event:Event):void { // Upload resources var context3D:Context3D = stage3D.context3D; var textures:Vector.<ExternalTextureResource> = new Vector.<ExternalTextureResource>(); for each (var resource:Resource in rootContainer.getResources(true)) { if (resource is ExternalTextureResource) { textures.push(resource); } else { resource.upload(context3D); } } var texturesLoader:TexturesLoader = new TexturesLoader(stage3D.context3D); texturesLoader.loadResources(textures); addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(e:Event = null):void { modelContainer.rotationZ += .01; modelContainer.z = 30 * Math.sin (modelContainer.rotationZ * 3); dLight.rotationZ -= 0.01; var kappa:Number = .5 * ( Math.sin(2 * dLight.rotationZ) + 1); dLight.color = 0xff0000 + ((kappa * 0xff) << 8) + (kappa * 0xff); dLight.intensity = .5 + kappa ; ambient.intensity = .5 + kappa; controller.update(); camera.render(stage3D); } } }

Compile the completed project to see the result (see Figure 17).

The finished project as it appears after compiling.
Figure 17. The finished project as it appears after compiling.

Where to go from here

Hopefully this article has helped you learn some basics to continue working with Alternativa3D version 8. For more information visit the following online resources:


More Like This