Journey to the Next Dimension With Papervision3D: Part 1

This entry is part 1 of 2 in the series Journey to the Next Dimension With Papervision3D

To tie in with our Papervision3D Essentials giveaway, today’s tutorial also features a PV3D theme.

This two-part tutorial will show you how to get started with the Papervision3D engine, then how to make your creation jump out of the screen using an anaglyph effect in combination with 3D spectacles.

Introduction

Got a pair of 3D glasses lying around? Here in the UK, Channel 4 is running a special 3D Week – seven days of TV programmes broadcast in 3D – so plenty of people here do. Let’s put them to use.

This two-part tutorial will show you how to get started with the Papervision3D engine, and then how to make your creation jump out of the screen.

In this first part, you’ll learn the basics of PV3D, ending up with something like this:

Cube of cubes

…and in the second part, you’ll learn about the anaglyph effect for 3D glasses, and apply it to what you’ve made like so:

In three of the glorious dees

Step 1: The Setup

If you’re using Flash, create a new ActionScript 3.0 Flash file. Set the size of the stage to be whatever you like – I’ll stick with the default 550 by 400 pixels.

While you’re at it, create a new ActionScript file, and save it as Main.as in the same folder as your FLA. We’re going to use this AS file as the FLA’s document class, so click a blank space in your FLA file, and enter Main in the “Document class” box of the Properties panel.

Document class

(If you’re not using the Flash IDE, just create a new AS3 project.)

Step 2: Download Papervision3D

Head over to the Papervision Download Page. There are lots of different versions and a few different types of files (zip, swc, mxp). Just grab the latest .zip file (it should say Featured next to it). The one I’m using is called Papervision3D 2.1.920.zip (for use with “Papervision3D Essentials” book).

Step 3: Extract the Zip

Extract the zip file you just downloaded to anywhere on your hard drive. I like to keep all the different engines I use in the same folder, but it’s up to you.

Step 4: Set a Classpath

Flash needs to know where you extracted Papervision before it can use it. We use a classpath for this: click Edit > Preferences, select ActionScript, then click ActionScript 3.0 Settings….

In the box that appears, click the little “crosshair” icon, then find the folder where you unzipped Papervision and click OK. Click OK to the other boxes until you get back to the FLA.

Classpath

If you’re not using the Flash IDE, you’ll have to set this in a different way. For example, in FlashDevelop, you should click Tools > Global Classpaths.

Step 5: Set the Scene in Papervision

In Papervision, all your 3D objects must be placed inside a scene. It’s kind of like the Stage in regular ActionScript. So, before we do anything we need to create a Scene3D object that will contain everything else.

Switch to your Main.as file. Let’s quickly add the base code needed for any document class:

package
{
	import flash.display.MovieClip;

	public class Main extends MovieClip
	{
		public function Main()
		{

		}
	}
}

The Scene3D object is in org.papervision3d.scenes.Scene3D, so we need to import that, then create a new public var to hold the scene, and finally create the actual scene object: (lines 4, 8 and 12)

package
{
	import flash.display.MovieClip;
	import org.papervision3d.scenes.Scene3D;

	public class Main extends MovieClip
	{
		public var scene:Scene3D;

		public function Main()
		{
			scene = new Scene3D();
		}
	}
}

Step 6: Add a Cube

To start with, let’s just create a big plain cube sitting in our scene.

We’ll follow the same sort of steps as above to create it, then add it to our scene: (lines 5, 10, 15, 16)

package
{
	import flash.display.MovieClip;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.objects.primitives.Cube;

	public class Main extends MovieClip
	{
		public var scene:Scene3D;
		public var cube:Cube;

		public function Main()
		{
			scene = new Scene3D();
			cube = new Cube();
			scene.addChild( cube );
		}
	}
}

Note that we use “addChild()” to add the cube to the scene, just as we do when adding a MovieClip to the Stage.

Step 7: Color the Cube

The above code will give you an error if you try to run it. That’s because we haven’t told the cube what its face surfaces should look like.

Papervision uses materials to describe how a surface looks. We can make a very simple, single-colored material using a ColorMaterial:

var grayMaterial:ColorMaterial = new ColorMaterial( 0xCCCCCC );

The “0xCCCCCC” represents the color gray; just take the color code of any color and replace the # with 0x:

color code for gray

Because a cube has six faces, we need to give it six materials. To do this we put all six in a list:

var materialsList:MaterialsList = new MaterialsList();
materialsList.addMaterial( grayMaterial, "front" );
materialsList.addMaterial( grayMaterial, "back" );
materialsList.addMaterial( grayMaterial, "left" );
materialsList.addMaterial( grayMaterial, "right" );
materialsList.addMaterial( grayMaterial, "top" );
materialsList.addMaterial( grayMaterial, "bottom" );

