Archive

Posts Tagged ‘papervision3d’

Papervision3D : Creating a custom mesh

January 13th, 2009

Hi:

A while back, a friend of mine was working on a project in which he needed to have several trapezoid like objects floating in space which he would then later manipulate their positions to form a larger shape. We figured that the best way to go about it was to create our own trapezoid primitive in papervision using the available core classes. Needless to say, the project deadline was too close to even try it out so we ended up using trapezoid like movieclips as materials. Of course using a natively drawn mesh would have done wonders to the processor but I guess it is what is its. The thought of creating my own custom primitive (or better said, custom mesh) in papervision still lingered though. Finally, I got time to dig in and give it a shot and the results are not to shabby if I do say so myself!

Start of by creating an instance of the Trianglemesh3D class and some variables we will need in a bit:

var mesh:TriangleMesh3D = new TriangleMesh3D();
var width:Number = 500;
var height:Number = 500;
var difference:Number = .25

A mesh is basically 2 or more triangles used to form a shape. Each triangle in turn is made up of 3 vertices. The trapezoid class we’ll be examining will only use two triangles to create the shape. The first thing we need to do is plot out the vertices. A trapezoid has four corners hence we need 4 vertices:

var tl:Vertex3D = new Vertex3D(-width*0.5, height*0.5, 0); // top left
var tr:Vertex3D = new Vertex3D(width*0.5, height*0.5, 0); // top right
var br:Vertex3D = new Vertex3D(width*0.5 - (width * difference), -height*0.5, 0); // bottom right
var bl:Vertex3D = new Vertex3D(-width*0.5 + (width * difference), -height*0.5, 0); // bottom left

In the code above, “width” and “height” are self explanatory, “difference” is a number (0 – .5) indicating the length of the shorter side of the trapezoid in relation to the longest side.

Don’t forget to add the vertices to the geometry of our mesh:

mesh.geometry.vertices.push(tl, tr, bl, br);

Now that we have our vertices plotted, we need to “connect the dots” to create our triangles. In order to create our triangles we need to use the Triangle3D class which accepts as arguments the mesh which will hold the triangle, an array of vertices to draw the triangle on, a material, and an array containing 3 NumberUV objects which I will explain later in this post.

Let’s set up our vertex arrays, one for each triangle:

var triangle_1_vertices:Array = [bl, tl, tr];
var triangle_2_vertices:Array = [br, bl, tr];

Now let’s set up our corresponding NumberUV arrays. Again, one for each triangle:

var textureMap_1:Array = [new NumberUV(0, 0), new NumberUV(0, 1), new NumberUV(1, 1)];
var textureMap_2:Array = [new NumberUV(1, 0), new NumberUV(0, 0), new NumberUV(1, 1)];;

The UVs basically tell the Triangle3D instance how to map the texture. (0, 0) would be bottom-left, (0, 1) is top-left, top-right is (1, 1) and bottom-right is (1, 0).

Let’s quickly throw together the material we will be using for our mesh:

var material:ColorMaterial = new ColorMaterial(0x00CC00);
var wireMaterial:WireframeMaterial = new WireframeMaterial(0x000000);
var composite:CompositeMaterial = new CompositeMaterial();
composite.addMaterial(material);
composite.addMaterial(wireMaterial);

Now to set up our triangles:

var triangle_1_face:Triangle3D = new Triangle3D(mesh, triangle_1_vertices, composite, textureMap_1);
var triangle_2_face:Triangle3D = new Triangle3D(mesh, triangle_2_vertices, composite, textureMap_2);

Now we add our triangles (or faces) to the geometry of our mesh and finally tell the mesh that its geometry is set to be rendered:

mesh.geometry.faces.push(triangle_1_face, triangle_2_face);
mesh.geometry.ready = true;

We’re done! You can now add your mesh to the 3d scene and manipulate as you would any DisplayObject3D!

Here is the Trapezoid class I made using the code we just used above:

