## CS4 Animated Shuttle – drawTriangles Blender Parser

January 28, 2009

Intro

There’s been a number of posts speculating whether 3D models could be brought into CS4. The problem has do with properly mapping uv coordinates to the appropriate vertex values. In this post, I’ll demonstrate the development of a very simple parser which allows you to bring Blender models into CS4. It uses the drawTriangles method, the Blender XML Exporter created in a previous post, and a one-to-one mapping scheme of vertex and uv data points.

I’m sure that as time progresses more advanced parsers will be developed, but for our present projects, this one works really well.

Demo

Source

Discussion

To create a Blender parser using the drawTriangles method, you’ve got to get your mapping right. It must be one-to-one: each vertex must have one unique uv point. But in modeling software, such as Blender, that’s not true. You can have multiple uv points for one vertex point as shown in the image below One 3D Point Becomes four in 2D

So, you can see the problem from the figure above. When you unfold a pyramid, uv mapping of 0ne 3D vertex point becomes four 2D points. In this case, the Blender data will give four uv data points for the apex of your pyramid above (point 4: 0,0,0 -> uv:points: 00, 01, 10, 11). But drawTriangles does not know what to do with this. It wants one uv point for each vertex. The way around this problem is to collect all similar uv data points per vertex and assign a new vertex number for non -unique points. So for example,

