The Elusive Torus – Papervision

Intro

I’ve been waiting for a torus primitive to magically appear in Papervision since version 1.7. And it didn’t happen – so I wrote one. Or better yet, I ported the Away3D torus over to Papervision. Thanks Away3D! I’ve always thought that Away3D had a more advanced approach to their primitive set (than Papervision) and this torus port proves it.

The port is actually (almost) set up so it can be generalized to accept any set of parametric equations with two parameters. I have not generalized it, but with a few lines of code you’re there.

I have to thank Gabriel Putnam once again, he had created the geodesic sphere (shown in the previous post) in both Papervision and Away3D and I was able to look at what he did and do the same thing for the torus.

The elusive Torus

The Elusive Torus

Discussion

Here are the steps you need to take to port the Away3D torus over to Papervision:

  • Place the Away3D Torus primitive in the Papervision 0rg/papervision3d/objects/primitives folder
  • Change the package statement to package org.papervision3d.objects.primitives
  • Replace the Sand3D imports with the appropriate Papervision imports

import org.papervision3d.core.*;
import org.papervision3d.core.proto.*;
import org.papervision3d.core.geom.*;
import org.papervision3d.core.geom.renderables.Triangle3D;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.math.NumberUV;

  • Delete use namespace arcane
  • Add super(material, new Array(), new Array(), null); to the constructor method
  • Add to the buildTorus method the following lines of code:

this.geometry.ready = true;
var aVertice:Array = this.geometry.vertices;
var aFace:Array = this.geometry.faces;
var aUV:Array = new Array();

  • Add aVertice.push(grid[i][j]); to the parametric vertex generation under the if (yUp) statement
  • Change createVertex to Vertex3D
  • Change all Vertex Type declarations to Vertex3D
  • Change all UV Type declarations to NumberUV
  • Replace

addFace(createFace(a, b, c, null, uva, uvb, uvc));
addFace(createFace(d, c, b, null, uvd, uvc, uvb));

with

aFace.push( new Triangle3D( this, [a, b, c], material, [uva, uvb, uvc])); aFace.push( new Triangle3D( this, [d, c, b], material, [uvd, uvc, uvb]));

  • Delete all non-contributing statements (this is pretty easy if you are editing in Flex – just delete the statements that give you an error when you run the torus program)

This post demonstrates how easy it is to port from Away3D, and sets the framework for creating a generalized parametric primitive.

To see the entire torus primitive and its wrapper, click the more button below

Torus Primitive

package org.papervision3d.objects.primitives
{
import org.papervision3d.core.*;
import org.papervision3d.core.proto.*;
import org.papervision3d.core.geom.*;
import org.papervision3d.core.geom.renderables.Triangle3D;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.math.NumberUV;

public class Torus extends TriangleMesh3D
{

private var grid:Array;
private var _radius:Number;
private var _tube:Number;
private var _segmentsR:int;
private var _segmentsT:int;
private var _yUp:Boolean;

public function Torus( material:MaterialObject3D=null, radius:Number=100, tube:Number=50, segmentsR:int=8, segmentsT:int=6, yUp:Boolean=true)
{
super( material, new Array(), new Array(), null );

this._radius = radius;
this._tube = tube;
this._segmentsR = segmentsR;
this._segmentsT = segmentsT;
this._yUp = yUp;

buildTorus(_radius, _tube, _segmentsR, _segmentsT, _yUp);

}

private function buildTorus(radius:Number, tube:Number, segmentsR:int, segmentsT:int, yUp:Boolean):void
{
this.geometry.ready = true;

var i:int;
var j:int;

var aVertice:Array = this.geometry.vertices;
var aFace:Array = this.geometry.faces;
var aUV:Array = new Array();

grid = new Array(segmentsR);
for (i = 0; i < segmentsR; i++)
{
grid[i] = new Array(segmentsT);
for (j = 0; j < segmentsT; j++)
{
var u:Number = (i / segmentsR) * 2 * Math.PI;
var v:Number = (j / segmentsT) * 2 * Math.PI;

if (yUp){
grid[i][j] = new Vertex3D((radius + tube*Math.cos(v))*Math.cos(u), tube*Math.sin(v), (radius + tube*Math.cos(v))*Math.sin(u));
aVertice.push(grid[i][j]);
}else{
grid[i][j] = new Vertex3D((radius + tube*Math.cos(v))*Math.cos(u), -(radius + tube*Math.cos(v))*Math.sin(u), tube*Math.sin(v));
aVertice.push(grid[i][j]);
}}
}

for (i = 0; i < segmentsR; i++)
for (j = 0; j < segmentsT; j++)
{
var ip:int = (i+1) % segmentsR;
var jp:int = (j+1) % segmentsT;
var a:Vertex3D = grid[i ][j];
var b:Vertex3D = grid[ip][j];
var c:Vertex3D = grid[i ][jp];
var d:Vertex3D = grid[ip][jp];

var uva:NumberUV = new NumberUV(i / segmentsR, j / segmentsT);
var uvb:NumberUV = new NumberUV((i+1) / segmentsR, j / segmentsT);
var uvc:NumberUV = new NumberUV(i / segmentsR, (j+1) / segmentsT);
var uvd:NumberUV = new NumberUV((i+1) / segmentsR, (j+1) / segmentsT);

aFace.push( new Triangle3D( this, [ a, b, c], material, [uva, uvb, uvc]) );

aFace.push( new Triangle3D( this, [d, c, b], material, [uvd, uvc, uvb]) );

}
}

}
}

Wrapper

package
{
//Flash imports
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
//import Papervision
import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.view.BasicView;

//Create Cone class
public class WireTorus extends BasicView
{
//Instantiate Cone and wireframe material
private var cone:Torus;
private var coneMaterial:WireframeMaterial;

public function WireTorus()
{
//Call super class
super(1, 1, true, false);
initPV3D();
startRendering();
}

//
protected function initPV3D():void
{
//Set Stage
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
//Set the background to black
opaqueBackground = 0;
// Create a wireframe material for the Cylinder
coneMaterial = new WireframeMaterial(0xFFFFFF);
coneMaterial.doubleSided=true;
//Add your wireframe to the scene
cone = new Torus(coneMaterial,200,100,10,10);
cone.rotationX=90;
// Add Your Cone to the Scene
scene.addChild(cone);
}

// override onRenderTick so you can execute code
override protected function onRenderTick(event:Event=null):void
{
//Rotate plane around y-axis
cone.pitch(2);
cone.roll(2);
//Call the super.onRenderTick function
super.onRenderTick(event);
}

}
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: