Erain 3D
--> FDT Pure coding comfort


Author: Max Pellizzaro
Date: June 3rd 2009
version: 3.1.1

Mode7 and camera properties

Objective of the tutorial

Hello everyone, in this tutorial we will talk about the use of a new cool feature called: Mode7! Basically this new feature will allow you to render/model situation where you need to have infinitive floor. There are other tutorials that have model a similar situation like Tutorial 15 that use a sequence of plane3D or like Tutorial 21 that use bitmap properties. The Mode7 is a new approach to model infinitive floor. As always, there is no a better approach, it always depends on what do you want to model, but it is good to know different ways to model similar situations.
Since using this new feature is pretty simple, I have decide to add to this tutorial some “camera” notions that will help understanding basic camera properties that sometimes people don't know much.
well let's begin.

How to

Set up

This tutorial has been developed using CS3, so if you want to see and debug the tutorial you must use CS3 as well. Basically I import images and use some visual components (sliders and check box). It will not be difficult to code them in AS3 as well, but sometimes I like to use shortcuts
All the required files can be found here:

example028.zip

The AS Code

package
{
   import flash.display.*; 
   import flash.events.*;
   import flash.ui.*;
   import sandy.core.Scene3D;
   import sandy.core.data.*;
   import sandy.core.scenegraph.*;
   import sandy.core.scenegraph.mode7.*;
   import sandy.materials.*;
   import sandy.materials.attributes.*;
   import sandy.primitive.*;
   import flash.text.*;
   import fl.controls.Slider;
   import fl.controls.CheckBox;
   

   public class Example028 extends Sprite 
   {
      private var scene:Scene3D;
	  private var camera:CameraMode7;
	  private var tg:TransformGroup;
	  private var myCone:Cone;
	  private var myHedra:Hedra;
	  private var mode7:Mode7;
	  private var street:BitmapData = new Street (0,0);
	  private var green:BitmapData = new Field (0,0);
	  private var sea:BitmapData = new Sea (0,0);
	  private var near:Number=1;
	  private var far:Number=10000;
	  private var slider1:Slider = new Slider();
	  private var slider2:Slider = new Slider();
	  private var slider3:Slider = new Slider();
	  private var myText1:TextField = new TextField();
	  private var myText2:TextField = new TextField();
	  private var myText3:TextField = new TextField();
	  private var check1:CheckBox = new CheckBox();
	  private var check2:CheckBox = new CheckBox();
	  
	  
      public function Example028()
      { 
		 // We want to add some slider on the left side
		 slider1.x=7;
		 slider1.y=22;
		 slider1.minimum = 10;
		 slider1.maximum = 180;
		 slider1.value = 45;
		 slider1.focusEnabled=false;
		 slider1.liveDragging=true;
		 
		 slider1.addEventListener( Event.CHANGE, sliderHandler );
		 myText1.x = 40;
		 myText1.y = 7;
		 myText1.text = "45";
		 addChild(myText1);
		 addChild(slider1);
		
		 // We want to add some slider on the left side
		 slider2.x=100;
		 slider2.y=22;
		 slider2.minimum = 1;
		 slider2.maximum = 500;
		 slider2.value = 1;
		 slider2.focusEnabled=false;
		 slider2.liveDragging=true;
		 
		 slider2.addEventListener( Event.CHANGE, sliderHandler );
		 myText2.x = 140;
		 myText2.y = 7;
		 myText2.text = "1";
		 addChild(myText2);
		 addChild(slider2);
		 
		 
		  // We want to add some slider on the left side
		 slider3.x=190;
		 slider3.y=22;
		 slider3.minimum = 1000;
		 slider3.maximum = 10000;
		 slider3.value = 10000;
		 slider3.focusEnabled=false;
		 slider3.liveDragging=true;
		 
		 slider3.addEventListener( Event.CHANGE, sliderHandler );
		 myText3.x = 230;
		 myText3.y = 7;
		 myText3.text = "10000";
		 addChild(myText3);
		 addChild(slider3);
		 
		 check1.x = 275;
		 check1.y = 12;
		 check1.label = "near_far";
		 check1.selected=true;
		 addChild(check1);
		 check1.addEventListener( Event.CHANGE, sliderHandler);
		 
		 check2.x = 350;
		 check2.y = 12;
		 check2.label = "repeatMap";
		 check2.selected=false;
		 addChild(check2);
		 check2.addEventListener( Event.CHANGE, sliderHandler);
		 
		 ///-------////
		 
		 // We create the camera
		 camera = new CameraMode7( 550, 400);
		 camera.x = 0;
		 camera.y = 200;
		 camera.z = -1000;
		 camera.lookAt(0,50,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();
		 
		 mode7 = new Mode7();
	     mode7.setBitmap ( green );
		 mode7.setHorizon (true, 0x000000, 1);
		 mode7.setNearFar(true);
		 mode7.repeatMap = false;
		 
		 // we now create the two new objects
		 myCone = new Cone("theObj1",50, 100);
		 myHedra = new Hedra( "theObj2", 80, 60, 60 );
		 
		 myCone.x = -160;
		 myCone.z = 150;
		 myHedra.x = 90;
		 
		  
		 g.addChild( mode7 );
		 g.addChild(myCone);
		 g.addChild(myHedra);
		  
		 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.z=camera.z+100;
					break;
				case Keyboard.DOWN:
					camera.z=camera.z-100;;
					break;
				case Keyboard.RIGHT:
					camera.x=camera.x+10;
					break;
				case Keyboard.LEFT:
					camera.x=camera.x-10;
					break;
			}
        }
		
	  private function sliderHandler(event : Event):void{
		  myText1.text = new String(slider1.value); 
		  camera.fov = slider1.value;
		  myText2.text = new String(slider2.value);
		  camera.near = slider2.value;
		  myText3.text = new String(slider3.value);
		  camera.far = slider3.value;
		  mode7.setNearFar(check1.selected);
		  mode7.repeatMap = check2.selected;
		  
	  }	
   }
}