package
{
   import org.papervision3d.core.geom.TriangleMesh3D;
   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.MaterialObject3D;

   public class Trapezoid extends TriangleMesh3D
   {
     
      private var height:Number;
      private var width:Number;
      private var difference:Number;
     
      public function Trapezoid($material:MaterialObject3D = null, $width:Number = 500, $height:Number = 500, $difference:Number = 0.5)
      {
         super($material, new Array(), new Array());
         width = $width;
         height = $height;
         difference = $difference * 0.5;
         buildTrapazoid();
      }
     
      private function buildTrapazoid():void
      {
         var materialInstance:MaterialObject3D = material;
         var arrVertices:Array = geometry.vertices;
         var arrFaces:Array = geometry.faces;
         
         // create vertices
         var tl:Vertex3D = new Vertex3D(-width*0.5, height*0.5, 0); // top left
         var tr:Vertex3D = new Vertex3D(width*0.5, height*0.5, 0); // top right
         var br:Vertex3D = new Vertex3D(width*0.5 - (width * difference), -height*0.5, 0); // bottom right
         var bl:Vertex3D = new Vertex3D(-width*0.5 + (width * difference), -height*0.5, 0); // bottom left
         
         //add vertices
         arrVertices.push(tl, tr, bl, br);
         
         // create faces
         var triangle_1_vertices:Array = [bl, tl, tr];
         var triangle_2_vertices:Array = [br, bl, tr];
         
         var textureMap_1:Array = [new NumberUV(0, 0), new NumberUV(0, 1), new NumberUV(1, 1)];
         var textureMap_2:Array = [new NumberUV(1, 0), new NumberUV(0, 0), new NumberUV(1, 1)];
         
         var triangle_1_face:Triangle3D = new Triangle3D(this, triangle_1_vertices, materialInstance, textureMap_1);
         var triangle_2_face:Triangle3D = new Triangle3D(this, triangle_2_vertices, materialInstance, textureMap_2);
           
         // add faces      
         arrFaces.push(triangle_1_face, triangle_2_face);
         
         geometry.ready = true;
      }
     
   }
}

And here is a document class which shows you how to use it:

package
{
   import flash.events.Event;
   
   import org.papervision3d.materials.*;
   import org.papervision3d.materials.special.CompositeMaterial;
   import org.papervision3d.view.BasicView;

   public class CustomMesh extends BasicView
   {
      private var trapazoid:Trapazoid;

      public function CustomMesh()
      {
         camera.focus = 11;
         camera.zoom = 100;
         
         var material:ColorMaterial = new ColorMaterial(0x00CC00);
         var wireMaterial:WireframeMaterial = new WireframeMaterial(0x000000);
         var composite:CompositeMaterial = new CompositeMaterial();
         composite.addMaterial(material);
         composite.addMaterial(wireMaterial);
         
         composite.doubleSided = true;
         
         /*var movieMat:MovieAssetMaterial = new MovieAssetMaterial("Badge", true);
         movieMat.doubleSided = true;*/


         trapazoid = new Trapazoid(composite, 181, 246, .5);

         scene.addChild(trapazoid);
         startRendering();
      }

      override protected function onRenderTick(event:Event = null):void
      {
         trapazoid.yaw(2);
         super.onRenderTick(event);
      }
   }
}

These are the very basic first steps in creating your very own primitives in papervision. If you get build more complex, feature rich implementations please do let me know!!

Lab, papervision3d ,

Dragging objects in Papervision3D

December 26th, 2008

A few months ago, Andy Zupko added some methods to Papervision3D which facilitated the ability to drag objects in 3d space. I collected those methods and placed them in a static class called RayTracer. The class currently has only one method which returns a Number3D object with the coordinates in 3D space based on the position of your mouse on a Plane3D object.

Andy says:

In lay terms – this basically shoots a ray from the camera, through where the mouse is, into 3D space. You can then do whatever you want knowing where that ray is.

This is the code for the test above:

package
{
    import flash.events.Event;
   
    import org.papervision3d.core.math.Number3D;
    import org.papervision3d.materials.ColorMaterial;
    import org.papervision3d.materials.WireframeMaterial;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.Plane;
    import org.papervision3d.objects.primitives.Sphere;
    import org.papervision3d.view.BasicView;

    public class Dragging3D extends BasicView
    {
       
        private var sphere:Sphere;
       
        public function Dragging3D()
        {
            initialize();
            createObjects();
            startRendering();
        }
       
        private function initialize():void
        {
            camera.zoom = 11;
            camera.focus = 100;
            camera.z = -2000;
            camera.y = 200;
        }
       
        private function createObjects():void
        {
            var plane:Plane = new Plane(new ColorMaterial(0x0FFFF00), 1000, 1000, 10, 10);
            plane.rotationX = 90;
            scene.addChild(plane);
           
            var wireMaterial:WireframeMaterial = new WireframeMaterial();
            sphere = new Sphere(wireMaterial, 50, 10, 10);
            sphere.useOwnContainer = true;
            sphere.y = 25;
            scene.addChild(sphere);
        }
       
        override protected function onRenderTick(event:Event = null):void
        {
            super.onRenderTick(event);
           
            var intersect:Number3D = RayTracer.getIntersection(viewport, camera, [0, 1, 0]);

            sphere.x = intersect.x;
            sphere.z = intersect.z;
        }
    }
}