(point 4: 0,0,0 -> uv:points: 00, 01, 10, 11

becomes,

point 4: 0,0,0 -> 00
point 5: 0,0,0 -> 01
point 6: 0,0,0 -> 10
point 7: 0,0,0 -> 11

Importantly, points 0-3 are the four base pyramid points which are not unwrapped and as a result don’t need to be assigned new vertex numbers. The new vertex numbers have the same vertex coordinates as shown above – only the point assignment for the triangular fan is changed.

Note: The number of extra points you need to add is entirely dependent on how you unfold your object. If you use the hole punch method, you only need four extra vertices for an entire figure. As in anything, there’s no free lunch. You always give up something to gain something.

Code

The code sorts points into unique vertices and uv numbers (creating a 0ne-to-one mapping). If unique data can not be found new vertices are assigned creating a 0ne-to-one mapping as described in the post on the polar cube.

Blender XML Exporter

The whole process starts by creating a Blender XML file and photoshop image. This is done by using the Blender XML Exporter discussed in an earlier post.

The Blender XML file is imported into the program, parsed, and sorted. Then the sorter code below is used to create the one-to-one mapping scheme discussed above. Here are the steps:

1. The code starts by grabbing the index and vertex data created from the Blender XML export.

for (var i:int = 0; i< myFaceNum; i++) {

//Grab Indices from Blender XML
indices.push(int(mySplitFace[12*i]));
indices.push(int(mySplitFace[12*i+1]));
indices.push(int(mySplitFace[12*i+2]));

//Grab UV Data from Blender XML
myUVDatArray.push(Number(mySplitFace[12*i+3]));
myUVDatArray.push(Number(1-mySplitFace[12*i+4]));

myUVDatArray.push(Number(mySplitFace[12*i+5]));
myUVDatArray.push(Number(1-mySplitFace[12*i+6]));

myUVDatArray.push(Number(mySplitFace[12*i+7]));
myUVDatArray.push(Number(1-mySplitFace[12*i+8]));
}

2. The raw data above is sorted and a one-to-one mapping scheme created.

//Ferts Sorting Program
myFertsNum=indices.length;
myVertsNum=verts.length/3-1;//iteration number

for (var j:int = 0; j< myFertsNum; j++) {
for (var k:int = j+1; k<myFertsNum; k++) {
if (indices[j]==indices[k]) {
if ( (myUVDatArray[2*j]==myUVDatArray[2*k]) && (myUVDatArray[2*j+1]==myUVDatArray[2*k+1]) ) {
} else { verts.push(verts[3*indices[k]],verts[3*indices[k]+1],verts[3*indices[k]+2])
myVertsNum++;
indices[k]=myVertsNum; }}}}

3. And the uvtData is extracted.

//Sort uvtData (verts match uvtData-the golden rule for drawTriangles)
for (var m:int = 0; m<verts.length/3; m++) {
for (var n:int = 0; n<indices.length; n++) {
if (indices[n]==m) {
uvtData.push(myUVDatArray[2*n], myUVDatArray[2*n+1], 0);
break; }}}

Important Note!!!

The resulting parser works really well for convex structures, but has difficulty with concave objects. Due to sorting issues.

Both Flash & Math and Dorking Around 3D in Flash (and in one of my previous post) have suggested individual triangle sorting routines, and Dorking Around 3D in Flash has a working textured convex example using triangle sorting. Further testing and development needs to be done in this area: Individual triangle sorting may handle concave figures without a problem, but at present they do not use the drawTriangles method or an XML importer from Blender, as presented in this post.

Encapsulation

The code is fully encapsulated and closely resembles Papervision3D. A primitive is declared and an animation loop created inside a wrapper file (just as in Papervision3D).

blenderHouse = new BlenderPrim(“assets/data/shuttle.xml”, bmp, 300.0, 300.0, 10);

The parameters of the constructor function above are xml, bitmap, width and height. And the Blender Primitive lives in tbe org/lively3d/objects/primitives folder. This is the same as Papervision3D’s primitive path except for the lively3d part which is used to distinguish the different approaches.

Click the more button below to view the wrapper and Blender Primitive classes.

## Google Map Wormhole in Gumbo Air (Flex 4)

January 26, 2009

Intro

I’m working on a huge Google map project for a seminar I’m doing next Tuesday, (and given that I have much time on my hands – right!), I could not resist creating this Google Map wormhole. The animation is created by iterating the map coordinates (longitude and latitude forward), and uses the Tunnel class developed by Petri Leskinen on Pixelero http://pixelero.wordpress.com/.

I don’t iterate uvtData as is done on Pixelero, but longitude and latitude coordinates of the Google map. The change is picked up by drawing the iterated movie into a bitmapdata object and throwing that on to the Tunnel class.

It’s actually map data coming at you (not just a jpeg being recycled). Discussion

Bringing Google map data into CS4 or Papervision3D is really easy, as discussed in an earlier post (Google Map on a Papervision Primitive) . In this case, I use Gumbo (Flex 4) not Papervision3D. Gumbo performs better than Papervision3D and does not distort button positions on standard Google control buttons (as Papervision3D does) – hurray!!!

Here are the steps required to get your Google map Wormhole working!

movie.graphics.beginFill(0xFFFFFF);
movie.graphics.drawRect(0,0,300,300);

movie.graphics.endFill();

Step 3: Create a bitmapdata and draw your movie into it

_bmpd=new BitmapData(300,300, false);
_bmpd.draw(movie);

Step 4: Instantiate the Tunnel class (adding in the bitmapdata material) and add the tunnel to a canvas container on your Flex stage.

tunnel = new Tunnel(_bmpd, 800.0, 600.0, 32, 32);

Step 5: Redraw the movie and iterate Latitude and Longitude coordinates in the onEnterFrame animation loop.

_bmpd.draw(movie);

myLat=myLat-.0002*sin;
myLng=myLng-.0002;

To see the complete code click the more button below

## Flash CS4 Polar Cube (one-to-one mapping)

January 24, 2009

Intro

Mapping a sphere to a cube becomes a fundamental issue in CS4, where vertex to UV data is a one-to-one map. Typical UV data brought in from Blender or 3DSMax, which have multiple uv data points per vertex (or triangle fan), will not work with the drawTriangles method of CS4. There are work-a-rounds, but eventually it all boils down to creating some type of one-to-one mapping scheme.

An illustrative step in this process is the creation of a polar cube – a polar cube created completely from the polar parametric equations of an octagonal cubic (not pieced together with six planes (or 8 planes in this case) as is done in Papervision3D and other such software). Got a little ahead of myself here – the techniques described can be used to make any number of sides. I kept referring to a cube but created an octagonal as was pointed out by makc3d in the comments. The equations can be used to created a sculpty prim maker which will be posted soon.

Not 8 separate sides, all one structure.

Polar Cube Derivation

The parametric mapping equations (for a polar cube) are simple, and for a 2D boil down to

x = r(θ)*cos(θ)
y = r(θ)*sin(θ)

and in 3D,

x = r(θ, Φ)*cos(θ)sin(Φ)
y = r(θ, Φ)*sin(θ)sin(Φ)
z = r(θ, Φ)*cos(Φ)

where r is function of angle (not constant as in the spherical case).

Solving for the 2D case, r(θ) is given by

θ: 0 to 90, r(θ) = 1/(sin(θ) + cos(θ))
θ: 90 to 180, r(θ) = 1/(sin(θ) – cos(θ))
θ: 180 to 270, r(θ) = -1/(sin(θ) + cos(θ))
θ: 270 to360, r(θ) = -1/(sin(θ) – cos(θ))

These solutions are easily obtained by substitution x = r(θ)*cos(θ), and y = r(θ)*sin(θ) into the linear equations shown in the figure below and solving for r(θ). 2D Polar Case

The generalized solution is

r(a, b, θ) = a/(sin(θ) + b*cos(θ))

where

θ: 0 to 90 (a=1, b=1), θ: 90 to 180 (a=1, b=-1), θ: 180 to 270 (a=-1, b=-1), θ: 270 to360 (a=-1, b=-1) Of interest, the values of the a, b parameters correspond to all possible combinations of 1 and -1, similar two coins which gives (HH, HT, TH, TT) where H=1, and T=-1.

3D Case

Following the approach above, for the 3D case (where 8 possible planes corresponding to the 8 sides of the polar cube), the general solution is given by

r(a, b, c, θ, Φ) = a/(cos(Φ)+b*sin(θ)sin(Φ)+c*cos(θ)sin(Φ))

where the parameters a, b, c correspond to flipping three coins at the same time with 8 possible outcomes (HHH, HHT, HTH, HTT, THH, THT, TTH, TTT or 111, 11-1, 1-11, 1-1-1, -111,- 11-1, -1-11, -1-1-1), corresponding to the 8 sides of our polar cube.

The eight possibilities used to map the vertices of the cube are given below:

θ: 0 to 90, Φ:0 to 90 (-1,-1,-1)
θ: 90 to 180, Φ:0 to 90 (-1,-1,1)
θ: 180 to 270, Φ:0 to 90 (-1,1,1)
θ: 270 to360, Φ:0 to 90 (-1,1,-1)

θ: 0 to 90, Φ:90 to 180 (1,1,1)
θ: 90 to 180, Φ:90 to 180 (1,1,-1)
θ: 180 to 270, Φ:90 to 180 (1,-1,-1)
θ: 270 to360, Φ:90 to 180 (1,-1,1)

Coding the Parametric Equations

The coding is straightforward. The cube’s vertices are derived from the parametric form given above and its indices are derived from a one-to-one mapping of a sphere onto a cube. That’s why the spherically mapped image, shown in the image above, lays on the cube without distortion.

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;

// 8 planes 8case

if(ix>=0 && ix<2*Math.PI/4){

//θ: 0-90, Φ: 0-90, (-1,-1,-1)

if(iy>=-2*Math.PI/4 && iy<0){
varMyrIs=rFunc(-1,-1,-1,ix,iy);
}else{

//θ: 0-90, Φ: 90-180, (1,1,1)

varMyrIs=rFunc(1,1,1,ix,iy);}
}

if(ix>=2*Math.PI/4 && ix<2*Math.PI/2){

//θ: 90-180, Φ: 0-90, (-1,-1,1)

if(iy>=-2*Math.PI/4 && iy<0){
varMyrIs=rFunc(-1,-1,1,ix,iy);
}else{

//θ: 90-180, Φ: 90-180, (1,1,-1)

varMyrIs=rFunc(1,1,-1,ix,iy);}
}

if(ix>=2*Math.PI/2 && ix<6*Math.PI/4){

//θ: 180-270, Φ: 0-90, (1,-1,1)

if(iy>=-2*Math.PI/4 && iy<0){
varMyrIs=rFunc(-1,1,1,ix,iy);
}else{

//θ: 180-270, Φ: 90-180, (-1,-1,1)

varMyrIs=rFunc(1,-1,-1,ix,iy);}
}

if(ix>=6*Math.PI/4 && ix<=2*Math.PI){

//θ: 270-360, Φ: 0-90, (-1,1,-1)

if(iy>=-2*Math.PI/4 && iy<0){

varMyrIs=rFunc(-1,1,-1,ix,iy);
}else{

//θ: 270-360, Φ: 90-180, (1,-1,1)

varMyrIs=rFunc(1,-1,1,ix,iy);}
}

//Polar Cube
paraVec = new Vector3D(
varMyrIs*Math.cos(iy)*Math.cos(ix), varMyrIs*Math.sin(iy), varMyrIs*Math.cos(iy)*Math.sin(ix));

//Collect vetices in the verts Vector array

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

Now you’ll ready to start Knowledge Space. To see the entire code click the more link below:

## Flash CS4 Spherical Panorama (animating uvtData)

January 24, 2009

Intro

Creating a CS4 Panorama has a unique twist – literally! You actually don’t rotate the primitive but you animate its texture, using the code snippet below:

public function step(moveU:Number, moveV:Number=0.0):void {
for (var i=0; i<uvtData.length; i+=2) {
uvtData[i++] -= moveU;
uvtData[i] += moveV;
// each loop i increases by 3 because skiping over the t-coordinate
}
}

The uvtData is easily animated just by skipping through correct U or V values of the uvtData vector and adding a small increment. Click on the image below to see the web demo.

As in the previous Super Prim post, Petri Leskinen’s great work on Pixelero http://pixelero.wordpress.com/ was key to this creation. He demonstrates an animated tube which with a little work I was able to turn into this panorama.

Discussion

The encapsulated code very closely resembles the OOP regimentation of Papervision3D. The CS4PanoPrim wrapper class instantiates the SpherePano primitive. And the SpherePano constructor function has 5 input parameters: material, width, height, hSegments, and wSegments, as shown below:

spherePano = new SpherePano(bmp, 500.0, 500.0, 32, 32);

The SpherePanoPrim is set up very much like the Super Prim (previous post) with the addition of a new mask function, which gives you the ability to trim the look of your pano.

// mask crops that to a rectangle

}

