Author: Max Pellizzaro
Date: November 7th 2007
Update: July 12th 2009
version: 3.1.1

Movie Material

Objective of the tutorial

In this tutorial you will learn how to apply a special skin (Material) to any 3D Object: a Movie Clip. A Movie Clip is the AS3 Class that allows modeling a sequence of elements that has frames. The same consideration we are doing for this tutorial can be applied also for flash movie (FLV).

You must be aware of something when using a Movie Clip to skin your object. The rendering engine will convert the Movie Clip to a bitmap on a regular basis to catch the animation that might be present in your Movie Clip. This means that if the Movie Clip has any kind of user interaction, this will be lost during the rendering process. In our tutorial we will build two Movie Clips just to show how they can then be applied on the faces of a cube.

In this tutorial we will use a nice feature provided by Sandy that will allow to load any resources with a special loader that can fire an Event when loading process in completed.

How to

Set up

The Document class must be changed to Example010.as The name of the class in the .as file and the name of the constructor now is: Example010. The Example010.as use two Movie Clips that have been created with two other *.as class: main.as and main2.as. You will find all the classes and *.fla files into the below archive.

example010_v02.rar

The new updated version can be found here:
example010_v3.1.1.zip

The AS Code

package
{
   import flash.display.*;
   import flash.net.URLRequest;
 
   import flash.events.*;
   import flash.ui.*;
   import sandy.core.Scene3D;
   import sandy.core.data.*;
   import sandy.core.scenegraph.*;
   import sandy.materials.*;
   import sandy.materials.attributes.*;
   import sandy.primitive.*;
   import sandy.util.*;
   import sandy.events.*;

   public class Example010 extends Sprite 
   {
	  private var scene:Scene3D;
	  private var camera:Camera3D;
	  private var box:Box;
	  private var queue:LoaderQueue;
	  
     public function Example010():void
     {
	   queue = new LoaderQueue();
	   queue.add( "test", new URLRequest("main.swf") );
	   queue.add( "test2", new URLRequest("main2.swf") ); 
	   queue.addEventListener(SandyEvent.QUEUE_COMPLETE, loadComplete );
	   queue.start();
     }
	 
      public function loadComplete(event:QueueEvent ):void
      {  
		 // We create the camera
		 camera = new Camera3D( 300, 300 );
		 camera.z = -400;
		 
		 // We create the "group" that is the tree of all the visible objects
		 var root:Group = createScene();
		 
		 // We create a Scene and we add the camera and the objects tree 
		 scene = new Scene3D( "scene", this, camera, root );
		 
		 // Listen to the heart beat and render the scene
		 addEventListener( Event.ENTER_FRAME, enterFrameHandler );
      }
	 
      // Create the scene graph based on the root Group of the scene
      private function createScene():Group
      {
		 // Create the root Group
		 var g:Group = new Group();
		 
		 // Create a cube so we have something to show
		 box = new Box( "box",100,100,100,"tri");
		 
		 box.rotateX = 30;
		 box.rotateY = 30;
		 box.x = 0;
				
		 // we define a simple color material
		 var materialAttr:MaterialAttributes = new MaterialAttributes( 
				new LineAttributes( 0, 0xD7D79D, 0 ),
				new LightAttributes( true, 0.1)
				);

		 var material:Material = new ColorMaterial( 0xD7D79D, 1, materialAttr );
		 material.lightingEnable = true;
		 var app:Appearance = new Appearance( material );		
		
		 // we define two Movie Material
		 var material01:MovieMaterial = new MovieMaterial( 
				queue.data["test"],40);
		 material01.lightingEnable = true;
		 var app01:Appearance = new Appearance( material01 );
		 
		 var material02:MovieMaterial = new MovieMaterial( 
				queue.data["test2"],40);
		 material02.lightingEnable = true;
		 var app02:Appearance = new Appearance( material02 );
		  
		 box.appearance = app; 
		 box.aPolygons[0].appearance = app01;
		 box.aPolygons[1].appearance = app01;
		 box.aPolygons[2].appearance = app02;
		 box.aPolygons[3].appearance = app02;
		 box.aPolygons[10].appearance = app02;
		 box.aPolygons[11].appearance = app02;
		 g.addChild( box );
          
		 return g;
      }

      // The Event.ENTER_FRAME event handler tells the Scene3D to render
      private function enterFrameHandler( event : Event ) : void
      {
		 box.tilt += 1;
		 box.pan += 1;
		 //sphere.pan += 1
		 scene.render();
      }
   }
}