The magic happens in the onRenderTick method. This is where we added the RayTracer static method. The first two arguments are self explanatory. The final argument is an array representing the “normal” on an imaginary plane:

[0, 1, 0] = XY plane = objects dragged on the x and z axises
[1, 0, 0] = YZ plane = objects dragged on the y and z axises
[0, 0, 1] = XZ plane = objects dragged on the x and y axises

This is the RayTracer class:

package
{
    import org.papervision3d.core.math.Number3D;
    import org.papervision3d.core.math.Plane3D;
    import org.papervision3d.core.proto.CameraObject3D;
    import org.papervision3d.view.Viewport3D;

    public class RayTracer
    {
       
        public static function getIntersection(viewport:Viewport3D, camera:CameraObject3D, normal:Array):Number3D
        {
            var plane3D:Plane3D = new Plane3D(new Number3D(normal[0], normal[1], normal[2]), new Number3D(0, 0, 0));
            var cameraPosition:Number3D = new Number3D(camera.x, camera.y, camera.z);
            var ray:Number3D = camera.unproject(viewport.containerSprite.mouseX, viewport.containerSprite.mouseY);
            ray = Number3D.add(ray, cameraPosition);
            var intersect:Number3D = plane3D.getIntersectionLineNumbers(cameraPosition, ray);
            return intersect;
        }
       
    }
}

Should be pretty simple to implement. Hit me back if you have any questions!

Experiment, Lab , ,

Exploring a Papervision3D class – Text3D

December 13th, 2008

Hi:

As some of you may know VectorVision (vector fonts in flash) was added into Papervision3D last week so I decided to check out the new typography package. To my surprise, it was fairly simple to set up. This is a small example.

package
{
    import flash.events.Event;
   
    import org.papervision3d.materials.special.Letter3DMaterial;
    import org.papervision3d.typography.Font3D;
    import org.papervision3d.typography.Text3D;
    import org.papervision3d.typography.fonts.HelveticaRoman;
    import org.papervision3d.view.BasicView;

    public class SampleText3D extends BasicView
    {
       
        private var text3D:Text3D;
        private var textMaterial:Letter3DMaterial;
        private var font3D:Font3D;
               
        public function SampleText3D()
        {
            initialize();
            startRendering();
        }
       
        private function initialize():void
        {
            textMaterial = new Letter3DMaterial(0x00FFFF);
            font3D = new HelveticaRoman();
            text3D = new Text3D("Hello there.", font3D, textMaterial);
            text3D.scale = 2;
            scene.addChild(text3D);
        }
       
        override protected function onRenderTick(event:Event = null):void
        {
            super.onRenderTick(event);
            text3D.yaw(0.5);
            text3D.roll(0.5);
        }
    }
}

Experiment, Lab ,

Exploring a Papervision3D class – MovieAssetParticleMaterial

December 12th, 2008
Comments Off

Hi All!

Not to long ago, I decided to go on a reconnaissance mission and plunged into the Papervison3D classes. I decided to read up on a class a week and just devour it ans learn as much about it as I could. I didn’t get the chance to do that until now. Here’s the first class : MovieAssetParticleMaterial and below is an example of what you can do with it.

The MovieAssetParticleMaterial is the material used for the Particle class which in turn is added to an instance of the Particles class using its “addParticle” method. I know that may have sounded a bit confusing, but here’s the break down. In the code for the example, I created 150 particles in a loop and add each particle to an array for later use:

for(var a:Number = 0; a<Particles3D.PARTICLE_COUNT; a++){
    var particleMaterial:MovieAssetParticleMaterial = new MovieAssetParticleMaterial("orb", true);
    particleMaterial.smooth = true;
   
    var particles3D:Particles = new Particles("particles_"+a);
    var particle:Particle = new Particle(particleMaterial, 2.5);
   
    particles3D.addParticle(particle);
    container3D.addChild(particles3D);
   
    arrParticles.push(particles3D);
}

After you have your particles set up, you would need some sort of 3D shape to map them to. Start off with something as simple as a sphere:

sphere = new Sphere(new WireframeMaterial(0x000000), 200, 15, 10);

Notice that all we did was create an instance of it, we really never added it to the scene. That’s because all we need is the vertice coordinates of the sphere in order to map the particles to them. We alreay have all our particles in an array, now we need to get all the vertices for the sphere in an array. Luckily, that is a very simple task:

