Erain 3D
--> FDT Pure coding comfort


Author: Max Pellizzaro
Date: October 27th 2007
Update: July 12th 2009
version: 3.1.1

Using the Camera

Objective of the tutorial

In this tutorial, we will study the use of the object Camera3D object. In the previous tutorial, we have just used the camera as a view point of the entire scene, but we actually never used it, neither had we gone through its properties or methods.

A Camera3D is just more than a static object – we can move it around, rotate, roll, tilt, and much more.

Knowing that you can move the Camera is very important because sometimes you will face a simple dilemma: should I move my object around or should I move my camera around?

Well, this is my personal advice: if you need to move only one object around, leaving the others in their original positions, move the single object. But if you want to move all the objects around, consider moving only the camera, and nothing else. You will soon discover that it will be easier and more efficient.

For example, if you implement a 3D maze, you can just draw the walls of the maze, and move the camera around to explore the maze.
But let's stop talking and dig into our example. I have decided to move away from the cube and start using other primitives: Line3D and a Torus.

How to

Set up

Remember these few little changes:
The Document class must be changed to Example003.as The name of the class written inside the .as file and the name of the constructor now is: Example003

example003.rar

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

The AS Code

Use the code below for reference. Do not worry if it is not commented – it is being discussed below.

package
{
   import flash.display.Sprite; 
   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.*;

   public class Example003 extends Sprite 
   {
      private var scene:Scene3D;
	  private var camera:Camera3D;

      public function Example003()
      { 
		 // We create the camera
		 camera = new Camera3D( 300, 300 );
		 camera.x = 100;
		 camera.y = 100;
		 camera.z = -400;
		 camera.lookAt(0,0,0);
		 
		 // 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 );
		 stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
		 
      }

      // 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();
		 
		 // first we will create a simple coordinate system
		 var myXLine:Line3D = new Line3D( "x-coord", new Point3D(-50, 0, 0), new Point3D( 50, 0, 0 ));
		 var myYLine:Line3D = new Line3D( "y-coord", new Point3D(0, -50, 0), new Point3D( 0, 50, 0 ));
		 var myZLine:Line3D = new Line3D( "z-coord", new Point3D(0, 0, -50), new Point3D( 0, 0, 50 ));
		 
		 
         // Create a torus so we have something to show
         var torus:Torus = new Torus( "theTorus", 120, 20);
		 
		 
		 // we define a new material
		 var materialAttr:MaterialAttributes = new MaterialAttributes( 
				new LineAttributes( 0.5, 0x2111BB, 0.4 ),
				new LightAttributes( true, 0.1)
				);

	     var material:Material = new ColorMaterial( 0xFFCC33, 1, materialAttr );
	     material.lightingEnable = true;
	     var app:Appearance = new Appearance( material );

	     torus.appearance = app;
		 
		  torus.rotateX = 30;
		  torus.rotateY = 30;
		 
		  // We need to add the cube to the group
		 g.addChild(myXLine);
		 g.addChild(myYLine);
		 g.addChild(myZLine);
		 g.addChild( torus	 );
          
		  return g;
      }

      // The Event.ENTER_FRAME event handler tells the world to render
      private function enterFrameHandler( event : Event ) : void
      {
         scene.render();
      }
	  
	  private function keyPressed(event:KeyboardEvent):void {
            switch(event.keyCode) {
				case Keyboard.UP:
					camera.tilt +=2;
					break;
				case Keyboard.DOWN:
					camera.tilt -=2;
					break;
				case Keyboard.RIGHT:
					camera.pan -=2;
					break;
				case Keyboard.LEFT:
					camera.pan +=2;
					break;
				case Keyboard.CONTROL:
					camera.roll +=2;
					break;	
				case Keyboard.PAGE_DOWN:
					camera.z -=5;
					break;
				case Keyboard.PAGE_UP:
					camera.z +=5;;
					break;	
			}
        }
   }
}

Examining the code

Now, let’s see what we have changed from the previous tutorial.

Importing the packages

First, we have added some extra import statements in order to use some new classes (If you are not familiar with importing classes and packages, see the Adobe documentation or a third-party book on ActionScript 3.0)

   import flash.display.Sprite; 
   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.*;

Relocating the Camera

camera = new Camera3D( 300, 300 );
//camera.x = 100;
//camera.y = 100;
camera.z = -400;
//camera.lookAt(0,0,0);

In the first Flash swf example below, I'm not using these settings (I have commented them out). You can uncomment them to see their effect. You just need to know that you can move the camera anywhere in the space using its three properties: x, y, z, and you can tell the camera where in the scene to point, using camera.lookAt().

Placing an axis as reference

// first we will create a simple coordinate system
var myXLine:Line3D = new Line3D( "x-coord", new Point3D(-50, 0, 0), new Point3D( 50, 0, 0 ));
var myYLine:Line3D = new Line3D( "y-coord", new Point3D(0, -50, 0), new Point3D( 0, 50, 0 ));
var myZLine:Line3D = new Line3D( "z-coord", new Point3D(0, 0, -50), new Point3D( 0, 0, 50 ));

It is simple to draw the lines–just specify the starting and ending points, which you can define using the Vector class. To make the code simpler to read, I am not attaching any appearance to them, so they will be rendered as solid black lines.

Placing a Torus

var torus:Torus = new Torus( "theTorus", 120, 20);

Some of you might remember this object from geometry. The constructor takes three parameters: the name, the radius of the ring, and the radius of the cross-section of the ring (how thick the tube will be).

Adding the objects to the Group

g.addChild(myXLine);
g.addChild(myYLine);
g.addChild(myZLine);
g.addChild( torus);

Constructing the EventListener

addEventListener( Event.ENTER_FRAME, enterFrameHandler );
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);

The first listener is responsible of the rendering of the entire scene, while the other is responsible to catch user input events: in this case Keyboard Event. (I’ve implemented the KEY_DOWN event, but feel free to implement any event you feel more comfortable. On the web, you can find classes that allows to hide this implementation and gives you static method to catch the key pressed, but I want to give you here the basic concepts that will allow you to understand what is going on, and let you dig in more sophisticated code).

Let’s investigate what does the keyPressed method:

   switch(event.keyCode) {
      case Keyboard.UP:
         camera.tilt +=2;
         break;
      case Keyboard.DOWN:
         camera.tilt -=2;
         break;
      case Keyboard.RIGHT:
         camera.pan -=2;
         break;
      case Keyboard.LEFT:
         camera.pan +=2;
         break;
      case Keyboard.CONTROL:
         camera.roll +=2;
         break;	
      case Keyboard.PAGE_DOWN:
         camera.z -=5;
         break;
      case Keyboard.PAGE_UP:
         camera.z +=5;
         break;	
   }

The keyPressed method takes different actions depending on which key was pressed (the Page Up and Page Down keys won't be recognized during authoring but will be detected properly at runtime). And what it does it just use some properties of the class Camera3D. It’s easy to understand what we are doing, so we just need to see the result live.

The output

We now have something to play with. Remember, for the Flash examples below to receive keyboard focus, you must click the mouse inside the scene. (The thin red border around each Flash example was created in the Flash authoring tool for cosmetic reasons and has nothing to do with the tutorial or Sandy.)

Once a Flash example has keyboard focus, you can use the up, down, right, or left arrow keys to move (translate) the camera in each direction. Use the PageUp and PageDown keys to zoom the camera in and out (translate it in the z direction). Use the control key to rotate the camera.

You are moving the Camera, not the object; the object is stationary, as you can see by the fact that its position is constant relative to the coordinate system.

I think you have got an idea of how the Camera3D works, and now you can play with it.