CS4 Super Primitive using Matrix3D

Intro

After creating a million custom primitives in Papervision3D, I have always wanted to create just one that did it all using parametric equations. But many of the algorithms used to generate the basic primitives in Papervision3D (Away3D is a little better) are so complicated that its hard to bring them altogether under one roof.

It’s something you need to do from the start. And with many thanks to Petri Leskinen (and a little recoding on my part) we can now do that as shown in the figure below.

Super Prim - Plane, Cylinder, Cone, Sphere, Half Torus

Super Prim - Plane, Cylinder, Cone, Sphere, Half Torus

Earth Map Courtesy of NASA/JPL-Caltech

Demo

Source

Petri on his blog Pixelero (http://pixelero.wordpress.com/) created a globe example which uses the parametric eqautaions of a sphere.

// polar coordinate:
var vc:Vector3D = new Vector3D(
Math.cos(iy)*Math.cos(ix),
Math.sin(iy),
Math.cos(iy)*Math.sin(ix)

);

// In the case of a sphere the normal is so easy:
vertexNormals.push(vc);

// the coordinate, scaled by radius
vertices.push(radius*vc.x, 1.05*radius*vc.y, radius*vc.z);

With a little recoding I was able to integrate a switch case and timer which iterates through the parametric equations of a plane, cylinder, cone, sphere, and half torus.

switch (number) {
case 0:
//Plane
paraVec = new Vector3D(-.5*(2-ix), .5*(iy),0);
break;
case 1:
//Cylinder
paraVec = new Vector3D(
Math.cos(ix), iy, Math.sin(ix));
break;
case 2:
//Cone
paraVec = new Vector3D(
(iy)*Math.cos(ix), Math.sin(iy), (iy)*Math.sin(ix));
break;
case 3:
//Sphere
paraVec = new Vector3D(
Math.cos(iy)*Math.cos(ix), Math.sin(iy), Math.cos(iy)*Math.sin(ix));
break;
case 4:
//Torus
paraVec = new Vector3D(
(1+.4*Math.cos(iy))*Math.cos(ix), .4*Math.sin(iy), (1+.4*Math.cos(iy))*Math.sin(ix));
break;
default:
trace ( ” no case tested true ” )
}

The heart of the code runs on the Matrix3D class which does all the perspective scaling for you automatically. This is all explained in the book and its accompanying videos.

To see the complete code, click the more button below.

Generalized (Super) Primitive

package {

import flash.display.*;
import flash.geom.*;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;

public class GeneralizedPrimitive extends Sprite {
//Embed your texture
[Embed(source=”worldmapCourtesyNASAJPL.jpg”)]
private var YourImage:Class;
//Primitive Declarations
private var primitive:Sprite;
private var myTimer:Timer;
private var myCount:int=0;
private var paraVec:Vector3D;
private var bitmapData:BitmapData;
private var rows:int=32;
private var cols:int=16;
private var ix:Number;
private var iy:Number;
//Elliptical Parameters
private var radx:Number=1;
private var rady:Number=1;
private var radz:Number=1;
//Vertice Data
private var verts:Vector.<Number>;
private var indices:Vector.<int>;
private var uvtData:Vector.<Number>;
private var uvtShadingData:Vector.<Number>;
private var projectedVerts:Vector.<Number>;

private var perspective:PerspectiveProjection;
private var projectionMatrix:Matrix3D;
private var myAngle:Number = 0;

public function GeneralizedPrimitive():void {

var myTimer = new Timer(1800);
myTimer.addEventListener(“timer”, timerHandler);
myTimer.start();

}

//Handle Timer Event
private function timerHandler(event:TimerEvent):void {

myCount=myCount%5;
init(myCount);
myCount++;

}

private function init(number:Number):void {
//Instantiate parameters
paraVec = new Vector3D();
verts = new Vector.<Number>();
indices= new Vector.<int>();
projectedVerts = new Vector.<Number>();
uvtData = new Vector.<Number>();
uvtShadingData = new Vector.<Number>();
bitmapData = new YourImage().bitmapData;

//remove primitive from stage before adding the next one
if(primitive){
removeChild(primitive);}
addChild(primitive= new Sprite());
//Set position on stage
primitive.x=stage.stageWidth/2;
primitive.y=stage.stageHeight/3;
//Set perspective
perspective= new PerspectiveProjection();
perspective.fieldOfView = 35.0; // camera angle, in degrees

//Calculate Vertices
for (var i:int = 0 ; i!=rows; i++) {
ix= i/(rows-1)*Math.PI*2.0;

for (var j:int =0 ; j!=cols; j++) {
iy= (j/(cols-1)-0.5)*Math.PI;

// Primitive Selection Switch Case
switch (number) {
case 0:
//Plane
paraVec = new Vector3D(-.5*(2-ix), .5*(iy),0);
break;
case 1:
//Cylinder
paraVec = new Vector3D(
Math.cos(ix), iy, Math.sin(ix));
break;
case 2:
//Cone
paraVec = new Vector3D(
(iy)*Math.cos(ix), Math.sin(iy), (iy)*Math.sin(ix));
break;
case 3:
//Sphere
paraVec = new Vector3D(
Math.cos(iy)*Math.cos(ix), Math.sin(iy), Math.cos(iy)*Math.sin(ix));
break;
case 4:
//Torus
paraVec = new Vector3D(
(1+.4*Math.cos(iy))*Math.cos(ix), .4*Math.sin(iy), (1+.4*Math.cos(iy))*Math.sin(ix));
break;
default:
trace ( ” no case tested true ” )
}
//Collect vetices in the verts Vector array
verts.push(radx*paraVec.x,rady*paraVec.y,radz*paraVec.z);

//Load uvt data
uvtData.push( i/(rows-1),j/(cols-1), 0.0);
//Initialize projected vertices
projectedVerts.push(0.0,0.0);
}
}

//Create indices
var ii:int =0;
for (var ik:int=0 ; ik!=rows-1; ik++) {
for (var jk:int=0 ; jk!=cols-1; jk++) {
indices.push( ii,ii+cols+1,ii+1,
ii+cols,ii+cols+1,ii++);
}
ii++;
}

stage.addEventListener(Event.ENTER_FRAME, loop);
}

private function loop(event:Event =null):void {
// Set up a viewpoint:
projectionMatrix = perspective.toMatrix3D();
projectionMatrix.prependTranslation(0,0,0.35);
myAngle+=2;
//Rotate Primtive
projectionMatrix.prependRotation( myAngle ,new Vector3D(0,1,0.0));
//Update projection vectors
Utils3D.projectVectors(projectionMatrix, verts,
projectedVerts, uvtData);
//Draw primtive
with (primitive.graphics) {
clear();
beginBitmapFill(bitmapData,null, false, false);
drawTriangles(projectedVerts, indices, uvtData,TriangleCulling.NEGATIVE);
endFill();
}
}

}
}

Advertisements

6 Responses to CS4 Super Primitive using Matrix3D

  1. makc3d says:

    Just to echo what I said on ML, looks quite similar to http://blog.wbsv.ru/?p=345.

    On the practical side, what would be the benefit of this? Perhaps if we could mix or morph two primitives together…

    • Mike Lively says:

      Here’s where this is going – this program is a stepping stone to a Blender import algorithm I’m completing today. It allows you to import your Blender models into CS4. I’ve got the Blender into CS4 working, I just now need to generalize the algorithm to work with any Blender model. Almost there … when this is complete, I will create similar algorithms for 3DSMax.

      Thanks for the comment.

  2. makc3d says:

    Ah, I did not realize it was NOT for papervision, I guess I needed to actually read it :) Ha, it’s kinda x2 funny given that I just did that ASE parser for CS4, http://makc3d.wordpress.com/2009/01/22/ase-parser-for-flash-10 with very similar code in the demo.

  3. makc3d says:

    p.s. I think it’s (iy)*Math.cos(ix), iy, (iy)*Math.sin(ix)); not (iy)*Math.cos(ix), Math.sin(iy), (iy)*Math.sin(ix)); for the cone.

  4. […] in the previous Super Prim post, Petri Leskinen’s great work on Pixelero http://pixelero.wordpress.com/ was key to this […]

  5. Hey Mike,

    Do you perhaps know how to tween rotation/translation in 3D with Tweener using the Matrix3D’s appendRotation/appendTranslation properties? If we could do that you could animate some of the more simpler 3D transformations in straight Flash/Flex without papervision (carousel galleries, etc.) without using all of Papervision. Thanks so much, this stuff is a little over my head :).

    Stoked to check out your book!
    Lance

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: