Using Custom Primitives in Papervision

Intro

I’ve been building a spherical 3D memory game for the book and found the geodesic sphere and curved plane primitives very useful. These two primitives are not part of the standard Papervision primitive set and are therefore referred to as custom primitives.

You can download  the geodesic sphere primitive from panosalado (a great open source pano project) and the curved plane is created here by me. Here is a little background on the primitives.

Geodesic Sphere

The geodesic sphere primitive was created by Gabriel Putnam and can be downloaded from the open source Panosalado project found on Google Code. It starts with an octahedron and then builds triangle resolution by breaking the edges.
Geodesic Spheres handle image distortion better than the “normal” sphere in Papervision because all of their triangles are more uniform. However, there is still very significant distortion at the poles, but arguably less and the equator is definitely less distorted. Its advantage over using a Sphere primitive is that its vertices are evenly spaced.

Curved Plane

Using the geodesic sphere from above you can wrap a series of planes around it to create a 3D memory game. The positions of the planes can be positioned using the geometry.vertices method demonstrated in the previous blog post. But just using square planes looks a little disjointed as shown on the left of the image below. For a better visual appeal, you want to wrap the planes around the geodesic sphere so that their curvature matches the geo-sphere. This can be accomplished by creating a custom curved plane primitive shown on the right side of the image below. 

 

Creating a Curved Plane that Matches the Geodesic Sphere

Creating a Curved Plane that Matches the Geodesic Sphere

 

It’s pretty easy to create a curved plane. Follow this procedure:

• Open up the Plane primitive found in org/papervision3d/objects/primitives and rename it CurvedPlaneXY. Then rename the class and constructor CurvedPlaneXY as well.
• Next add parabolic curvature for both the x and y iteration across the width and height of the plane as shown in the code below;

for( var ix:int = 0; ix < gridX + 1; ix++ )
{for( var iy:int = 0; iy < gridY1; iy++ )
{var x :Number = ix * iW – textureX;
var y :Number = iy * iH – textureY;
//Curvature
var z :Number = -(myCurvatureX*x*x+myCurvatureY*y*y)/((width*width+height*height)/2);
vertices.push( new Vertex3D( x, y, z ) );
}}

This is pretty easy to do and greatly enhances the visual appeal of the wrapped geo-sphere.

You can find the code that wraps the geodesic sphere in curved planes, the geodesic sphere primitive and the curved plane primitives by clicking the more button below;

Geo-Sphere Wrapper