If you want to learn how to make spherical pano images check out the following YouTube links by Amanda Verrette (one of my graphic designers):

Parts 4, 5, 6, 7, and 8 are still in production.

There’s still more work to do on this before release, but it’s great starter code. And harnesses the OOP structure of Papervision3D. To view both classes discussed above click the more link below:

## CS4 Super Primitive using Matrix3D

January 20, 2009

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.

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

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.

## CS4 Second Life Tree Superior to PV3D

January 18, 2009

Intro

When it comes to creating Second Life foliage in Flash 3D, Flash CS4 is far superior in ease of use, code required, and portability.

To see a demo and grab the source files click the links below:

Source

Demo

Given that I like Papervision3D so much, you’ll find the following analysis very unbiased. But it surprised me, and made me think a little about the direction I’m headed. I’m not giving up Papervision3D, there are too many things that PV3D can do that CS4 can’t. But I’m definitely blending CS4 with Papervision3D whenever a savings like this can be found.

Ease of Use

The steps required to create the Second Life tree graphic for use in the 3D environment for CS4 and PV3D are given below. CS4 requires no programming and PV3D is programming intensive.

CS4, No Programming Required

To create the Second Life Tree in CS4 Flash follow these steps

1. Import the front and side tree “png” images onto the Flash Stage.
2. Turn them both into movie clips
3. Rotate one 90 degrees with the 3D rotation tool and use the 3D translation tool to overlap them at their centers
4. Turn both into a movie clip and check the linkage of that movie clip for export

