-->

Previous articles summary :

  • First steps in Papervision3D : Part 1
    Creation of a new Papervision3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Papervision3D classes.
  • First steps in Papervision3D : Part 2
    Illustration of use of new Papervision3D v2.0 class BasicView that encapsulates essential elements to rapidly start developing new 3D scenes.

Now that we are able to render simple 3D scenes, I’d like to add some animation. In the previous parts we saw that the initialisation of Papervision3D and the creation of the scene objects occurred in the constructor of our example classes. To add animation we need to update the scene at regular intervals which is done either by listening to the Event.FRAME_ENTER event as shown in Example001 or overloading the onRenderTick function of BasicView as shown in Example002 (which is in effect an encapsulation of the first option).

This example follows the code shown in Example002, so I’m using the BasicView.

package {
 
  import flash.display.StageAlign;
  import flash.display.StageScaleMode;
  import flash.events.Event;
 
  import org.papervision3d.core.geom.Lines3D;
  import org.papervision3d.core.geom.renderables.Line3D;
  import org.papervision3d.core.geom.renderables.Vertex3D;
  import org.papervision3d.core.proto.MaterialObject3D;
  import org.papervision3d.materials.WireframeMaterial;
  import org.papervision3d.materials.special.LineMaterial;
  import org.papervision3d.objects.primitives.Sphere;
  import org.papervision3d.view.BasicView;

  public class Example003 extends BasicView {
 
    private static const ORBITAL_RADIUS:Number = 200;
   
    private var sphere:Sphere;
    private var theta:Number = 0;
   
    public function Example003() {
      super(0, 0, true, false);
     
      // set up the stage
      stage.align = StageAlign.TOP_LEFT;
      stage.scaleMode = StageScaleMode.NO_SCALE;

      // Initialise Papervision3D
      init3D();
     
      // Create the 3D objects
      createScene();
     
      // Start rendering the scene
      startRendering();
    }
   
    private function init3D():void {

      // position the camera
      camera.x = -200;
      camera.y =  200;
      camera.z = -500;
    }

    private function createScene():void {

      // First object : a sphere
     
      // Create a new material for the sphere : simple white wireframe
      var sphereMaterial:MaterialObject3D = new WireframeMaterial(0xFFFFFF);

      // Create a new sphere object using wireframe material, radius 50 with
      //   10 horizontal and vertical segments
      sphere = new Sphere(sphereMaterial, 50, 10, 10);

      // Position the sphere (default = [0, 0, 0])
      sphere.x = -ORBITAL_RADIUS;

      // Second object : x-, y- and z-axis
     
      // Create a default line material and a Lines3D object (container for Line3D objects)
      var defaultMaterial:LineMaterial = new LineMaterial(0xFFFFFF);
      var axes:Lines3D = new Lines3D(defaultMaterial);

      // Create a different colour line material for each axis
      var xAxisMaterial:LineMaterial = new LineMaterial(0xFF0000);
      var yAxisMaterial:LineMaterial = new LineMaterial(0x00FF00);
      var zAxisMaterial:LineMaterial = new LineMaterial(0x0000FF);

      // Create a origin vertex
      var origin:Vertex3D = new Vertex3D(0, 0, 0);

      // Create a new line (length 100) for each axis using the different materials and a width of 2.
      var xAxis:Line3D = new Line3D(axes, xAxisMaterial, 2, origin, new Vertex3D(100, 0, 0));
      var yAxis:Line3D = new Line3D(axes, yAxisMaterial, 2, origin, new Vertex3D(0, 100, 0));
      var zAxis:Line3D = new Line3D(axes, zAxisMaterial, 2, origin, new Vertex3D(0, 0, 100));
     
      // Add lines to the Lines3D container
      axes.addLine(xAxis);
      axes.addLine(yAxis);
      axes.addLine(zAxis);

      // Add the sphere and the lines to the scene
      scene.addChild(sphere);
      scene.addChild(axes);
    }
   
    override protected function onRenderTick(event:Event=null):void {

      // rotate the sphere
      sphere.yaw(-4);
     
      // change the position of the sphere
      theta += 3;
      var x:Number = - Math.cos(theta * Math.PI / 180) * ORBITAL_RADIUS;
      var z:Number =   Math.sin(theta * Math.PI / 180) * ORBITAL_RADIUS;
      sphere.x = x;
      sphere.z = z;
     
      // call the renderer
      super.onRenderTick(event);
    }

  }
}

As you can see below, we see as before the sphere and the axes, but we have added animation so that the sphere rotates on its z-axis and orbits the origin (click on image to launch animation).


Compared to Example002 shown in Part 2, there are very few differences in the construction of the scene. The initialisation of the 3D is identical except for the position of the camera. The observer is now positioned above the horizontal plane looking down at the scene (the camera is still targeted on the origin). The construction of the 3D objects is also virtually identical : the only difference being the initial position of the sphere.

The real difference comes for overloading the onRenderTick function which is called at every FRAME_ENTER event :

    override protected function onRenderTick(event:Event=null):void {

      // rotate the sphere
      sphere.yaw(-4);
     
      // change the position of the sphere
      theta += 3;
      var x:Number = - Math.cos(theta * Math.PI / 180) * ORBITAL_RADIUS;
      var z:Number =   Math.sin(theta * Math.PI / 180) * ORBITAL_RADIUS;
      sphere.x = x;
      sphere.z = z;
     
      // call the renderer
      super.onRenderTick(event);
    }

As you can see, all that is necessary is to update the rotation and position of the sphere. The yaw function rotates a 3D object around its z-axis. A calculation is performed to convert an angle theta, that we increase at every frame, into x and z coordinates of the sphere. Note that we must call to super.onRenderTick(event) to display the updated scene.

A lot more can be performed at every frame - for example we could reposition the camera as well - but hopefully this gives a simple example showing how easy animation can be in Papervision3D!

Next article:

6 Responses to “First steps in Papervision3D : Part 3 - animation”

Robson said...

Fisrt of all, I’m very thankfull for your tutorials here, It’s been very helpfull in many ways.

Now I’ve got a problem in this part 3: the output gives me a “Error #1009: Cannot access a property or method of a null object reference.” every time, it references the “onRenderTick(event:Event=null)” I guess…

Any ideias of what I’m doing wrong?
thx

tartiflop said...

Hi robson,
Sorry, not sure what the problem is. Try running in debug mode in eclipse/Flex Builder - in the console you should see what line the error occurs at and which object is null.

ed said...

Great tutorials! Thanks!

I believe I also had the same problem as Robson. It was because of this line in createScene()

In Example002, its
var sphere:Sphere = new Sphere(sphereMaterial, 50, 10, 10);

In Example003, it is
sphere = new Sphere(sphereMaterial, 50, 10, 10);
which is correct.

Using the var sphere:Sphere…etc. from Example002 in Example003 creates a local sphere variable for the createScene function, so when sphere is used in onRenderTick it refers to the private sphere class variable which is null.

tartiflop said...

Yes, that would indeed explain the problem! Thanks Ed!

Vitalik said...

Hi … great post … can you say if its posible that the same DisplayObject3D will be add for two different group(DisplayObject3D)&

liuhuan said...

woooooooow, it’s so useful~~ Thanks a lot!

-->