var vertices:Array = sphere.geometry.vertices;

Now all we need to do is place a particle on each vertice by means of a loop and a little help from Tweener as so:

var vertices:Array = sphere.geometry.vertices;
activeVertices = vertices.length;
selectedShape = sphere;
for(var a:Number = 0; a<activeVertices; a++){
    Tweener.addTween(arrParticles[a], {x:vertices[a].x,
                           y:vertices[a].y,
                           z:vertices[a].z,
                           time:2,
                           transition:"easeInStrong"});
}

Thats pretty much it! I’m sure there’s loads of really cool stuff that can be done with 3D particles. Below is the full code for the example above. Enjoy!

package
{
    import caurina.transitions.Tweener;
   
    import flash.events.Event;
   
    import org.papervision3d.core.geom.Particles;
    import org.papervision3d.core.geom.renderables.Particle;
    import org.papervision3d.materials.WireframeMaterial;
    import org.papervision3d.materials.special.MovieAssetParticleMaterial;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.Cylinder;
    import org.papervision3d.objects.primitives.Sphere;
    import org.papervision3d.view.BasicView;

    public class Particles3D extends BasicView
    {
        private static const PARTICLE_COUNT:uint = 150;
        private var sphere:Sphere;
        private var cylinder:Cylinder;
        private var container3D:DisplayObject3D;
        private var selectedShape:DisplayObject3D;
        private var arrParticles:Array;
        private var activeVertices:Number;
       
        public function Particles3D()
        {
            super();
            createParticles();
            createObjects3D();
            mapParticlesToSphere();
            startRendering();
        }
       
        private function createParticles():void
        {
            container3D = new DisplayObject3D();
            arrParticles = [];
           
            for(var a:Number = 0; a<Particles3D.PARTICLE_COUNT; a++){
                var particleMaterial:MovieAssetParticleMaterial = new MovieAssetParticleMaterial("orb", true);
                particleMaterial.smooth = true;
               
                var particles3D:Particles = new Particles("particles_"+a);
                var particle:Particle = new Particle(particleMaterial, 2.5);
               
                particles3D.addParticle(particle);
                container3D.addChild(particles3D);
               
                arrParticles.push(particles3D);
            }
           
            scene.addChild(container3D);
        }
       
        private function createObjects3D():void
        {
            sphere = new Sphere(new WireframeMaterial(0x000000), 200, 15, 10);
            cylinder = new Cylinder(new WireframeMaterial(0x000000), 60, 840, 10, 10);
        }
       
        private function mapParticlesToSphere():void
        {
            var vertices:Array = sphere.geometry.vertices;
            activeVertices = vertices.length;
            selectedShape = sphere;
            for(var a:Number = 0; a<activeVertices; a++){
                Tweener.addTween(arrParticles[a], {x:vertices[a].x,
                                                   y:vertices[a].y,
                                                   z:vertices[a].z,
                                                   time:2,
                                                   transition:"easeInStrong"});
            }
            Tweener.addTween(arrParticles[a], {time:4, onComplete:mapParticlesToCylinder});
        }
       
        private function mapParticlesToCylinder():void
        {
            var vertices:Array = cylinder.geometry.vertices;
            activeVertices = vertices.length;
            selectedShape = cylinder
            for(var a:Number = 0; a<activeVertices; a++){
                Tweener.addTween(arrParticles[a], {x:vertices[a].x,
                                                   y:vertices[a].y,
                                                   z:vertices[a].z,
                                                   time:2,
                                                   transition:"easeInStrong"});
            }
            Tweener.addTween(arrParticles[a], {time:4, onComplete:mapParticlesToSphere});
        }
       
        private function hideUnusedParticles():void
        {
            for (var a:Number = 0; a < Particles3D.PARTICLE_COUNT; a++) {
                if (a < selectedShape.geometry.vertices.length) {
                    arrParticles[a].visible = true;
                } else {
                    arrParticles[a].visible = false;
                }
            }
        }
       
        override protected function onRenderTick(event:Event=null):void
        {
            super.onRenderTick(event);
            container3D.yaw(.5);
            container3D.roll(.5);
            hideUnusedParticles();
        }      
       
    }
}
;

Experiment, Lab , ,

Applying modifiers to 3D objects in Papervision3D using AS3Mod

December 9th, 2008

I have been meaning to dig into the as3mod library for a while now but never had the time because I was working on a project. Finally I found some time and dove right into it! At first, I had no idea what I was getting into, but as I read deeper into the classes and devoured the documentation, stuff started to make sense. So much that I decided to build a very simple demonstration of the different modifiers available:

