Erain 3D
advert here

Author: Max Pellizzaro
Date: March 9th 2008
version: 3.0.2

First WOW tutorial: Bounding Area and Sphere

Objective of the tutorial

Hi guys, and welcome to a new experience: WOW. If you remember, and if you have followed some of my previous tutorials there is a section called: Advanced motion: tweenings vs dynamic animation. In that set of 4 tutorials we have learned on how to use Tweening class with Sandy, or how to programmatically implement physic with Sandy.
Implementing physic in 3D is very complicated and involves skills and lot of mathematics. WOW is a first try to make easy to implement physic in 3D. It is a 3D engine that needs a rendering engine, and this is where Sandy comes to help. WOW is pretty new and young, and probably there is much to do, but I’m sure we will have fun in learning how to use it in conjunction with Sandy.
In WOW's home page you can find the software to download and some demos. Tutorials are not fully explained and we lack of documentation, but this is the reason of these tutorials: learning how to use WOW in conjunction with Sandy!
In this first tutorial we will learn the first WOW primitives: WBoundArea and WSphere.

How to

Set up WOW

In order to “install” WOW engine, we need to place two different libraries in our pc, the WOW library and the AS3 Data Structures For Game Developers.
You can download them in the WOW’s home page or, you can get them here (for lazy people like me that wants to have all in one place!). Remember that this war archive has been created the same date of this tutorial, future WOW updates will not reported here, so check the home page for latest release.

wow_dslibs.rar

Set up CS3

Now we need to tell CS3 how to use both WOW and AS3 Data Structures For Game Developers. We need to do the same steps we have explained in install_sandy_flash_cs3 when we wanted to tell CS3 to use Sandy. I will report them here and adapt them to WOW.
Unzip the previous war archive in a dedicated folder. In my case my folder is called: E:\max\setup01\WOW. Now we will CS3 to point to that directory. You accomplish this last point following these steps:

The following screenshot should help you to setup CS3 in the right way.

Set up

We are ready for the “real” class now! The main class has been named Example030. And here you will find it …

example030.rar

The AS Code

In this section we report the AS code as a reference, and it will be explained in the next paragraph.

package {  
    
	//flash engine 
	import flash.utils.*;  
	import flash.display.Sprite;  
    import flash.events.*;
	import flash.ui.*;
   
    //wow engine    
    import fr.seraf.wow.primitive.*; 
    import fr.seraf.wow.core.WOWEngine;  
    import fr.seraf.wow.core.data.WVector;  
        
	//sandy engine	 
    import sandy.core.Scene3D;
    import sandy.core.data.*;
    import sandy.core.scenegraph.*;
    import sandy.materials.*;
    import sandy.materials.attributes.*;
    import sandy.primitive.*;
		
		
		public class Example030 extends Sprite {  
        private var wow:WOWEngine;  
		private var sphere01:WSphere;
		private var bound:WBoundArea;
		
		private var sphereS:Sphere;
		private var cube:Box;
		private var scene:Scene3D;
	    private var camera:Camera3D;
	  
           public function Example030() {  
     
               //create an instance of the physic engine    
               wow=new WOWEngine();  
               // SELECTIVE is better for dealing with lots of little particles colliding,    
               wow.collisionResponseMode = wow.SELECTIVE;  
               // gravity -- particles of varying masses are affected the same    
               wow.addMasslessForce(new WVector(0,2,0));  
               //create a sphere    
               sphere01 = new WSphere(0,0,0,25,false,1,1,1);   
               sphere01.elasticity=1;  
			   sphere01.friction=0; 
			   sphere01.py = -150;
			   wow.addParticle(sphere01); 
			   
			   bound = new WBoundArea(190,200,190);  
			   bound.setPosition(0,0,0);  
			   bound.elasticity=1;  
			   bound.friction=0;  
			   wow.setBoundArea(bound);  
			   
			   // Sandy code
			   camera = new Camera3D( 600, 600 );
		       camera.z = -400;
			   var root:Group = createScene();
			   scene = new Scene3D( "scene", this, camera, root );
			  
			  stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressedHandler);
			  stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMovedHandler);
			  addEventListener( Event.ENTER_FRAME, enterFrameHandler );
			  
           }  
		   
		  private function createScene():Group
          {
          // Create the root Group
          var g:Group = new Group();
		 
          // Create a cube so we have something to show
          sphereS = new Sphere( "theSphere", 25,10,10);
		  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 );
		  sphereS.appearance = app;
		  sphereS.useSingleContainer = false;
		  
		  sphereS.x = 0;
		  sphereS.y = 150;
		  sphereS.z = 0;
		 
		  // the box
		  cube = new Box( "theBox", 200, 200, 180, PrimitiveMode.QUAD, 1 );
		  cube.enableBackFaceCulling = false;
		  cube.useSingleContainer = false;
		  
		   // We need to add the cube to the group
		   g.addChild( sphereS );
		   g.addChild(cube);
          
		   return g;
          }
		   
		  
		private function mouseMovedHandler(event:MouseEvent):void {
           cube.rotateZ=(600/2-event.stageX)/15;
		   cube.rotateX=(600/2-event.stageY)/15;
		   bound.setRotation (-(600/2-event.stageY)/15,0,-(600/2-event.stageX)/15);
        }	
		  
		  private function keyPressedHandler(event:KeyboardEvent):void {
            switch(event.keyCode) {
				case Keyboard.SPACE:
				 sphereS.x = 0;
		         sphereS.y = 150;
		         sphereS.z = 0;
				 sphere01.px = 0;
				 sphere01.py = -150;
				 sphere01.pz = 0;
			     break;
			}
		  }
		  
		  private function enterFrameHandler( event : Event ):void {  
             //run the engine once  
             wow.step()
			 //get the position 
			 sphereS.x = sphere01.px;
			 sphereS.y = -sphere01.py;
			 sphereS.z = sphere01.pz;
			 scene.render();
         }  
		   
		   
       }  
   }  