package
{
//Flash imports
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;

import org.papervision3d.objects.primitives.*;
import org.papervision3d.core.math.Quaternion;
import org.papervision3d.core.utils.Mouse3D;
import org.papervision3d.materials.*;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.*;
import org.papervision3d.view.BasicView;

//Create WirePlane class
public class GeoGameCurve extends BasicView
{
//Instantiate plane and wireframe material

private var cubeMaterial:WireframeMaterial;

private var mouse3D:Mouse3D;

private var myGraphicsHolder:DisplayObject3D = new DisplayObject3D();
private var cubeGrid:GeodesicSphere;

private var particleArray:Array = new Array();
private var materialArray:Array = new Array();

private var mySize:Number=100;

private var doRatate:Boolean=false;

private var oldMouseX:Number;
private var oldMouseY:Number;

private var oldRotX:Number=0;
private var oldRotY:Number=0;

private var slerp:Number = 0;

public function GeoGameCurve()
{
//Call super
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×000000;

// Create a wireframe material for the plane
cubeMaterial = new WireframeMaterial(0xFFFFFF);

viewport.interactive = true;
Mouse3D.enabled = true;
mouse3D = viewport.interactiveSceneManager.mouse3D;

//Add your wireframe to the scene

cubeGrid = new GeodesicSphere(new WireframeMaterial(0xffffff), mySize, 2);

for(var i:int = 0; i<cubeGrid.geometry.vertices.length; i++)
{

var myPart:CurvedPlaneXY = new CurvedPlaneXY(new WireframeMaterial(0xffffff), mySize/2.1, mySize/2.1,4,4,-10,-10);

myPart.x=cubeGrid.geometry.vertices[i].x;
myPart.y=cubeGrid.geometry.vertices[i].y;
myPart.z=cubeGrid.geometry.vertices[i].z;

if(myPart.x>0)
{
var myRadius1:Number=Math.sqrt(myPart.x*myPart.x+myPart.z*myPart.z);

myPart.rotationY=((180/Math.PI)*Math.acos(myPart.z/myRadius1))+180;

}else{

var myRadius2:Number=Math.sqrt(myPart.x*myPart.x+myPart.z*myPart.z);

myPart.rotationY=-((180/Math.PI)*Math.acos(myPart.z/myRadius2))+180;
}

if(myPart.x==0)
{

myPart.rotationY=-((180/Math.PI)*Math.acos(myPart.z/mySize))+180;
}

myPart.rotationX=(90-(180/Math.PI)*Math.acos(myPart.y/mySize));

particleArray.push(myPart);
myGraphicsHolder.addChild(myPart);
}
// myGraphicsHolder.addChild(cubeGrid);

myGraphicsHolder.addChild(cubeGrid);

camera.focus=40;
camera.zoom=50;

scene.addChild(myGraphicsHolder);

stage.addEventListener(MouseEvent.MOUSE_DOWN,function(e:MouseEvent):void {doRatate=true;
oldMouseX=mouseX;
oldMouseY=mouseY;
});

stage.addEventListener(MouseEvent.MOUSE_UP,function(e:MouseEvent):void {doRatate=false;
oldRotX=myGraphicsHolder.rotationX;
oldRotY=myGraphicsHolder.rotationY;

});

}

// override onRenderTick so you can execute code
override protected function onRenderTick(event:Event=null):void
{

if(doRatate){

myGraphicsHolder.rotationY = (oldMouseX-mouseX+oldRotY);
myGraphicsHolder.rotationX = (oldMouseY-mouseY+oldRotX);

}

//Call the super.onRenderTick function
super.onRenderTick(event);
}

}
}

Geodesic Sphere Primitive