PV3D, Programming Intensive

1. Create a Tree Primitive (see the Post on Second Life Tree)
2. Import the Tree Primitive into a BasicView wrapper program

Counting lines of code was the real eye opener, it really shows the advantage of having the native z component in Flash 10.

Code Required

All things considered CS4 beats Papervision3D hands down in the number of lines (fewer) required to code the same user experience: 23 to 243, a factor of 10. Comparison of Lines of Code Required

Portability

Like Papervision3D, CS4 runs on Windows, Mac, and Linux. But with CS4 you can run your Second Life tree with Papervision3D, Away3D, Sandy3D, or any other 3D package running in the Flash 10 player.

The code for the CS4 Second Life Tree is given below:

CS4 Code

package {
import flash.display.Sprite;
import flash.display.*;

public class SLTreePackage extends Sprite
{
private var tree:SLTree= new SLTree();
public function SLTreePackage()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
tree.x=stage.stageWidth/2;
tree.y=stage.stageHeight/4;
//Start Tree Rotating
}
private function onEnterFrame(event:Event):void
{
tree.rotationY+=1;
}
}
}

## Second Life Tree in Papervision3D

January 17, 2009

Intro

A Second Life tree in Papervision3D is pretty easy to make. It’s made up of two planes intersecting at 90 degrees. As you rotate around the tree, it appears to be 3D since you see its sister plane. Of course it’s just an optical illusion, and as you get closer to the tree the planes become more apparent. But given the processing savings of creating a tree with just one primitive-it’s worth it! When you get to the Chapter on virtual tours you’ll use this trick to create an entire grove of trees on a Google Map.