Examining the code

Let’s examine the code.
The first thing you will notice is that I have placed three different import section, so it is clearer what belongs to flash, sandy and wow.

//flash engine 
import flash.utils.*;  
import flash.display.Sprite;  
import flash.events.*;
import flash.ui.*;
 
 //wow engine    
 import fr.seraf.wow.primitive.*; 
 import fr.seraf.wow.core.WOWEngine;  
 import fr.seraf.wow.core.data.WVector;  
 
 //sandy engine	 
  import sandy.core.Scene3D;
  import sandy.core.data.*;
  import sandy.core.scenegraph.*;
  import sandy.materials.*;
  import sandy.materials.attributes.*;
  import sandy.primitive.*;

What we really need to understand is that WOW is a physic engine, and not a rendering engine, so we need to learn how o link WOW's objects properties to Sandy's objects properties.
The correct way to model something is this one:

Let’s walk through each one of these steps.

Create the WOW engine

This task is pretty easy to do, just two lines of code:

//create an instance of the physic engine    
wow=new WOWEngine();  
// SELECTIVE is better for dealing with lots of little particles colliding,    
wow.collisionResponseMode = wow.SELECTIVE;

Let’s spend few words on collisionResponseMode. There are three possible values:

WOWngine.STANDARD
WOWngine.SELECTIVE
WOWngine.SIMPLE

If we read the comment inside the WOWEngine class we will find this explanation: Those settings go in order from slower and more accurate to faster and less accurate. In all cases it's worth experimenting to see what mode suits your simulation best. So try the differences from your own.

Create the WOW objects

In this tutorial we are going to create two objects: a box, a container and a bouncing ball. The box will contain the ball that will bounce depending on the orientation of the box. These two objects in WOW are modeled with what is called a WSphere and a WBoundArea, so the code will look like:

…
sphere01 = new WSphere(0,0,0,25,false,1,1,1);  
…
bound = new WBoundArea(190,200,190);

Let’s examine better the parameters of the two primitives for the sphere the eight parameters represents. We start from the sphere:

And for the WBoundArea is lot easier since it represent the 3 dimension of a box. Both these two primitives also have setter methods that allows to modify the parameters we set in their constructor.
The complete code will look like this:

sphere01 = new WSphere(0,0,0,25,false,1,1,1);   
sphere01.elasticity=1;  
sphere01.friction=0; 
sphere01.py = -150;
…..
bound = new WBoundArea(190,200,190);  
bound.setPosition(0,0,0);  
bound.elasticity=1;  
bound.friction=0;

Now that we have declare the two objects, we need to add them to our engine. This is pretty easy :

wow.addParticle(sphere01);
wow.setBoundArea(bound);

We need to add one more thing to the engine: FORCE. With WOW it is possible, and required, to add a direction and a magnitude of the main force that will model our world. In a normal situation you want to model a gravity, and this is done by adding a force in the Y direction pointing down.

wow.addMasslessForce(new WVector(0,2,0));

You might wonder why the Y value is positive. This is an important thing to remember, the coordinate system between WOW and Sandy are different!! On Sandy the Y axis is pointing up, while on WOW it is pointing down, so keep always this in mind.
We are done with the WOW part so far.

Create the Sandy engine

This is the easy part, since by now you know that far better than me…

camera = new Camera3D( 600, 600 );
camera.z = -400;
var root:Group = createScene();
scene = new Scene3D( "scene", this, camera, root );
Create the Sandy objects

Sandy objects are pretty easy to create, since we just want to create a box that will model the WBoundArea and a Sphere that will model the WSphere.
In principle the same values used to create the WOW objects should be the same as the values we will use to create the Sandy objects. BUT, my eyes, my visual feeling tells me that sometimes the two values might different of some unit just to have a better effect. Try to play with them and you will find your best match.

…
sphereS = new Sphere( "theSphere", 25,10,10);
…
sphereS.x = 0;
sphereS.y = 150;
 sphereS.z = 0;
 
 // the box
 cube = new Box( "theBox", 200, 200, 180, PrimitiveMode.QUAD, 1 );
 
…
How to link Sandy objects and WOW objects

It’s now time to link WOW objects to Sandy objects. We do this in two places: when we rotate the box and when we bounce the ball. Let’s see the first link:

private function mouseMovedHandler(event:MouseEvent):void {
   cube.rotateZ=(600/2-event.stageX)/15;
   cube.rotateX=(600/2-event.stageY)/15;
   bound.setRotation (-(600/2-event.stageY)/15,0,-(600/2-event.stageX)/15);
}

As you can see the rotation of the cube is synchronized to the rotation of the BoundArea. The second link is between the WOW Sphere and the Sandy Sphere. Here it is:

private function enterFrameHandler( event : Event ):void {  
 
//run the engine once  
wow.step()
 
//get the position 
sphereS.x = sphere01.px;
sphereS.y = -sphere01.py;
sphereS.z = sphere01.pz;
 scene.render();
 
 }

This is it! Let’s see our result now.

The output

Use the mouse to modify the orientation of the cube. Use the space bar to reset the position of the ball.