Examining the code

 private var queue:LoaderQueue;

This class allows you to queue up requests for loading external resources. This is a very nice features because you can load elements and put them on a queue and use them as needed. In order to use this utility we just need few lines of code:

queue = new LoaderQueue();
queue.add( "test", new URLRequest("main.swf") );
queue.add( "test2", new URLRequest("main2.swf") ); 
queue.addEventListener(SandyEvent.QUEUE_COMPLETE, loadComplete );
queue.start();

As we can see you just need to define a name that will be the reference of the object you are loading (in this case we have two reference: test and test2), and the you need to specify the url of the resource you are trying to load. In our example we have two Movie Clips: main.swf and main2.swf.

package  {
	
	import flash.geom.*;
	import flash.display.BitmapData;
	import flash.display.MovieClip;
	import flash.display.Bitmap;
	import flash.events.*;
	
	public class Main extends MovieClip {
		private var mc1:MovieClip = new MovieClip();
	
		public function Main() {
			this.graphics.beginFill(0xD7D79D);
			this.graphics.drawRect(0, 0, 100, 100);
			mc1.graphics.lineStyle(1);
			mc1.graphics.beginFill(0x000099);
			mc1.graphics.drawCircle(20,50,10);
			mc1.addEventListener(Event.ENTER_FRAME, run);
			this.addChild(mc1);
		}

		private function run(e:Event):void {
			if (mc1.x >= 100)
			 mc1.x =-50 ;
			else
			 mc1.x +=3;	
		}
	
	} // end class

} // end package

This class extend the Movie Clip class, so we are sure that the Loader will treat it as a Movie Clip.

public class Main extends MovieClip {

Then we define another Movie Clip inside the class that represent a red ball that will be used to have a simple animation inside the Main Movie Clip.

private var mc1:MovieClip = new MovieClip();

We then place a background color just to make a nice look:

this.graphics.beginFill(0xD7D79D);
this.graphics.drawRect(0, 0, 100, 100);

Next we draw our little red ball:

mc1.graphics.beginFill(0x000099);
mc1.graphics.drawCircle(20,50,10);

Last, but not least, we model the animation of the ball inside the even handler called run. In this example we model a simple linear movement

 if (mc1.x >= 100)
    mc1.x =-50 ;
else
    mc1.x +=3;
mc1.x = 30 + 30*Math.cos(teta);
mc1.y = 0 + 30*Math.sin(teta);
teta += .1;
if (teta >= 3.14*2)
   teta = 0;

I’ll skip the building of the cube and the Color Material because by now you are probably more expert than me. Let’s dig into the Movie Material constructor:

var material01:MovieMaterial = new MovieMaterial( 
				queue.data["test"],40);
material01.lightingEnable = true;
var app01:Appearance = new Appearance( material01 );
 
var material02:MovieMaterial = new MovieMaterial( 
   				queue.data["test2"],40);
material02.lightingEnable = true;
var app02:Appearance = new Appearance( material02 );

The MovieMaterial class takes two parameters: the Movie Clip and the “update interval” that will be used to render the Movie Clip. As you can see we are using the two reference we have used when loading the external files.

box.aPolygons[0].appearance = app01;
box.aPolygons[1].appearance = app01;
box.aPolygons[2].appearance = app02;
box.aPolygons[3].appearance = app02;
box.aPolygons[10].appearance = app02;
box.aPolygons[11].appearance = app02;

So let’s see the result !!

The output

As you can see there are three faces that have loaded the Movie Clip we have just created !