…and then pass that list to the cube when we create it:

cube = new Cube( materialsList );

So, your whole code should end up looking like this: (don’t forget the import statements!)

package
{
	import flash.display.MovieClip;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.objects.primitives.Cube;
	import org.papervision3d.materials.ColorMaterial;
	import org.papervision3d.materials.utils.MaterialsList;

	public class Main extends MovieClip
	{
		public var scene:Scene3D;
		public var cube:Cube;

		public function Main()
		{
			var grayMaterial:ColorMaterial = new ColorMaterial( 0xCCCCCC );
			var materialsList:MaterialsList = new MaterialsList();
			materialsList.addMaterial( grayMaterial, "front" );
			materialsList.addMaterial( grayMaterial, "back" );
			materialsList.addMaterial( grayMaterial, "left" );
			materialsList.addMaterial( grayMaterial, "right" );
			materialsList.addMaterial( grayMaterial, "top" );
			materialsList.addMaterial( grayMaterial, "bottom" );

			scene = new Scene3D();
			cube = new Cube( materialsList );
			scene.addChild( cube );
		}
	}
}

Step 8: Add a Camera

So we’ve got no errors, but in order to see anything, we need to add a camera to the scene. We’ll see everything through the camera’s “lens”.

Adding a camera is just as simple as adding a cube – simpler, in fact, as we don’t have to addChild() it to the scene:

import org.papervision3d.cameras.Camera3D;
public var camera:Camera3D;
scene = new Scene3D();
cube = new Cube( materialsList );
scene.addChild( cube );
camera = new Camera3D();	//this is the new line in Main()

Now a camera’s on the scene, but it’s not hooked up to any output, so we still can’t see the cube!

Step 9: Add a Viewport and a Renderer

By default, the cube is placed right smack in the middle of the scene (at x=0, y=0, z=0), and the camera is positioned 1000 units back from it (at x=0, y=0, z=-1000).

How can we get the image that the camera sees into the Flash Player window?

How to link camera to stage?

The answer is, we use a viewport. This is a type of DisplayObject, like a MovieClip, so we can addChild() it to the stage. But we can also make Papervision render (i.e. draw) the camera’s view to this viewport – it’s a bit like having an artist draw what he can see through a camera lens, then taking his drawing and sticking it to a TV set. Except faster.

So we need to create a viewport and a renderer:

import org.papervision3d.view.Viewport3D;
import org.papervision3d.render.BasicRenderEngine;
public var viewport:Viewport3D;
public var renderer:BasicRenderEngine;
//put this at the end of Main()
viewport = new Viewport3D();
viewport.autoScaleToStage = true;	//this will make the viewport as big as the stage
addChild( viewport );
renderer = new BasicRenderEngine();

Step 10: Render the Scene

Now all we need to do is make the renderer do the actual rendering. For this, it needs to know the scene, the camera, and the viewport:

renderer.renderScene( scene, camera, viewport );

At last! We can finally test out the SWF. Drum roll, please…

The Incredible gray Square, ladies and gentlemen

Incredible! Astounding! OK fine, it’s actually quite lame. How can we even tell it’s a cube? It looks like a square.

Step 11: Rotate the Cube

If we rotate the cube, we’ll be able to tell whether it’s actually a cube or not.

Since the cube is in three dimensions, the word “rotate” is a little confusing – which direction do we mean? We need to specify whether we’re rotating around the x-axis, y-axis, or z-axis.

The Cube object has three properties we can use to define this, called (unsurprisingly) rotationX, rotationY and rotationZ. Let’s change a couple of them:

scene = new Scene3D();
cube = new Cube( materialsList );
cube.rotationX = 25;	//change rotation
cube.rotationY = 40;	//change rotation
scene.addChild( cube );
camera = new Camera3D();
The Incredible gray CUBE, ladies and gentlemen

It’s better, but since all the faces are exactly the same color, they just merge into each other. Let’s fix that.

Step 12: Reskin the Cube

Instead of gray, I’m going to paint the sides with the ActiveTuts+ logo.

If you’re using the Flash IDE, create a new movie clip and draw or paste the image you’d like to use. I’ve included the logo in my FLA’s library inside the zip.

Right-click your movie clip and select Properties. Check “export for ActionScript” and give it a Class name. This will let you access it using code. (If you’re not using the Flash IDE, the zip also contains a SWC with a MovieClip called ActiveTutsLogo that you can use. Or, you can create a new MovieClip in code and add your image to it. I’m not going to go into the details of that here, though.)

