Home Labs Galleries PetitOn
Page 3

Part 5. Materials

Sometimes we want our materials to be a bit more vivid. It may be that we want to create a disco ball or a psychedelic moving texture, or just present a talking head.

Two materials offer animation, the MovieMaterial, which takes a MovieClip as its texture, and the VideoMaterial , which allows you to present an FLV video on your 3D objects. this time we will study how these useful and funny materials can be used.

The MovieMaterial

If you want to apply a MovieClip to your object, whether animated or not, you use the MovieMaterial. Its constructor takes three arguments, the MovieClip to use, an update interval and an optional MaterialAttributes. Internally the material takes a snapshot of the animated MovieClip at the update interval. The default update interval is 40 ms.

We use the same general application as in the earlier examples. The interesting changes are done within the createScene method. Before we go into this, let's create an animated MovieClip.

The clip

This is the way to do it in the Flash IDE.

Go to Insert a new MovieClip ( Ctrl + F8 ).
In the dialog name select the Movie clip radio button, tick the "Export for ActionScript" check box and give the clip a name.

Create two layers and make 40 frames in both layers

In the lower layer, draw a square with some background color, and make sure the registration point is in the upper left corner. Lock the layer.

In the upper layer draw a smaller square with another color.

In the upper layer, convert the frames 10, 20, 30 and 40 to key frames one by one, while you move the smaller square to a new position.

Test that you have an animation by dragging the play head, and go back to the main stage. The clip should reside in the library with no instance on stage.

The code

With the animated clip in the library, we are ready to dress up our standard primitive with a MovieMaterial. Here is the code in createScene

	private function createScene():Group
	{
		var root:Group = new Group();
		box = new Box( 'box', 60, 60, 60, PrimitiveMode.TRI, 2);

		movie = new TheMovie();
		material = new MovieMaterial( movie );
		var app:Appearance = new Appearance( material );
		box.appearance = app;
			
		box.enableNearClipping = true;
		root.addChild( box );
		return root;
	}

The movie and material variables are instance variable, so we are able to access them from any method with the class.

It is also interesting to see what happens if we change the alpha channel of the material. We do this, using the same application we used earlier. The result is shown to the right above, where also the back face culling is disabled, so we can see the inside of the cube.

Using an existing SWF

There might be situations, where you have a Flash movie, a SWF, that you want to use as an animated texture. You can then either import it to the library, and use as you do any MovieClip, or you can load it dynamically at run time. Let's try the externally loaded variant, with my old motor animation. It's a bit rudimentary, but what the heck, it moves.

The motor.swf is created and compiled for an earlier version of Flash Player, so it uses the old MV1 engine. This means trouble if you load it using the loader, that's why I chose to import it to the library. I will call the automatically created class Motor.

So here we go.

	// Create the root Group and the object tree 
	private function createScene():Group
	{
		var root:Group = new Group();
		box = new Box( 'box', 60, 60, 60, PrimitiveMode.TRI, 2);

		movie = new Motor();
		box.appearance = new Appearance( new MovieMaterial( movie ));

		box.enableBackFaceCulling = false;
		box.enableNearClipping = true;

		root.addChild( box );
		return root;
	}

Not much difference here. When instantiating the Motor containing the SWF, we get a MovieClip, that we can pass to the MovieMaterial constructor. We can even access the start and stop methods for the SWF, as we shall see.

To that end we add to the MOUSE_DOWN handler a call to a method toggleMovie, that starts and stops the motor.

	private function downHandler( e:Event ){
		moving = true;
		toggleMovie();
	}
	private function toggleMovie(){
		animate = !animate;
		animate?movie.play():movie.stop();
	}

The movie and animate variables of course are instance variables.

 

If you try to load the AS2 SWF at run time, you will run into some trouble. The first is that what you get from the loader is not a MovieClip. If you try to pass it to the MovieMaterial constructor, you get

Error #1034:"cannot convert flash.display::AVM1Movie@36b9c to flash.display.Sprite."

So what you get as loader.content is an object of class AVM1Movie, a display object handled by an earlier version of the virtual machine in the Flash Player. You can use this object in a MovieClip, but there are restrictions. We cannot access properties or method of the AVM1Movie from AS3, so we cannot use the the stop() and start() calls to toggle its animation on and off.

We create the scene as before, but without the appearance and material.

	// Create the root Group and the object tree 
	private function createScene():Group
	{
		var root:Group = new Group();
		box = new Box( 'box', 60, 60, 60, PrimitiveMode.TRI, 2);

		box.enableBackFaceCulling = false;
		box.enableNearClipping = true;
		root.addChild( box );
		return root;
	}

After calling the createScene method, we call loadMovie, to load the external SWF.

   //  Load the movie
  function loadMovie()
  {
 	var loader:Loader = new Loader();
	loader.contentLoaderInfo.addEventListener( Event.COMPLETE, loadComplete );
	loader.load(new URLRequest("motor.swf"));
  }

