Cylinder radial segment primitive object for Papervision3D

Pondelok, Máj 19th, 2008
Cylinder radial segment primitive object for Papervision3D

For my latest project I needed to display 3D cylinder slices – Papervision was an obvious choice. Unfortunately the primitive cylinder class does not work this way, the cylinder is built as a square mesh with no option for segment slices. So I had to help myself, I started to play with the almost undocumented PV3D primitives, step by step modifying the original cylinder class and after couple hours I dig out what is what and derived my RadialSegment class. It follows the original concept with one material for whole object, supports UV mapping and inherit all other properties. Here it is, use it as you wish.

papervision3d cylinder radial segment

Code and live example in full article

Here is live example and source code follows:

package {
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 RadialSegment class lets you create and display cylinders radial segments.
*
 
* The RadialSegment is divided in horizontal mesh segments and vertical ragial segments.
*  	 * Derivated from original Cylinder class by Daniel Sedlacek (sedlacek.daniel@gmail.com).
*  	 * Please follow the original Papervision3D license.
*/
public class RadialSegment extends TriangleMesh3D {
/**
* Number of segments horizontally. Defaults to 8.
*/
public var segmentsW : Number;		/**
* Number of segments vertically. Defaults to 6.
*/
public var segmentsH : Number;
 
/**
* Default radius of Segment3D if not defined.
*/
static public var DEFAULT_RADIUS : Number = 100;
 
/**
* Default height if not defined.
*/
static public var DEFAULT_HEIGHT : Number = 50;
 
/**
* Default value of gridX if not defined.
*/
static public var DEFAULT_SEGMENTSW : Number = 8;
 
/**
* Default value of gridY if not defined.
*/
static public var DEFAULT_SEGMENTSH : Number = 2;
 
/**
* Minimum value of gridX.
*/
static public var MIN_SEGMENTSW : Number = 3;
 
/**
* Minimum value of gridY.
*/
static public var MIN_SEGMENTSH : Number = 1;
 
/**
* Create a new Cylinder object.
*
 
* @param	material	[optional] - A MaterialObject3D object that contains the material properties of the object.
*  		 * @param	angle		[optional] - Desired segment angle <0,1>.
*  		 * @param	radius		[optional] - Desired radius.
*  		 * @param	segmentsW	[optional] - Number of segments horizontally. Defaults to 8.
*  		 * @param	segmentsH	[optional] - Number of segments vertically. Defaults to 6.
*  		 * @param	topRadius	[optional] - An optional parameter for con- or diverging cylinders
*  		 * @param	initObject	[optional] - An object that contains user defined properties with which to populate the newly created GeometryObject3D.
*  		 * It includes x, y, z, rotationX, rotationY, rotationZ, scaleX, scaleY scaleZ and a user defined extra object.
*  		 * 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 RadialSegment( material : MaterialObject3D = null, angle : Number = 0.25, radius : Number = 100, height : Number = 100, segmentsW : int = 8, segmentsH : int = 2, topRadius : Number = -1, initObject : Object = null ) {
super(material, new Array(), new Array(), null, initObject);			this.segmentsW = Math.max(MIN_SEGMENTSW, segmentsW || DEFAULT_SEGMENTSW);
// Defaults to 8
this.segmentsH = Math.max(MIN_SEGMENTSH, segmentsH || DEFAULT_SEGMENTSH);
// Defaults to 6
if (radius == 0) radius = DEFAULT_RADIUS;
// Defaults to 100
if (height == 0) height = DEFAULT_HEIGHT;
// Defaults to 100
if (topRadius == -1) topRadius = radius;
// segment
angle = angle > 1 ? 1 : angle < 0 ? 0 : angle;
 
buildSegment(angle, radius, height, topRadius);
}
 
private function buildSegment( fAngle : Number, fRadius : Number, fHeight : Number,  fTopRadius : Number ) : void {
var matInstance : MaterialObject3D = material;
 
var i : Number, j : Number;
 
var iHor : Number = this.segmentsW + 1;
var iVer : Number = this.segmentsH;
var aVertice : Array = this.geometry.vertices;
var aFace : Array = this.geometry.faces;
var aVtc : Array = new Array();
 
for (j = 0;j < (iVer + 1);j++) {
// vertical
var fZ : Number = fHeight * (j / (iVer + 0)) - fHeight / 2;
//-fRadius*Math.cos(fRad1*Math.PI);
var fRds : Number = fTopRadius + (fRadius - fTopRadius) * (1 - j / (iVer));
//*Math.sin(fRad1*Math.PI);
var aRow : Array = new Array();
var oVtx : Vertex3D;
 
for (i = 0;i < iHor;i++) {
// horizontal
var fRad2 : Number = Number(2 * i / (iHor - 1));
var fX : Number = fRds * Math.sin(fRad2 * Math.PI * fAngle);
var fY : Number = fRds * Math.cos(fRad2 * Math.PI * fAngle);
oVtx = new Vertex3D(fY, fZ, fX);
 
aVertice.push(oVtx);
aRow.push(oVtx);
}
 
// special middle vertex
oVtx = new Vertex3D(0, fZ, 0);
aVertice.push(oVtx);
aRow.push(oVtx);
 
aVtc.push(aRow);
}
var iVerNum : int = aVtc.length;
 
var aP4uv : NumberUV, aP1uv : NumberUV, aP2uv : NumberUV, aP3uv : NumberUV;
var aP1 : Vertex3D, aP2 : Vertex3D, aP3 : Vertex3D, aP4 : Vertex3D;
 
for (j = 0;j < iVerNum;j++) {
var iHorNum : int = aVtc[j].length;
for (i = 0;i < iHorNum;i++) {
if (j > 0 && i >= 0) {
// select vertices
var bEnd : Boolean = i == (iHorNum - 0);
aP1 = aVtc[j][bEnd ? 0 : i];
aP2 = aVtc[j][(i == 0 ? iHorNum : i) - 1];
aP3 = aVtc[j - 1][(i == 0 ? iHorNum : i) - 1];
aP4 = aVtc[j - 1][bEnd ? 0 : i];
// uv
var fJ0 : Number = j / iVerNum;
var fJ1 : Number = (j - 1) / iVerNum;
var fI0 : Number = (i + 1) / iHorNum;
var fI1 : Number = i / iHorNum;
aP4uv = new NumberUV(fI0, fJ1);
aP1uv = new NumberUV(fI0, fJ0);
aP2uv = new NumberUV(fI1, fJ0);
aP3uv = new NumberUV(fI1, fJ1);
 
aFace.push(new Triangle3D(this, [aP1,aP2,aP3], matInstance, [aP1uv,aP2uv,aP3uv]));
aFace.push(new Triangle3D(this, [aP1,aP3,aP4], matInstance, [aP1uv,aP3uv,aP4uv]));
}
}
if (j == 0 || j == (iVerNum - 1)) {
for (i = 0;i < (iHorNum - 2);i++) {
// uv
 
aP1 = aVtc[j][iHorNum - 1];
aP2 = aVtc[j][i];
aP3 = aVtc[j][i + 1];
 
var bTop : Boolean = j == 0;
aP1uv = new NumberUV((bTop ? 1 : 0) + (bTop ? -1 : 1) * (aP1.x / fRadius / 2 + .5), aP1.z / fRadius / 2 + .5);
aP2uv = new NumberUV((bTop ? 1 : 0) + (bTop ? -1 : 1) * (aP2.x / fRadius / 2 + .5), aP2.z / fRadius / 2 + .5);
aP3uv = new NumberUV((bTop ? 1 : 0) + (bTop ? -1 : 1) * (aP3.x / fRadius / 2 + .5), aP3.z / fRadius / 2 + .5);
 
// face
if (j == 0)	aFace.push(new Triangle3D(this, [aP1,aP3,aP2], matInstance, [aP1uv,aP3uv,aP2uv]));
else		aFace.push(new Triangle3D(this, [aP1,aP2,aP3], matInstance, [aP1uv,aP2uv,aP3uv]));
}
}
}
this.geometry.ready = true;
}
}
}
tagged under:

ABOUT THIS AUTHOR

twitter.com/daniel_sedlacek

3 Trackbacks/Pingbacks

  1. Spätné upozorenie: Cylinder radial segment primitive object for Papervision3D on Máj 19, 2008
  2. Spätné upozorenie: flash your on Máj 19, 2008
  3. Spätné upozorenie: Pages tagged "the primitives" on Máj 21, 2008

13 Comments


  1. marcel weber
    Visit Site
    August 28th, 2009

    Sounds nice! I would like to see the demo, but the links are broken.


  2. admin
    Visit Site
    Október 13th, 2009

    Sorry Marcel, problem fixed. It was caused by changing my hosting to another provider and I have some issues with WordPress. But now you can see example and download source code


  3. Giedrius
    Visit Site
    Január 5th, 2010

    It seems this class doesn’t work with papervision library 2.0…
    Could You upload Your papervision library some how?


  4. Giedrius
    Visit Site
    Január 5th, 2010

    Sorry…
    It works. Made some corrections. Just rendering isn’t well enough. While rotating camera there appears white spot on stage…


  5. Daniel Sedlacek
    Visit Site
    Január 5th, 2010

    Sorry, it is bit out of date now. Hope you can use it at least as a concept.


  6. Achim
    Visit Site
    Jún 30th, 2010

    Hi,
    is there an update of this nice primitive working with PV3D 2.0?
    That would be really useful to create Pie Charts!


  7. Daniel Sedlacek
    Visit Site
    Júl 6th, 2010

    @Achim: This should help, it’s PV3D 2.0 and it provides more control over texturing. Enjoy. http://franto.com/uploads/examples/pie/Cylinder3D.as


  8. Daniel Sedlacek
    Visit Site
    Júl 7th, 2010

    @Achim: this should help, it’s Pv3D 2.0 version with enhanced texturing and fixed UV mapping bug. Get the new class here.


  9. Pedro
    Visit Site
    September 10th, 2010

    Thank you for the hard work.
    I´m having trouble using materials other than ColorMaterial.
    I´s it possible to use FlatshadeMaterial on this?


  10. Pedro
    Visit Site
    September 10th, 2010

    Is it possible to use FlatShadeMaterials? I´m having trouble using materials other than ColorMaterial


  11. Arindam Mojumder
    Visit Site
    September 20th, 2010

    Hello SIr,

    I have used your class for making a Pie chart. But in the joining section it is disturbing. Can you help me to sort out the problem?

    Here is my code:

    package {

    import org.papervision3d.view.BasicView;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.events.InteractiveScene3DEvent;
    import RadialSegment;
    import org.papervision3d.objects.primitives.*;
    import org.budgetorium.budget.primitives3d.*;

    import flash.events.*;
    import flash.display.Stage;

    import org.papervision3d.lights.PointLight3D;
    import org.papervision3d.materials.*;
    import org.papervision3d.materials.shadematerials.FlatShadeMaterial;

    import caurina.transitions.Tweener;

    public class Main extends BasicView {

    private var _holder:DisplayObject3D;
    private var light:PointLight3D = new PointLight3D();
    private var curDegree:Number =0;
    private var angle:Number=0;

    private var tweenTime:Number = 0.5;
    private var transition:String = “easeOutExpo”;

    public function Main() {

    //super(0,0,true,true,”Free”);
    viewport.interactive = true;
    _holder =new DisplayObject3D();
    light.y = 2000;
    camera.y = 400;
    camera.zoom=30;

    var material:ColorMaterial= new ColorMaterial(0xff0000);
    material.doubleSided=true;
    material.smooth = true;
    material.interactive = true;
    var plane:Plane = new Plane (material,400,400,2,2);

    //MakeSection(360/100*10,0xCCFF00,0×000000,0.10);
    MakeSection(360/100*50,0x0000FF,0×000000,0.50);
    MakeSection(360/100*50,0xFF0000,0×000000,0.50);
    //MakeSection(360/100*20,0xFF66CC,0×000000,0.20);

    startRendering();
    //stage.addEventListener(MouseEvent.MOUSE_DOWN,activate);
    //stage.addEventListener(MouseEvent.MOUSE_UP,removeListenerrotateCamera);
    stage.addEventListener(MouseEvent.MOUSE_WHEEL,activate);

    plane.addEventListener(InteractiveScene3DEvent.OBJECT_OVER,Over);
    plane.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, Out);
    scene.addChild(_holder);
    //scene.addChild(plane);

    }
    private function MakeSection(rotationVal:Number,col1:uint,col2:uint,per:Number,wd:Number=600,hg:Number=100,horSeg:Number=40,verSeg:Number=0):void {

    var mat:FlatShadeMaterial=new FlatShadeMaterial(light,col1,col2);
    //mat.doubleSided=true;
    mat.interactive=true;
    //var segmentedCylinder:RadialSegment = new RadialSegment(mat,per,wd,hg,horSeg,verSeg);
    var segmentedCylinder:Cylinder3D = new Cylinder3D();

    curDegree += rotationVal;
    segmentedCylinder.rotationY = curDegree;
    _holder.addChild(segmentedCylinder);

    segmentedCylinder.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, Over);
    segmentedCylinder.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, Out);

    }

    private function Over(ev:InteractiveScene3DEvent):void {
    var obj:DisplayObject3D = ev.displayObject3D;
    Tweener.addTween(obj,{z:100,time:tweenTime,transition:transition});
    }
    private function Out(ev:InteractiveScene3DEvent):void {

    var obj:DisplayObject3D = ev.displayObject3D;
    Tweener.addTween(obj,{z:0,time:tweenTime,transition:transition});
    }
    private function activate(e:MouseEvent):void {
    //stage.addEventListener(MouseEvent.MOUSE_MOVE,rotateCamera);
    _holder.rotationY += (e.delta*10);;
    }
    private function removeListenerrotateCamera(e:MouseEvent):void {
    stage.removeEventListener(MouseEvent.MOUSE_MOVE,rotateCamera);
    }
    private function rotateCamera(e:MouseEvent):void {
    var dist2:Number = ((stage.mouseX) – stage.stageWidth * 0.5) * 0.00018;
    angle+=dist2;
    _holder.rotationY=Math.cos(angle)*100;

    /*angle+=dist2;
    _holder.x=Math.cos(angle)*900;
    _holder.z=Math.sin(angle)*900;
    var new_zoom=20-stage.mouseY*0.015;
    camera.zoom += ( new_zoom – camera.zoom ) * 0.95;*/
    //camera.y= camera.zoom*90+60;
    }
    }
    }


  12. Daniel Sedlacek
    Visit Site
    September 20th, 2010

    Hi Guys,

    are using the new class I left in the comment?

    @Arindam : what is your problem?

    Sorry but I can not give you more support on this, it has been so long ago since I worked on it.


  13. Keiran
    Visit Site
    Máj 31st, 2011

    Hi!
    This is a bit older but very useful if you want to create 3D pie charts.
    Arindam’s script is a good base for this task. To get rid of the problem Arindam described, you have to create layers for each segment.
    Just add the following line to the function where Cylinder3D is instantiated:
    var layer:ViewportLayer = viewport.getChildLayer(segmentedCylinder);

    It has the same effect as segmentedCylinder.useOwnContainer = true; but uses less processor power.

Sorry, comments for this entry are closed at this time.

Images is enhanced with WordPress Lightbox JS by Zeo