Instead of a ColorMaterial we’re going to use a MovieMaterial, and instead of specifying a color, we’ll specify a movie clip. So replace this:

var grayMaterial:ColorMaterial = new ColorMaterial( 0xCCCCCC );
var materialsList:MaterialsList = new MaterialsList();
materialsList.addMaterial( grayMaterial, "front" );
materialsList.addMaterial( grayMaterial, "back" );
materialsList.addMaterial( grayMaterial, "left" );
materialsList.addMaterial( grayMaterial, "right" );
materialsList.addMaterial( grayMaterial, "top" );
materialsList.addMaterial( grayMaterial, "bottom" );

…with this:

var logoMaterial:MovieMaterial = new MovieMaterial( new ActiveTutsLogo() );
//replace "ActiveTutsLogo" above with the Class name of your movie clip
var materialsList:MaterialsList = new MaterialsList();
materialsList.addMaterial( logoMaterial, "front" );
materialsList.addMaterial( logoMaterial, "back" );
materialsList.addMaterial( logoMaterial, "left" );
materialsList.addMaterial( logoMaterial, "right" );
materialsList.addMaterial( logoMaterial, "top" );
materialsList.addMaterial( logoMaterial, "bottom" );

You’ll also need to import the MovieMaterial:

import org.papervision3d.materials.MovieMaterial;

Test it again:

Dented cube

Well, it works, but it looks a little dented.

Step 13 (Optional): Remove the Dents

The “dented” look is because Papervision is set by default to draw things quickly rather than accurately. I want to make sure this tutorial will run on slower computers, so I’m going to leave it at that, but here’s how you can improve it:

When you create the cube, you can pass it parameters to define how many segments each face is split up in to. The more segments you choose, the more accurate the cube looks – but the slower it gets rendered.

I’ve found that 10 is a good number of segments to use in each direction. Here’s how code for that looks:

cube = new Cube( materialsList, 500, 500, 500, 10, 10, 10 );

The fifth, sixth and seventh parameters define the number of segments used in each direction. To set them, though, we have to specify all the parameters before the fifth as well.

We’re already specifying the first parameter – that’s the material list. The second, third and fourth parameters define the width, depth and height of the cube. These are set to 500 by default, so I’ve kept them the same here.

If you use the above line of code, your cube will look like this:

Smart cube

Much neater!

Step 14: Make the Cube Spin

We can make a regular MovieClip spin around by increasing its rotation property every frame – and of course, we can do the same with the cube and its rotationX/Y/Z values.

Create an ENTER_FRAME event listener, which will run every frame:

import flash.events.Event;
//at the bottom of Main()
addEventListener( Event.ENTER_FRAME, onEnterFrame );
//as a new function
//inside the Main class but outside the Main() function
public function onEnterFrame( evt:Event ):void
{
	cube.rotationX = cube.rotationX + 5;
	cube.rotationY = cube.rotationY + 5;
}

This will make the cube turn a little bit more each frame. So if you test the SWF out now… the cube will stay completely still. Huh?

Step 15: Re-render the Scene Every Frame

Think back to the painter. We’re still looking at his old picture – we need him to draw us a new one every frame, or we won’t see any changes!

So, modify the onEnterFrame() function:

public function onEnterFrame( evt:Event ):void
{
	cube.rotationX = cube.rotationX + 5;
	cube.rotationY = cube.rotationY + 5;
	renderer.renderScene( scene, camera, viewport );
}

Check it out now:

Step 16: Add More Cubes

One cube’s great, but as Roman already showed you how to do that with Away3D, let’s take things a bit further.

Let’s add a few more, to form a horizontal line of cubes. We can use a simple for loop to do that; just replace this code:

cube = new Cube( materialsList );
cube.rotationX = 25;	//change rotation
cube.rotationY = 40;	//change rotation
scene.addChild( cube );

…with this:

for ( var i:int = -1; i <= 1; i++ )
{
	cube = new Cube( materialsList );
	cube.x = i * 350;
	cube.rotationX = 25;	cube.rotationY = 40;	scene.addChild( cube );
}

Note that I'm making the x-position of each cube depend on how far we are through the loop. If you run this, you'll get the following:

Weird

Step 17: Shrink the Cubes

Whoops, the cubes are too close together. We can shrink them to get around this; just change the scale property of each cube:

for ( var i:int = -1; i <= 1; i++ )
{
	cube = new Cube( materialsList );
	cube.x = i * 350;
	cube.scale = 0.40;	//make the cubes 40% of original size
	cube.rotationX = 25;
	cube.rotationY = 40;
	scene.addChild( cube );
}
One odd cube