We listen for the COMPLETE event, and let the event handler dress up our cube, and so we order the loader to load our external AVM1Movie.

	// Take care of the movie as they are loaded.
	function loadComplete( event:Event ):void {
		var target = event.target;
		motor = target.loader.content;
		movie = new MovieClip( ) ;
		movie.addChild( target.loader.content );
		material = new MovieMaterial( movie );
		box.appearance = new Appearance( material );			
	}

The loader content is our movie, and we have to add it as a child to a new MovieClip, that we can send pass to the MovieMaterial. It works, but it is a bit crippled, as we can no longer interact with the animation. You may find information that says you can use a LocalConnection object to communicate between AS2 and AS3 objects.

This is true, but not a feasible solution when you use old AS2 objects, as both objects must contain LocalConnection objects.

 

The VideoMaterial

In the building of natural scenes, you may want to use video as texture for your objects, maybe place a waterfall on a Plane3D or a Sprite2D, or use trees, moving in the wind. Or you might just want to show a talking head on a wall. In such cases you use a VideoMaterial, that takes a Video object as its animated texture. Like the MovieMaterial, it extends BitmapMaterial, and an internal timer is used to take a snapshot of the running video at a set interval.

The video can be included in the library, or it may be streamed from a media server or progressively downloaded from a web server. The first alternative is good only for very short video clips, that don't add to much weight to the Flash movie. If you have access to a media server, that can server the Adobe FLV format, you should go for that. The media server streaming allows for jumping from one point to another in the video. It also handles many simultaneous viewers. Finally, the progressive download over a net connection, that we are going to use here, works nearly as streaming, but doesn't require a media server. The Player downloads to a buffer and starts playing when the buffer is full. It then progressively downloads while playing the FLV file.

The video

If you have access to the Flash CS3 IDE, you have two encoders that can convert your video to the Flash video format FLV. The Sorenson Spark codec is mostly used to encode video for Flash Player 6 or 7 or later, while the On2 VP6 codec is used for version 8 or later. Creating and converting video is not part of this tutorial, but you can read more on the subject in Using Adobe Flash CS3 Video Encoder.

I will cite myself from the Sandy 1.x tutorial, to tell you how I created my video example.

"It was filmed one morning from my kitchen window, using a digital hard disk camera, and loaded into my computer over USB. In PowerDVD, which came with the camera, I produced the clip into a WMV movie.

As I have access to the Flash MX IDE, I also have both Sorenson Spark and On2 VP6 video encoders. What they do is to read in a video file, and convert it to the Flash Video Format or FLV.

If you have Flash MX but not the stand alone encoders, you can import the movie to the movies library, and export it from there as FLV. If you don't have the Flash authoring tool at all, you may use the free Riva FLV Encoder"

You can work with video the same way in Flash CS3 as in Flash MX. The only difference is that you will be able to select the On2 VP6 codec for the encoding.

A video cube

As a basis for the application we may take one of the transparency applications with the slider, and change it to load the FLV file progressively. The situation is new in that we not just wait for the video to load, and then apply it as a texture. Instead we will use a Video object and attach a NetStream that starts to download the video.

The createScene method is the same as for the external SWF above - we create the scene without any materials. After that we call the getVideo method.

	// Get and attach the video
	private function getVideo(){
		video = new Video(320, 240);
		material = new VideoMaterial( video, 25 );
		var app:Appearance = new Appearance( material );
		box.appearance = app;

		var nc:NetConnection = new NetConnection();
		nc.connect(null);

		ns = new NetStream(nc);
		video.attachNetStream(ns);
			
		// The client is a listener
		var listener:Object = new Object();
		listener.onMetaData = function( evt:Object ):void {};
		ns.client = listener;
		ns.play("working.flv"); // move this to createScene			
	}

Let's se what happens here!

First we create a Video object, on which we will project the video. We pass this to the constructor of a new VideoMaterial, which we use as material in an Appearance, and we set this to be appearance of our everlasting box. Nothing very upsetting so far :)

We create a NetConnection and call the connect() method on it. Passing null makes the connection work locally. On the connection we then create a NetStream, which we attach to the display object, our Video.

The NetStream needs a client, that listens for meta data events, such as specific flags in the stream, called cue points. The listener also needs a meta data handler. To make it simple, it does nothing in this case. A disclaimer is prudent here - the set up of the connection and stream is done as simply as possible. If we want the application to be robust, we need to catch possible errors and do something about them. If one day you have the time and urge to become experts on video in Flash, there are lots web sites and books to read.

We tell the net stream to start playing our FLV as soon as the local buffer is full. We are at the end of the tutorial document, so we don't want the video to start playing immediately and reach the end, before our reader gets to see it, so we call the pause method. The user will start and pause the video by clicking on it, so we reuse the toggleMovie handler from the MovieMaterial application above.

More to come, so stay tuned!
Your comments are welcome! Mail to petit -at- petitpub.com or use my blog form.