Demo

Source

YouTube (Note: Discussion of Primitive does not occur until 1/4 of video has been  played)

Discussion

The trick to creating this illusion is to take a cube, which is made up of six planes, eliminate four of the sides and translate two of them into an intersection point.

From the Cube primitive available in Papervision3D, create a Tree primitive: as was done in the hourglass case (see the book). Then navigate to the plane building functions of the cube (now named tree) and comment out the four unneeded planes. In this case you’ll keep front and right planes.

if( ! (excludeFaces & FRONT) )
buildPlane( “front”, “x”, “y”, width, height, depth2, ! Boolean( insideFaces & FRONT ) );

//Remove if( ! (excludeFaces & BACK) )
//Remove buildPlane( “back”, “x”, “y”, width, height, -depth2, Boolean(
//Remove insideFaces & BACK ) );

if( ! (excludeFaces & RIGHT) )
buildPlane( “right”, “z”, “y”, depth, height, width2, Boolean( insideFaces & RIGHT ) );

//Remove if( ! (excludeFaces & LEFT) )
//Remove buildPlane( “left”, “z”, “y”, depth, height, -width2, !
//Remove Boolean( insideFaces & LEFT ) );

//Remove if( ! (excludeFaces & TOP) )
//Remove buildPlane( “top”, “x”, “z”, width, depth, height2, Boolean(
//Remove insideFaces & TOP ) );

//Remove if( ! (excludeFaces & BOTTOM) )
//Remove buildPlane( “bottom”, “x”, “z”, width, depth, -height2, !
//Remove Boolean( insideFaces & BOTTOM ) );

Then navigate down to the vertex generation equations. Removing the “rev” term from the vertex(u) equation below will bring the front and right planes together.

vertex[ u ] = (iu * incU – textureU)[Remove * rev];
vertex[ v ] = iv * incV – textureV;
vertex[ w ] = depth;

Your primitive is ready to run. But remember the cube uses the materials list. In this case, since you have only two planes, you’ll create a material list of only two “png” image files. You use “png” image files since your tree must have the area around its branches transparent and “png” files have a transparent channel.

//Create a BitmapFileMaterial for your first png
myBitmapFileMaterial = new BitmapFileMaterial(“assets/TreeBigFront.png”);
myBitmapFileMaterial.doubleSided = true;

//Create a BitmapFileMaterial for your first png
myBitmapFileMaterial2 = new BitmapFileMaterial(“assets/TreeBigSide.png”);
myBitmapFileMaterial2.doubleSided = true;

var materialsList:MaterialsList = new MaterialsList();