Step 18: Add the Cubes to an Array

So that fixes the intersection problem, but only one of our cubes is spinning. How come?

It's because the cube variable always refers only to the last cube created - and our onEnterFrame() function only changes the rotations of that one cube.

So to fix this, we'll need an Array. Just as our materials list stored several materials, our Array will store several cubes.

public var cubeArray:Array;
cubeArray = new Array();	//create the new Array
for ( var i:int = -1; i <= 1; i++ )
{
	cube = new Cube( materialsList );
	cube.x = i * 350;
	cube.scale = 0.40;
	cube.rotationX = 25;
	cube.rotationY = 40;
	scene.addChild( cube );
	cubeArray.push( cube );	//add the new cube to the array
}

("Push" just means "add to the end of the list".)

Step 19: Make All the Cubes Spin

Now that every cube is in the Array, we can loop through the Array each frame and rotate each of them:

public function onEnterFrame( evt:Event ):void
{
	for each ( cube in cubeArray )
	{
		cube.rotationX = cube.rotationX + 5;
		cube.rotationY = cube.rotationY + 5;
	}
	renderer.renderScene( scene, camera, viewport );
}

The "for each" loop makes the cube variable refer to each cube in turn, one at a time, rather than just to the last cube created as it did before. Here's the result:

Three cubes in a row

Success!

Step 20: Make a Square of Cubes

We've made a line of cubes, so a square isn't going to be difficult. Instead of just making three cubes, we'll make three lines of three cubes.

To do this, we can use a loop-within-a-loop, like so:

for ( var i:int = -1; i <= 1; i++ )
{
	for ( var j:int = -1; j <= 1; j++ )	//loop inside a loop
	{
		cube = new Cube( materialsList );
		cube.x = i * 350;
		cube.y = j * 350;	//don't forget to change j!
		cube.scale = 0.40;
		cube.rotationX = 25;
		cube.rotationY = 40;
		scene.addChild( cube );
		cubeArray.push( cube );
	}	//don't forget this closing bracket either
}

Test it out:

Square of cubes

Nice. And note that we didn't have to change the code inside onEnterFrame() at all; the loop that runs every frame just rotates every cube inside the Array - and we're still pushing every single cube onto the Array.

Step 21: Make a Cube of Cubes

Well, it'd be disappointing to stop at a square, wouldn't it? After all, this is a 3D tutorial.

I expect you can figure out how to do this step on your own. But in case you want to compare:

for ( var i:int = -1; i <= 1; i++ )
{
	for ( var j:int = -1; j <= 1; j++ )
	{
		for ( var k:int = 0; k <= 2; k++ )
		{
			cube = new Cube( materialsList );
			cube.x = i * 350;
			cube.y = j * 350;
			cube.z = k * 350;
			cube.scale = 0.40;
			cube.rotationX = 25;
			cube.rotationY = 40;
			scene.addChild( cube );
			cubeArray.push( cube );
		}
	}
}

I've been a bit sneaky here. I've started k at 0 instead of at -1, because otherwise the front-most layer of cubes would be too close to the camera. Of course, you can use whichever numbers you like.

Hey, did you notice that the "dented" effect has basically vanished now that we're using smaller cubes?

Cube of cubes

Awesome!

Further Ideas to Try

This is only scratching the surface of what you can do with Papervision3D. Before we move on to 3D glasses, here's a few things you could experiment with:

  • Moving the cubes, instead of rotating them: you can just alter the x, y and z properties of each cube.
  • Replacing the cubes with spheres: if you import org.papervision3d.objects.primitives.Sphere you can use the Sphere class. Check out the docs on this here.
  • Controlling the camera with the mouse: you can get the mouse's x- and y-position at any time with the mouseX and mouseY properties. You can move the camera by changing its x, y and z properties. Why not link the two together?

To Be Continued...

In the second part, you'll learn how to make your scene work with 3D glasses. So if you have a pair, don't throw them away!

In the meantime, thanks for reading the first part. I hope you found it useful. If you've got any questions, or if anything was confusing, please post a comment below.


Other parts in this series:Journey to the Next Dimension With Papervision3D: Part 2»

Add Comment