The modifiers are really simple to apply to any 3d object including collada files!! Below is the document class used in the example. If you go through it, I’m sure you’ll pick up pretty fast.

You’re gonna nee d to grab the as3mod library found here and the latest version of papervision3d here.

package
{
    import com.as3dmod.IModifier;
    import com.as3dmod.ModifierStack;
    import com.as3dmod.modifiers.Bend;
    import com.as3dmod.modifiers.Bloat;
    import com.as3dmod.modifiers.Noise;
    import com.as3dmod.modifiers.Perlin;
    import com.as3dmod.modifiers.Skew;
    import com.as3dmod.modifiers.Taper;
    import com.as3dmod.modifiers.Twist;
    import com.as3dmod.plugins.pv3d.LibraryPv3d;
    import com.as3dmod.util.ModConstant;
    import com.as3dmod.util.Phase;
   
    import flash.events.Event;
   
    import org.papervision3d.materials.ColorMaterial;
    import org.papervision3d.materials.WireframeMaterial;
    import org.papervision3d.materials.special.CompositeMaterial;
    import org.papervision3d.materials.utils.MaterialsList;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.view.BasicView;

    public class SimpleMod extends BasicView
    {
        private var cube:Cube;
        private var modStack:ModifierStack;
        private var bend:Bend;
        private var bendPhase:Phase;
        private var perlin:Perlin;
        private var noise:Noise;
        private var skew:Skew;
        private var skewPhase:Phase;
        private var taper:Taper;
        private var taperPhase:Phase;
        private var twist:Twist;
        private var twistPhase:Phase;
        private var bloat:Bloat;
        private var bloatPhase:Phase;
       
        public function SimpleMod()
        {
            camera.z = -1500;
           
            cerateCube();
            addModifiers();
            configureComboBox();
            startRendering();
        }
       
        private function cerateCube():void
        {
            var colorMat:ColorMaterial = new ColorMaterial(0x00FF00);
            var wireMat:WireframeMaterial = new WireframeMaterial(0xFFFFFF);
            var compositeMat:CompositeMaterial = new CompositeMaterial();
            compositeMat.addMaterial(colorMat);
            compositeMat.addMaterial(wireMat);
           
            var materialsList:MaterialsList = new MaterialsList({ all:compositeMat });
           
            cube = new Cube(materialsList, 500, 500, 1000, 10, 10, 10);
           
            scene.addChild(cube);
        }
       
        private function addModifiers():void
        {
            modStack = new ModifierStack(new LibraryPv3d, cube);
           
            bend = new Bend(0.5, 0.5);
            bendPhase = new Phase();
           
            skew = new Skew(0);
            skewPhase = new Phase();
           
            taper = new Taper(3);
            taper.setFalloff(0.2, 0.5);
            taper.power = 6;
            taperPhase = new Phase();
           
            twist = new Twist(Math.PI / 2);
            twistPhase = new Phase();
           
            perlin = new Perlin(3);
            perlin.setFalloff(1, 0);
           
            noise = new Noise(25);
            noise.constraintAxes(ModConstant.X | ModConstant.Y);
           
            bloat = new Bloat();
        }
       
        private function configureComboBox():void
        {
            modifierCB.addItem({label:"Bend", data:bend});
            modifierCB.addItem({label:"Skew", data:skew});
            modifierCB.addItem({label:"Taper", data:taper});
            modifierCB.addItem({label:"Twist", data:twist});
            modifierCB.addItem({label:"Perlin", data:perlin});
            modifierCB.addItem({label:"Noise", data:noise});
            modifierCB.addItem({label:"Bloat", data:bloat});
            modifierCB.addEventListener(Event.CHANGE, changeHandler);
        }
       
        private function changeHandler($event:Event):void
        {
            modStack.clear();
            modStack.addModifier(modifierCB.selectedItem.data as IModifier);
        }
       
        override protected function onRenderTick(event:Event=null):void
        {
            super.onRenderTick(event);
           
            cube.yaw(.5);
             
            bendPhase.value += 0.05;
            bend.force = bendPhase.phasedValue * .5;
           
            skewPhase.value += 0.05;
            skew.force = skewPhase.phasedValue * 100;
           
            taperPhase.value += 0.05;
            taper.force = taperPhase.absPhasedValue * 2;
           
            twistPhase.value += 0.05;
            twist.angle = Math.PI / 8 * twistPhase.phasedValue;
           
            modStack.apply();
        }
    }
}

Enjoy!!

as3mod ,