Be aware that this code will not compile outside a CS3 env since it uses fl.controls.* components.

Examining the code

Let's examining the code. I will omit the GUI components since they are not really part of this tutorial, they only help to modify properties values (but is it not difficult to understand how to set them up correctly). Let's begin by the first difference with all the other Sandy tutorials: the camera:

camera = new CameraMode7( 550, 400);
camera.x = 0;
camera.y = 200;
camera.z = -1000;
camera.lookAt(0,50,0);

Other than using this new camera: CameraMode7, there is no much difference. As the documentation says: “CameraMode7 behaves like Camera3D, but with some constraints: - rotations are available only by the rotateY and tilt methods (other are desactivated) - the lookAt method is overrided to respect the available rotations”.

Now if we want to add the Mode7 element it is pretty easy:

mode7 = new Mode7();
mode7.setBitmap ( green );
mode7.setHorizon (true, 0x000000, 1);
mode7.setNearFar(true);
mode7.repeatMap = false;

The object called green is is just the Bitmap that represent our floor. In this tutorial is have been imported in the fla stage, but you can always decide to load it at run time.
The Horizon element allows you to draw a line at the horizon of your scene.
So far we are done, but I want to explore some basic properties that you might find useful to learn how to use them. The properties we are going to learn are:

Let's see the definition of all of them, but then a good demo is the best thing, as always.

The first three properties are related to Camera Objects:
fov: The angle of view of this camera in degrees.
near: Near plane distance for culling/clipping
far: Far plane distance for culling/clipping.

The last two setting are related to the Mode7 Object:
near_far: setNearFar property of Mode7 object
repeatMap: allows to repeat the bitmap used for the floor

And now let’s see the result !

The output

Use arrow key to move around the football field :)