Discussion 27 Comments

  1. André says:

    This is one of the most cool effect here, i work with anaglyph images too, it seems that you will create a yellow/cyan, would be nice also you teach the red/blue (wich is the most used)

    Thanks a lot

    • MichaelJW says:

      Cheers André :)

      Yep, I’m going to be focusing on the yellow/cyan because that’s the only kind of glasses I have with me. (Plus, I don’t think the orange logo would work too with with a red lens.)

      But I am going to explain how the whole thing works, so you can use any two-colour set of glasses you like — I just can’t test other combinations out myself.

      • André says:

        I´ve tested here, the red logo works fine with red/blue glasses.

        I dont know in other countries if the candy “tic tac” are selling, but here in Brazil a good way to create your own glasses is to buy a cherry tic tac and an extra strong mint tic tac, one have the packaging red and the other blue, also has a consistent packaging, it works very fine for me. Remembering that the red lens need to be over the left eye, and the blue over the right eye

      • André says:

        For red and yellow lens:
        http://candyaddict.com/blog/candy_images/tictac_summeredition.jpg

        And for red an cyan lens:
        http://www.brandweek.com/bw/photos/stylus/46287-TicTac-2packs.jpg

        Hehehe, it´s a nice and candy way to build your own anaglyph glasses

      • MichaelJW says:

        Haha André that’s brilliant! I’ll put that tip in the second part :)

        What kind of anaglyph work do you do?

      • André says:

        I work with anaglyph pictures and in 3D studio max too, but i have only one camera with single lens, so you know, about 10 pictures to create one good anaglyph image, and cant catch anything in movement.

        I usually use my anaglyph images in ads on magazines, but also some prodoct demonstration for clients, but created in 3D studio max.

        Thanks for your tutorial, this is the first time in years of flash that i see flash interacting with anaglyph, and the better, dynamically, i cant wait for second part.

  2. mutiu says:

    thank you for this…. I’ll be waiting for the second part

  3. lu_manjos says:

    Muito BOM!!!

  4. Ben says:

    Awesome ressource, thank you!

  5. This is a tutorial that is very interesting because I know the type new software to create designs .. thanks for tutorials you are all very good and a lot of new tutorials here..

  6. Mando says:

    thanks from germany….

    great tutorial….

  7. Phil says:

    Thanks for the turorial. Great!

    Greetings from Holland

  8. fatih says:

    really cool tut.thanks from turkey :D

  9. Wesley says:

    I want to turn mine in to a dice, but I can’t get it to show differnt faces

    var dice1Material:MovieMaterial = new MovieMaterial( new Dice1() );
    var dice2Material:MovieMaterial = new MovieMaterial( new Dice2() );
    var dice3Material:MovieMaterial = new MovieMaterial( new Dice3() );
    var dice4Material:MovieMaterial = new MovieMaterial( new Dice4() );
    var dice5Material:MovieMaterial = new MovieMaterial( new Dice5() );
    var dice6Material:MovieMaterial = new MovieMaterial( new Dice6() );
    //replace “ActiveTutsLogo” above with the Class name of your movie clip
    var materialsList:MaterialsList = new MaterialsList();
    materialsList.addMaterial( dice1Material, “front” );
    materialsList.addMaterial( dice2Material, “back” );
    materialsList.addMaterial( dice3Material, “left” );
    materialsList.addMaterial( dice4Material, “right” );
    materialsList.addMaterial( dice5Material, “top” );
    materialsList.addMaterial( dice6Material, “bottom” );

    thanks

  10. Incredible Michael is like Avatar movie :), I have my 3d glasses for begin to try this effects. Thanks.

  11. dards says:

    :) the one used in Avatar is polarized type eye glasses not anaglyph, Michael when will you write the second part? did you used two pair of camera object also? this is really cool, now the papervision3d will become a real 3d.

  12. priyesh sheth says:

    Awesome, gr8 tutorial

  13. Jimmy says:

    I got this error below

    TypeError: Error #1009: Cannot access a property or method of a null object reference.
    at Main()

    Any ideas? I would greatly appreciate it .

  14. Steven Thomas says:

    Hey Michael,

    Is that a way to make the camera move 360 degree in real time or pre rendered?

    Thx

    • Author

      Sure! If you’re just dealing with one camera, as in this part of the tutorial, it’s pretty simple: just alter the camera object’s x, y, and z properties, along with its rotationX, rotationY, and rotationZ properties. It gets trickier in Part 2 as you have to keep the two cameras next to each other.

  15. William says:

    I keep getting this error:

    1172: Definition org.papervision3d.materials:ColorMaterial could not be found.

    when I try to test any movie…but if i open the SWF file directly, i runs…what do I do?

Add a Comment

To add a code snippet to your comment, please wrap your code like so: <pre name="code" class="html">YOUR CODE</pre>. You can replace the class name with "js," "css," "sql," or "php." If there are any "<" or ">" within your code, please search and replace them with: &lt; and &gt; respectively.