/*
* Copyright 2007 (c) Gabriel Putnam
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the “Software”), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

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;

import org.papervision3d.Papervision3D;

/**
* GeodesicSphere implements octahedron-based geodesic sphere.
*
* <p>Compared to regular sphere, this primitive produces geometry with more
* evenly distributed triangles (code ported from Away3D mostly as is, with
* the exception of U/V mapping).</p>
*
* @author makc
* @version 3.0.3
* @date 10.04.2008
*
* @see http://en.wikipedia.org/wiki/Geodesic_dome
* @see http://en.wikipedia.org/wiki/Octahedron
*/
public class GeodesicSphere extends TriangleMesh3D {

private var radius_in:Number;
private var fractures_in:int;

/**
* Creates a GeodesicSphere primitive.
*
* @param p_sName A string identifier for this object.
* @param p_nRadius Sphere radius.
* @param p_nFractures Tesselation quality.
*/
public function GeodesicSphere ( material:MaterialObject3D=null, p_nRadius : Number = 100, p_nFractures : Number = 2, reverse : Boolean = false)
{
super( material, new Array(), new Array(), null );

radius_in = p_nRadius;
fractures_in = Math.max (2, p_nFractures);

buildGeodesicSphere(reverse);
}

/**
* @private
*/
public function buildGeodesicSphere(reverse:Boolean):void
{
var revFaces:Number = reverse ? -1 : 1;

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

// Set up variables for keeping track of the vertices, faces, and texture coords.
var nVertices:int = 0, nFaces:int = 0;
var aPacificFaces:Array = [], aVertexNormals:Array = [];

// Set up variables for keeping track of the number of iterations and the angles
var iVerts:uint = fractures_in + 1, jVerts:uint;
var j:uint, Theta:Number=0, Phi:Number=0, ThetaDel:Number, PhiDel:Number;
var cosTheta:Number, sinTheta:Number, cosPhi:Number, sinPhi:Number;

// Although original code used quite clever diamond projection, let’s change it to
// equirectangular just to see how it performs compared to standard Sphere – makc

var Pd4:Number = Math.PI / 4, cosPd4:Number = Math.cos(Pd4), sinPd4:Number = Math.sin(Pd4), PIInv:Number = 1/Math.PI;
var R_00:Number = cosPd4, R_01:Number = -sinPd4, R_10:Number = sinPd4, R_11:Number = cosPd4;
var z_vtx:Vertex3D, z_uv:NumberUV;

PhiDel = Math.PI / ( 2 * iVerts);

Phi += PhiDel;

// Build vertices for the sphere progressing in rings around the sphere
var i:int, q:int, aI:Array = [];
for (q = 1; q <= iVerts; q++) aI.push (q);
for (q = iVerts -1; q > 0; q–) aI.push (q);

for (q = 0; q < aI.length; q++) {
i = aI[q]; j = 0; jVerts = i*4;
Theta = 0;
ThetaDel = 2* Math.PI / jVerts;
cosPhi = Math.cos( Phi );
sinPhi = Math.sin( Phi );
for( j; j < jVerts; j++ )
{
cosTheta = Math.cos( Theta );
sinTheta = Math.sin( Theta );

z_vtx = new Vertex3D(cosTheta * sinPhi * radius_in, cosPhi * radius_in * revFaces, sinTheta * sinPhi * radius_in );
z_uv = new NumberUV(1-Theta * PIInv * 0.5, Phi * PIInv);
aVertice.push( z_vtx );
aUV.push( z_uv );
//l_oGeometry3D.setVertex (nVertices, cosTheta * sinPhi * radius_in, cosPhi * radius_in, sinTheta * sinPhi * radius_in);
//l_oGeometry3D.setVertexNormal (nVertices, cosTheta * sinPhi, cosPhi, sinTheta * sinPhi);
//l_oGeometry3D.setUVCoords (nVertices, Theta * PIInv * 0.5, Phi * PIInv);
nVertices++;

Theta += ThetaDel;
}
Phi += PhiDel;
}

// Four triangles meet at every pole, so we make 8 polar vertices to reduce polar distortions
for (i = 0; i < 8; i++)
{
z_vtx = new Vertex3D( 0, ((i < 4) ? radius_in : -radius_in) * revFaces, 0 );
z_uv = new NumberUV( 1-0.25 * (i%4 + 0.5), (i < 4) ? 0 : 1 );
aVertice.push( z_vtx );
aUV.push( z_uv );
//l_oGeometry3D.setVertex (nVertices + i, 0, (i < 4) ? radius_in : -radius_in, 0);
//l_oGeometry3D.setVertexNormal (nVertices + i, 0, (i < 4) ? 1 : -1, 0);
//l_oGeometry3D.setUVCoords (nVertices + i, 0.25 * (i%4 + 0.5), (i < 4) ? 0 : 1);
}

// Build the faces for the sphere
// Build the upper four sections
var k:uint, L_Ind_s:uint, U_Ind_s:uint, U_Ind_e:uint, L_Ind_e:uint, L_Ind:uint, U_Ind:uint;
var isUpTri:Boolean, Pt0:uint, Pt1:uint, Pt2:uint, tPt:uint, triInd:uint, tris:uint;
tris = 1;
L_Ind_s = 0; L_Ind_e = 0;
for( i = 0; i < iVerts; i++ ){
U_Ind_s = L_Ind_s;
U_Ind_e = L_Ind_e;
if( i == 0 ) L_Ind_s++;
L_Ind_s += 4*i;
L_Ind_e += 4*(i+1);
U_Ind = U_Ind_s;
L_Ind = L_Ind_s;
for( k = 0; k < 4; k++ ){
isUpTri = true;
for( triInd = 0; triInd < tris; triInd++ ){
if( isUpTri ){
Pt0 = U_Ind;
Pt1 = L_Ind;
L_Ind++;
if( L_Ind > L_Ind_e ) L_Ind = L_Ind_s;
Pt2 = L_Ind;
isUpTri = false;
} else {
Pt0 = L_Ind;
Pt2 = U_Ind;
U_Ind++;
if( U_Ind > U_Ind_e ) {
// pacific problem – correct vertex does not exist
aPacificFaces.push (
(Pt2 % 2 == 0) ?
[ Pt2 -1, Pt0 -1, U_Ind_s -1 ] :
[ Pt0 -1, Pt2 -1, U_Ind_s -1 ]);
continue;
}
Pt1 = U_Ind;
isUpTri = true;
}

// use extra vertices for pole
if (Pt0 == 0)
{
Pt0 = Pt1 + nVertices;
if (Pt1 == 4) {
// pacific problem at North pole
aPacificFaces.push ([ Pt0 -1, Pt1 -1, Pt2 -1 ]);
continue;
}
}

//aVertice[nFaces] = new Vertex3D(Pt0 -1, Pt1 -1, Pt2 -1);
//aUV[nFaces] = new NumberUV(Pt0 -1, Pt1 -1, Pt2 -1);
aFace.push( new Triangle3D( this, [ aVertice[Pt0 -1],aVertice[Pt1 -1],aVertice[Pt2 -1] ], null, [ aUV[Pt0 -1],aUV[Pt1 -1],aUV[Pt2 -1] ] ) );
//l_oGeometry3D.setFaceVertexIds (nFaces, Pt0 -1, Pt1 -1, Pt2 -1);
//l_oGeometry3D.setFaceUVCoordsIds (nFaces, Pt0 -1, Pt1 -1, Pt2 -1);
nFaces++;
}
}
tris += 2;
}
U_Ind_s = L_Ind_s; U_Ind_e = L_Ind_e;
// Build the lower four sections

for( i = iVerts-1; i >= 0; i– ){
L_Ind_s = U_Ind_s; L_Ind_e = U_Ind_e; U_Ind_s = L_Ind_s + 4*(i+1); U_Ind_e = L_Ind_e + 4*i;
if( i == 0 ) U_Ind_e++;
tris -= 2;
U_Ind = U_Ind_s;
L_Ind = L_Ind_s;
for( k = 0; k < 4; k++ ){
isUpTri = true;
for( triInd = 0; triInd < tris; triInd++ ){
if( isUpTri ){
Pt0 = U_Ind;
Pt1 = L_Ind;
L_Ind++;
if( L_Ind > L_Ind_e ) L_Ind = L_Ind_s;
Pt2 = L_Ind;
isUpTri = false;
} else {
Pt0 = L_Ind;
Pt2 = U_Ind;
U_Ind++;
if( U_Ind > U_Ind_e ) {
if (Pt2 %2 == 0)
aPacificFaces.push ([ Pt0 -1, Pt2 -1, U_Ind_s -1 ]);
else
aPacificFaces.push ([ Pt0 -1, U_Ind_s -1, L_Ind_s -1 ]);
continue;
}
Pt1 = U_Ind;
isUpTri = true;
}
// use extra vertices for pole
if (Pt0 == nVertices +1)
{
Pt0 = Pt1 + 8;
if (Pt1 == nVertices) {
// pacific problem at South pole
aPacificFaces.push ([ Pt0 -1, Pt2 -1, Pt1 -1 ]);
continue;
}
}

//aVertice[nFaces] = new Vertex3D(Pt0 -1, Pt2 -1, Pt1 -1);
//aUV[nFaces] = new NumberUV(Pt0 -1, Pt2 -1, Pt1 -1);
aFace.push( new Triangle3D( this, [ aVertice[Pt0 -1],aVertice[Pt2 -1],aVertice[Pt1 -1] ], null, [ aUV[Pt0 -1],aUV[Pt2 -1],aUV[Pt1 -1] ] ) );
//l_oGeometry3D.setFaceVertexIds (nFaces, Pt0 -1, Pt2 -1, Pt1 -1);
//l_oGeometry3D.setFaceUVCoordsIds (nFaces, Pt0 -1, Pt2 -1, Pt1 -1);
nFaces++;
}
}
}

// only now we can fix pacific problem
// (because doing so in any other way would break Gabriel code ;)
nVertices = aVertice.length;
//nVertices = l_oGeometry3D.aVertex.length;
for (i = 0; i < aPacificFaces.length; i++)
{
for (k = 0; k < 3; k++)
{
var p:int = aPacificFaces [i][k];
if (aUV[p].u == reverse ? 1 : 0 )
{
if ( !aVertice[nVertices] ) aVertice[nVertices] = aVertice[p];
if ( !aUV[nVertices] ) aUV[nVertices] = new NumberUV(reverse ? 0 : 1, aUV[p].v);

aPacificFaces [i][k] = nVertices;
nVertices++;
}

// if (l_oGeometry3D.aUVCoords [p].u == 0)
// {
// l_oGeometry3D.setVertex (nVertices,
// l_oGeometry3D.aVertex [p].x,
// l_oGeometry3D.aVertex [p].y,
// l_oGeometry3D.aVertex [p].z);
// l_oGeometry3D.setVertexNormal (nVertices,
// l_oGeometry3D.aVertexNormals [p].x,
// l_oGeometry3D.aVertexNormals [p].y,
// l_oGeometry3D.aVertexNormals [p].z);
// l_oGeometry3D.setUVCoords (nVertices, 1,
// l_oGeometry3D.aUVCoords [p].v);
// aPacificFaces [i][k] = nVertices;
// nVertices++;
// }
}
aFace.push( new Triangle3D( this, [ aVertice[ aPacificFaces [i][0] ],aVertice[ aPacificFaces [i][1] ],aVertice[ aPacificFaces [i][2] ] ], null, [ aUV[ aPacificFaces [i][0] ],aUV[ aPacificFaces [i][1] ],aUV[ aPacificFaces [i][2] ] ] ) );
//l_oGeometry3D.setFaceVertexIds (nFaces, aPacificFaces [i][0], aPacificFaces [i][1], aPacificFaces [i][2]);
//l_oGeometry3D.setFaceUVCoordsIds (nFaces, aPacificFaces [i][0], aPacificFaces [i][1], aPacificFaces [i][2]);

nFaces++;
}

//return l_oGeometry3D;

this.geometry.ready = true;

/* if(Papervision3D.useRIGHTHANDED)
this.geometry.flipFaces(); */

}
}
}

Curved Plane Primitive

package org.papervision3d.objects.primitives {

import org.papervision3d.Papervision3D;
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;
import org.papervision3d.core.proto.*;

/**
* The Plane class lets you create and display flat rectangle objects.
* <p/>
* The rectangle can be divided in smaller segments. This is usually done to reduce linear mapping artifacts.
* <p/>
* Dividing the plane in the direction of the perspective or vanishing point, helps to reduce this problem. Perspective distortion dissapears when the plane is facing straignt to the camera, i.e. it is perpendicular with the vanishing point of the scene.
*/
public class CurvedPlaneXY extends TriangleMesh3D
{
/**
* Number of segments horizontally. Defaults to 1.
*/
public var segmentsW :Number;

/**
* Number of segments vertically. Defaults to 1.
*/
public var segmentsH :Number;

/**
* Default size of Plane if not texture is defined.
*/
static public var DEFAULT_SIZE :Number = 500;

/**
* Default size of Plane if not texture is defined.
*/
static public var DEFAULT_SCALE :Number = 1;

/**
* Default value of gridX if not defined. The default value of gridY is gridX.
*/
static public var DEFAULT_SEGMENTS :Number = 1;

//Curvatured
public var myCurvatureX:Number;
public var myCurvatureY:Number;

// ___________________________________________________________________________________________________
// N E W
// NN NN EEEEEE WW WW
// NNN NN EE WW WW WW
// NNNNNN EEEE WWWWWWWW
// NN NNN EE WWW WWW
// NN NN EEEEEE WW WW

/**
* Create a new Plane object.
* <p/>
* @param material A MaterialObject3D object that contains the material properties of the object.
* <p/>
* @param width [optional] – Desired width or scaling factor if there’s bitmap texture in material and no height is supplied.
* <p/>
* @param height [optional] – Desired height.
* <p/>
* @param segmentsW [optional] – Number of segments horizontally. Defaults to 1.
* <p/>
* @param segmentsH [optional] – Number of segments vertically. Defaults to segmentsW.
* <p/>
* @param initObject [optional] – An object that contains user defined properties with which to populate the newly created GeometryObject3D.
* <p/>
* It includes x, y, z, rotationX, rotationY, rotationZ, scaleX, scaleY scaleZ and a user defined extra object.
* <p/>
* If extra is not an object, it is ignored. All properties of the extra field are copied into the new instance. The properties specified with extra are publicly available.
*/
public function CurvedPlaneXY( material:MaterialObject3D=null, width:Number=0, height:Number=0, segmentsW:Number=0, segmentsH:Number=0, curvatureX:Number=0,curvatureY:Number=0, initObject:Object=null )
{
super( material, new Array(), new Array(), null );

this.segmentsW = segmentsW || DEFAULT_SEGMENTS; // Defaults to 1
this.segmentsH = segmentsH || this.segmentsW; // Defaults to segmentsW

//Added for curvature.m
this.myCurvatureX=curvatureX;
this.myCurvatureY=curvatureY;

var scale :Number = DEFAULT_SCALE;

if( ! height )
{
if( width )
scale = width;

if( material && material.bitmap )
{
width = material.bitmap.width * scale;
height = material.bitmap.height * scale;
}
else
{
width = DEFAULT_SIZE * scale;
height = DEFAULT_SIZE * scale;
}
}

buildPlane( width, height );
}

private function buildPlane( width:Number, height:Number ):void
{
var gridX :Number = this.segmentsW;
var gridY :Number = this.segmentsH;
var gridX1 :Number = gridX + 1;
var gridY1 :Number = gridY + 1;

var vertices :Array = this.geometry.vertices;
var faces :Array = this.geometry.faces;

var textureX :Number = width /2;
var textureY :Number = height /2;

var iW :Number = width / gridX;
var iH :Number = height / gridY;

// Vertices
for( var ix:int = 0; ix < gridX + 1; ix++ )
{
for( var iy:int = 0; iy < gridY1; iy++ )
{
var x :Number = ix * iW – textureX;
var y :Number = iy * iH – textureY;
//Video Curve
var z :Number = -(myCurvatureX*x*x+myCurvatureY*y*y)/((width*width+height*height)/2);

vertices.push( new Vertex3D( x, y, z ) );
}
}

// Faces
var uvA :NumberUV;
var uvC :NumberUV;
var uvB :NumberUV;

for( ix = 0; ix < gridX; ix++ )
{
for( iy= 0; iy < gridY; iy++ )
{
// Triangle A
var a:Vertex3D = vertices[ ix * gridY1 + iy ];
var c:Vertex3D = vertices[ ix * gridY1 + (iy+1) ];
var b:Vertex3D = vertices[ (ix+1) * gridY1 + iy ];

uvA = new NumberUV( ix / gridX, iy / gridY );
uvC = new NumberUV( ix / gridX, (iy+1) / gridY );
uvB = new NumberUV( (ix+1) / gridX, iy / gridY );

faces.push(new Triangle3D(this, [ a, b, c ], material, [ uvA, uvB, uvC ] ) );

// Triangle B
a = vertices[ (ix+1) * gridY1 + (iy+1) ];
c = vertices[ (ix+1) * gridY1 + iy ];
b = vertices[ ix * gridY1 + (iy+1) ];

uvA = new NumberUV( (ix+1) / gridX, (iy+1) / gridY );
uvC = new NumberUV( (ix+1) / gridX, iy / gridY );
uvB = new NumberUV( ix / gridX, (iy+1) / gridY );

faces.push(new Triangle3D(this, [ a, b, c ], material, [ uvA, uvB, uvC ] ) );
}
}

this.geometry.ready = true;

if(Papervision3D.useRIGHTHANDED)
this.geometry.flipFaces();
}
}
}

 

 


About these ads

2 Responses to Using Custom Primitives in Papervision

  1. [...] 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 [...]

  2. [...] > Using Custom Primitives in Papervision « Professional Papervision3D Book [...]

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

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: