Michael Jackson Pearl Jam Stevie Ray Vaughan Ozzy Osbourne Finntroll MP3 list A Fine Frenzy Capone Phil Collins Shakira Pink Floyd Keane

Archive for the 'AS3' Category

Papervision Isometric View & Pathfinding with as3isolib and A* (A Star)

View Example

This week's example / tutorial is how to mix Papervision with as3isolib and A* (pronounced A Star) for a nice 3D isometric pathfinding experience. The version of A* that I am using comes straight out of Keith Peters book AdvancedEd ActionScript 3.0 Animation. Anyone looking to cover advanced animation topics in Flash should buy a copy of this book. It is excellent.

This tutorial will not cover how to create the A* classes but rather show you how to blend 3 things together; Papervision, as3isolib, and A* (the Keith Peters version). If you're just getting started using as3IsoLib take a look at these great tutorials and download the code: http://code.google.com/p/as3isolib/w/list

We will cover a few of the things that you need to successfully merge the pathfinding and 3D experience.

First item is our camera setting. We are setting ortho to true because this actually gives us a true isometric camera feel.

Actionscript:
  1. camera.ortho = true;

Inside of our makeGrid function we are setting up the groundwork for our pathfinding and isometric world. This grid has no information about the cellsize, just which parts of it are walkable and not walkable.

Actionscript:
  1. protected function makeGrid():void
  2. {
  3.     pathGrid = new Grid(10, 10);
  4.     for(var i:int = 0; i <20; i++)
  5.     {
  6.         pathGrid.setWalkable(Math.floor(Math.random() * 8) + 2,
  7.                           Math.floor(Math.random() * 8)+ 2,
  8.                           false);
  9.     }
  10.     drawGrid();
  11. }

Next we move on to drawGrid() which begins to connect the pathfinding and as3isolib

One of the great thing about as3isolib which is similar to papervision is that it has native objects that you can skin, such as boxes and polygons.

Here inside of drawGrid we run through the columns and rows that we setup in our makeGrid function. From the information in these loops we can get back the node information of the grid and check if an item is walkable or not walkable. If it is walkable we create a standard size box with a height of 0, if it is not walkable we create that same standard box but with a height of 40 so we can start to define our available paths. If the box is walkable we also want to set a mouseEvent so that we can select it. Finally we add these items to our isoScene.

Actionscript:
  1. for(var i:int = 0; i <pathGrid.numCols; i++)
  2. {
  3.     for(var j:int = 0; j <pathGrid.numRows; j++)
  4.     {
  5.         var node:Node = pathGrid.getNode(i, j);
  6.         var box:IsoBox = new IsoBox();
  7.  
  8.         if (node.walkable)
  9.         {
  10.             box.setSize(cellSize, cellSize, 0);
  11.             box.addEventListener(MouseEvent.CLICK, onGridItemClick);
  12.         }
  13.         else
  14.         {
  15.             box.setSize(cellSize, cellSize, 40);
  16.         }
  17.        
  18.         box.moveTo(i * cellSize, j * cellSize, 0);
  19.         isoScene.addChild(box);
  20.     }
  21. }

Another item within the drawGrid function is our playerHelper. We are only using this playerHelper so that we can get it's coordinates to follow along in papervision. We set him to the same size as our box items.

Actionscript:
  1. playerHelper.setSize(cellSize, cellSize, 10);

The next important step is setting up a way to have our viewport inside of our isoScene. We first create a nice wrapper for our viewport which is a native IsoSprite object. We then associate our viewport as one of the sprites inside of our isoSprite.

Actionscript:
  1. isoSprite = new IsoSprite();
  2. isoSprite.sprites = [viewport];
  3. isoScene.addChild(isoSprite);

Notice that we add our sprites kind of like we add filters for a movieclip. We are passing it an array.

Actionscript:
  1. //isoSprite.sprites = [viewport,moreStuff] - pass in an array of objects

Now lets see what happens when a grid item is clicked. First we gather the information about where we want to go. We gather that by getting the item that was clicked and getting its x & y positions divided by the cellSize. Then we give pathGrid.setEndNode those coordinates. Next we gather the information about where our playerHelper currently is divided by the cellSize and pass that information to pathGrid.setStartNode.

Actionscript:
  1. protected function onGridItemClick(evt:ProxyEvent):void
  2.         {
  3.             var box:IsoBox = evt.target as IsoBox;
  4.            
  5.             //Get and set End Nodes (where are we going)
  6.             var xpos:int = (box.x)/cellSize
  7.             var ypos:int = Math.floor(box.y / cellSize)
  8.             pathGrid.setEndNode(xpos,ypos );
  9.  
  10.             //Get and set Start Node (where are we now)
  11.             xpos = Math.floor(playerHelper.x / cellSize);
  12.             ypos = Math.floor(playerHelper.y / cellSize);
  13.             pathGrid.setStartNode(xpos, ypos);
  14.  
  15.             //Find our path
  16.             findPath();
  17.         }

Finally we call findPath(). This is the fun part. First we create a new instance of AStar and gather the path information that we gathered when we ran the onGridItemClick function.

We can now run through that loop and get each x and y portion of that loop. We simply add a tween with a delay that is the same time as our speed. This will allow you to see each move and when it is complete it will start it's next move.

Actionscript:
  1. protected function findPath():void
  2. {
  3.     var astar:AStar = new AStar();
  4.     var speed:Number = .3;
  5.     if(astar.findPath(pathGrid))
  6.     {
  7.         path = astar.path;
  8.     }
  9.    
  10.     for (var i:int = 0; i <path.length; i++)
  11.     {
  12.         var targetX:Number = path[i].x * cellSize;
  13.         var targetY:Number = path[i].y * cellSize;
  14.        
  15.         Tweener.addTween(playerHelper, { x:targetX, y:targetY, delay:speed * i , time:speed, transition:"linear" } );
  16.     }
  17. }

We now just need to look at how to sort the papervision with the as3isolib objects

Inside of our onRenderTick function which is an override from BasicView we use this to render our isoScene which is part of as3isolib and change the x,y coordinates of our sphere. We are basically following around the screenX and screenY of our playerHelper. The next and very important part of this is the depth sorting. We are pulling the depth at all times from the playerHelper object and assigning our isoSprite (which has our viewport in it) to that depth. Now we can watch as our 3D objects find their pretty little paths and sort without issue.

Actionscript:
  1. override protected function onRenderTick(event:Event = null):void
  2. {
  3.     super.onRenderTick(event);
  4.     isoScene.render();
  5.     sphere.x = playerHelper.screenX;
  6.     sphere.y = -playerHelper.screenY - 15;
  7.     isoScene.setChildIndex(isoSprite, isoScene.getChildIndex(playerHelper));
  8. }

Here is the full code:

Actionscript:
  1. package
  2. {
  3.     import as3isolib.display.IsoSprite;
  4.     import as3isolib.display.IsoView;
  5.     import as3isolib.display.primitive.IsoBox;
  6.     import as3isolib.display.primitive.IsoPrimitive;
  7.     import as3isolib.display.scene.IsoGrid;
  8.     import as3isolib.display.scene.IsoScene;
  9.     import bit101.AStar;
  10.     import bit101.Grid;
  11.     import bit101.Node;
  12.     import caurina.transitions.Tweener;
  13.     import flash.display.StageAlign;
  14.     import flash.display.StageScaleMode;
  15.     import flash.events.Event;
  16.  
  17.     import eDpLib.events.ProxyEvent;
  18.    
  19.     import flash.display.Sprite;
  20.     import flash.events.MouseEvent;
  21.    
  22.     import org.papervision3d.materials.WireframeMaterial;
  23.     import org.papervision3d.objects.primitives.Sphere;
  24.     import org.papervision3d.view.BasicView;
  25.  
  26.     public class Main extends BasicView
  27.     {
  28.         protected var cellSize:int = 50;
  29.         protected var pathGrid:Grid;
  30.         protected var playerHelper:IsoPrimitive;
  31.         protected var path:Array;
  32.         protected var isoSprite:IsoSprite;
  33.         protected var isoView:IsoView;
  34.         protected var isoScene:IsoScene;
  35.         protected var sphere:Sphere;
  36.        
  37.         public function Main()
  38.         {
  39.             super(800, 600, false);
  40.             stage.align = StageAlign.TOP_LEFT;
  41.             stage.scaleMode = StageScaleMode.NO_SCALE;
  42.            
  43.             create3D();
  44.             makeGrid();
  45.             startRendering();
  46.         }
  47.  
  48.         protected function create3D():void
  49.         {
  50.             sphere = new Sphere(new WireframeMaterial(),20);
  51.             scene.addChild(sphere);
  52.             camera.ortho = true;
  53.         }
  54.  
  55.         protected function makeGrid():void
  56.         {
  57.             pathGrid = new Grid(10, 10);
  58.             for(var i:int = 0; i <20; i++)
  59.             {
  60.                 pathGrid.setWalkable(Math.floor(Math.random() * 8) + 2,
  61.                                   Math.floor(Math.random() * 8)+ 2,
  62.                                   false);
  63.             }
  64.             drawGrid();
  65.         }
  66.        
  67.         protected function drawGrid():void
  68.         {
  69.             isoScene       = new IsoScene();
  70.             playerHelper    = new IsoPrimitive();
  71.             isoSprite     = new IsoSprite();
  72.             isoView         = new IsoView();
  73.  
  74.             for(var i:int = 0; i <pathGrid.numCols; i++)
  75.             {
  76.                 for(var j:int = 0; j <pathGrid.numRows; j++)
  77.                 {
  78.                     var node:Node = pathGrid.getNode(i, j);
  79.                     var box:IsoBox = new IsoBox();
  80.  
  81.                     if (node.walkable)
  82.                     {
  83.                         box.setSize(cellSize, cellSize, 0);
  84.                         box.addEventListener(MouseEvent.CLICK, onGridItemClick);
  85.                     }
  86.                     else
  87.                     {
  88.                         box.setSize(cellSize, cellSize, 40);
  89.                     }
  90.                    
  91.                     box.moveTo(i * cellSize, j * cellSize, 0);
  92.                     isoScene.addChild(box);
  93.                 }
  94.             }
  95.  
  96.             //Set properties for player helper
  97.             playerHelper.setSize(cellSize, cellSize, 10);
  98.            
  99.             //Set properties for isoView
  100.             isoView.setSize(stage.stageWidth, stage.stageHeight);
  101.            
  102.             //Set proper position for viewport
  103.             viewport.x = -stage.stageWidth / 2;
  104.             viewport.y = -stage.stageHeight / 2;
  105.  
  106.             //Add viewport to the isoSprite
  107.             isoSprite.sprites = [viewport];
  108.            
  109.             //Add the isoSprite and playerHelper to the isoScene
  110.             isoScene.addChild(isoSprite);
  111.             isoScene.addChild(playerHelper);
  112.            
  113.             //Add the isoScene to the isoView
  114.             isoView.addScene(isoScene);
  115.            
  116.             //Add the isoView to the stage
  117.             addChild(isoView);
  118.         }
  119.  
  120.         protected function onGridItemClick(evt:ProxyEvent):void
  121.         {
  122.             var box:IsoBox = evt.target as IsoBox;
  123.            
  124.             //Get and set End Nodes (where are we going)
  125.             var xpos:int = (box.x)/cellSize
  126.             var ypos:int = Math.floor(box.y / cellSize)
  127.             pathGrid.setEndNode(xpos,ypos );
  128.  
  129.             //Get and set Start Node (where are we now)
  130.             xpos = Math.floor(playerHelper.x / cellSize);
  131.             ypos = Math.floor(playerHelper.y / cellSize);
  132.             pathGrid.setStartNode(xpos, ypos);
  133.  
  134.             //Find our path
  135.             findPath();
  136.         }
  137.  
  138.         protected function findPath():void
  139.         {
  140.             var astar:AStar = new AStar();
  141.             var speed:Number = .3;
  142.             if(astar.findPath(pathGrid))
  143.             {
  144.                 path = astar.path;
  145.             }
  146.            
  147.             for (var i:int = 0; i <path.length; i++)
  148.             {
  149.                 var targetX:Number = path[i].x * cellSize;
  150.                 var targetY:Number = path[i].y * cellSize;
  151.                
  152.                 Tweener.addTween(playerHelper, { x:targetX, y:targetY, delay:speed * i , time:speed, transition:"linear" } );
  153.             }
  154.         }
  155.        
  156.         override protected function onRenderTick(event:Event = null):void
  157.         {
  158.             super.onRenderTick(event);
  159.            
  160.             //Render the isoScene
  161.             isoScene.render();
  162.            
  163.             //Place our 3D object at the correct location (following our playerHelper)
  164.             sphere.x = playerHelper.screenX;
  165.             sphere.y = -playerHelper.screenY - 15;
  166.            
  167.             /*
  168.            
  169.             Set the depth of our isoSprite which holds our viewport to the proper depth.
  170.            
  171.             NOTE: as3isolib objects - the depth sorting is done automatically,
  172.             we just need to tap into that
  173.            
  174.             */
  175.            
  176.             isoScene.setChildIndex(isoSprite, isoScene.getChildIndex(playerHelper));
  177.         }   
  178.     }
  179. }

Post to Twitter Post to Delicious Delicious Post to Digg Digg This Post Post to Facebook Facebook Post to StumbleUpon Stumble This Post

A Simple Papervision Carousel

Papervision 3D Carousel

download-source

This week I set out to create a Papervision Carousel in it's simplest form. At the heart of this carousel is a simple "for" loop / math which places the items in a circle in 3D space

Actionscript:
  1. for (var i:int = 0; i <planes.length; i++)
  2. {
  3.     var angle:Number    = Math.PI * 2 / numItems * i;
  4.     var plane:Plane     = planes[i];
  5.     plane.x             = Math.cos(angle) * radius;
  6.     plane.z             = Math.sin(angle) * radius;
  7.     plane.rotationY     = -360 / numItems * i - 90;
  8. }

Then to rotate our carousel we apply some similar math

Actionscript:
  1. var rotateTo:Number = (-360 / numItems) * currentItem + 90;
  2. TweenLite.to(planesHolder, 1, { rotationY:rotateTo, ease:Quint.easeInOut } );

This code allows us to just increment currentItem and rotate our carousel. Another easy add-on would be to setup a navigation along the bottom where you could control and change the currentItem to a specific number to rotate right to that section of the carousel.

It's also very easy to customize the number of items and radius of the carousel by adjusting these numbers.

Actionscript:
  1. protected var numItems:Number = 20;
  2. protected var radius:Number = 500;

Here is the full code.

Actionscript:
  1. package
  2. {
  3.     import flash.display.DisplayObject;
  4.     import flash.display.MovieClip;
  5.     import flash.display.Sprite;
  6.     import flash.events.Event;
  7.     import flash.events.MouseEvent;
  8.     import gs.easing.Quint;
  9.     import gs.TweenLite;
  10.     import org.papervision3d.materials.BitmapFileMaterial;
  11.     import org.papervision3d.objects.DisplayObject3D;
  12.     import org.papervision3d.objects.primitives.Plane;
  13.     import org.papervision3d.view.BasicView;
  14.    
  15.     /**
  16.      * ...
  17.      * @author Charlie Schulze, charlie[at]woveninteractive[dot]com
  18.      */
  19.    
  20.     public class Main extends BasicView
  21.     {
  22.         protected var planes:Array = [];
  23.         protected var numItems:Number = 20;
  24.         protected var radius:Number = 500;
  25.         protected var currentItem:Number = 0;
  26.        
  27.         protected var mat:BitmapFileMaterial;
  28.         protected var planesHolder:DisplayObject3D;
  29.         protected var rightBtn:Sprite;
  30.         protected var leftBtn:Sprite;
  31.        
  32.         public function Main():void
  33.         {
  34.             super();
  35.             init();
  36.         }
  37.         protected function init():void
  38.         {
  39.             createChildren();
  40.             createButtons();
  41.             commitProperties();
  42.             startRendering();
  43.         }
  44.         protected function createChildren():void
  45.         {
  46.            
  47.             planesHolder = new DisplayObject3D();
  48.            
  49.             //Create Material
  50.             mat             = new BitmapFileMaterial("images/queen.gif");
  51.             mat.smooth   = true;
  52.             mat.doubleSided = true;
  53.            
  54.             for (var i:int = 0; i <numItems; i++)
  55.             {
  56.                 var plane:Plane = new Plane(mat, 150, 234);
  57.                 planes.push(plane);
  58.                
  59.                 //Add plane to the scene
  60.                 planesHolder.addChild(plane);
  61.             }
  62.             scene.addChild(planesHolder);
  63.         }
  64.        
  65.         protected function commitProperties():void
  66.         {
  67.             //Set properties of our planes
  68.             for (var i:int = 0; i <planes.length; i++)
  69.             {
  70.                 var angle:Number    = Math.PI * 2 / numItems * i;
  71.                 var plane:Plane     = planes[i];
  72.                 plane.x             = Math.cos(angle) * radius;
  73.                 plane.z             = Math.sin(angle) * radius;
  74.                 plane.rotationY     = -360 / numItems * i - 90;
  75.             }
  76.            
  77.             //Adjust camera
  78.             camera.y = 200;
  79.            
  80.             //Rotate once
  81.             rotate();
  82.         }
  83.  
  84.         //Rotates the carousel
  85.         protected function rotate():void
  86.         {
  87.             var rotateTo:Number = (-360 / numItems) * currentItem + 90;
  88.             TweenLite.to(planesHolder, 1, { rotationY:rotateTo, ease:Quint.easeInOut } );
  89.         }
  90.        
  91.         /*
  92.          * Everything below this point is just for creating the buttons and
  93.          * setting button events for controlling the carousel.
  94.          */
  95.  
  96.         protected function createButtons():void
  97.         {
  98.             //Create Buttons
  99.             rightBtn = createButton();
  100.             leftBtn = createButton();
  101.                
  102.             addChild(leftBtn);
  103.             addChild(rightBtn);
  104.            
  105.             //Add button listeners
  106.             rightBtn.buttonMode = true;
  107.             leftBtn.buttonMode = true;
  108.             rightBtn.addEventListener(MouseEvent.CLICK, buttonClick);
  109.             leftBtn.addEventListener(MouseEvent.CLICK, buttonClick);
  110.                        
  111.             //Place buttons on stage
  112.             rightBtn.x    = stage.stageWidth - 120;
  113.             leftBtn.x       = 100;
  114.             rightBtn.y    =  stage.stageHeight / 2;
  115.             leftBtn.y       =  (stage.stageHeight / 2) + 20;
  116.             leftBtn.rotation    = 180;
  117.         }
  118.        
  119.         //Button actions
  120.         protected function buttonClick(evt:MouseEvent):void
  121.         {
  122.             switch (evt.target)
  123.             {
  124.                 case rightBtn:
  125.                 currentItem --;
  126.                 break;
  127.                
  128.                 case leftBtn:
  129.                 currentItem ++;
  130.                 break;
  131.             }
  132.             rotate();
  133.         }
  134.        
  135.         //Creates a simple arrow shape / returns the sprite
  136.         protected function createButton():Sprite
  137.         {
  138.             var btn:Sprite = new Sprite();
  139.            
  140.             btn.graphics.beginFill(0x333333);
  141.             btn.graphics.moveTo(0, 0);
  142.             btn.graphics.lineTo(0, 20);
  143.             btn.graphics.lineTo(10, 10);
  144.             btn.graphics.lineTo(0, 0);
  145.             btn.graphics.endFill();
  146.             return btn;
  147.         }
  148.     }
  149. }

Feel free to post links to ways you expand upon this file.

download-source

Post to Twitter Post to Delicious Delicious Post to Digg Digg This Post Post to Facebook Facebook Post to StumbleUpon Stumble This Post

Fix Z-Sorting issues with the QuadrantRenderEngine

quadrantrenderengine

download-source

Another way to solve your z-sorting issues is the use of the Quadrant Render Engine. The QuadrantRenderEngine only takes one parameter (type).

The three "types" of filtering available to you are:
QuadrantRenderEngine.ALL_FILTERS
QuadrantRenderEngine.CORRECT_Z_FILTER
QuadrantRenderEngine.QUAD_SPLIT_FILTER

For a full explanation of each of the 3 types available to you with this renderer take a look at this article.

The QuadrantRenderEngine use a technique of subdividing the screen into smaller and smaller regions to resolve potential conflicts between triangles.
blog.papervision3d.org

As also noted by others, this is a great tool to have around it does come with its performance issues. You may want to test out using ViewportLayers and optimizing in other areas.

Here is the simple code you need to change your renderer when extending BasicView.as:

Actionscript:
  1. renderer = new QuadrantRenderEngine(QuadrantRenderEngine.ALL_FILTERS);

Here is the full code for this example:

Actionscript:
  1. package 
  2. {
  3.     import flash.events.Event;
  4.     import org.papervision3d.materials.ColorMaterial;
  5.     import org.papervision3d.objects.primitives.Plane;
  6.     import org.papervision3d.objects.primitives.Sphere;
  7.     import org.papervision3d.render.QuadrantRenderEngine;
  8.     import org.papervision3d.view.BasicView;
  9.     import org.papervision3d.materials.BitmapFileMaterial;
  10.    
  11.     public class Main extends BasicView
  12.     {
  13.         protected var sphere:Sphere
  14.         protected var plane:Plane;
  15.         protected var bitmapMaterial:BitmapFileMaterial;
  16.         protected var colorMaterial:ColorMaterial;
  17.  
  18.         public function Main()
  19.         {
  20.             super();
  21.            
  22.             //Try commenting out this line to see the issues.
  23.             renderer = new QuadrantRenderEngine(QuadrantRenderEngine.ALL_FILTERS);
  24.            
  25.             createChildren();
  26.             commitProperties();
  27.             startRendering();
  28.         }
  29.         protected function createChildren():void
  30.         {
  31.            
  32.             //Create a new 3D object
  33.             colorMaterial = new ColorMaterial(0x000000);
  34.             bitmapMaterial = new BitmapFileMaterial("images/ourtex.jpg")
  35.  
  36.             //Create 3D Objects
  37.             plane = new Plane(colorMaterial,1000,1000,5,5)
  38.             sphere = new Sphere(bitmapMaterial, 50, 10,10);
  39.  
  40.            
  41.             //Add to scene
  42.             scene.addChild(plane);
  43.             scene.addChild(sphere);
  44.  
  45.         }
  46.        
  47.         protected function commitProperties():void
  48.         {
  49.             //Set some properties
  50.             sphere.scale = 4;
  51.             sphere.pitch( -10);
  52.             plane.rotationX = 60;
  53.         }
  54.         override protected function onRenderTick(event:Event = null):void
  55.         {
  56.             super.onRenderTick(event);
  57.  
  58.             //Rotate
  59.             sphere.yaw(1);
  60.         }
  61.     }
  62. }

download-source

Post to Twitter Post to Delicious Delicious Post to Digg Digg This Post Post to Facebook Facebook Post to StumbleUpon Stumble This Post

Papervision 3D Controlling Top and Bottom Cylinder Materials

custom-materials-cylinder
While working on a project this morning I came across the need to have a different material applied to a primitive cylinder. After digging through the Cylinder source code I came across these lines

Actionscript:
  1. if (fBottomFace) aFace.push( new Triangle3D(this, [aP1, aP3, aP2], matInstance, [aP1uv, aP3uv, aP2uv]) );
  2.  
  3. //and
  4.  
  5. if (fTopFace) aFace.push( new Triangle3D(this, [aP1, aP2, aP3], matInstance, [aP1uv, aP2uv, aP3uv]));

Since matInstance is just a material it can easily be replaced. I was in a hurry so I decided to just directly modified the class; not the greatest idea but it worked.

Actionscript:
  1. if (j == 0) {
  2.     if(bottomMat)
  3.     {
  4.         if (fBottomFace) aFace.push( new Triangle3D(this, [aP1, aP3, aP2], bottomMat, [aP1uv, aP3uv, aP2uv]) );
  5.     }
  6.     else
  7.     {
  8.         if (fBottomFace) aFace.push( new Triangle3D(this, [aP1, aP3, aP2], matInstance, [aP1uv, aP3uv, aP2uv]) );
  9.     }
  10.    
  11. }
  12. else
  13. {
  14.    
  15.     if(topMat)
  16.     {
  17.         if (fTopFace) aFace.push( new Triangle3D(this, [aP1, aP2, aP3], topMat, [aP1uv, aP2uv, aP3uv]));
  18.    
  19.     }
  20.     else
  21.     {
  22.         if (fTopFace) aFace.push( new Triangle3D(this, [aP1, aP2, aP3], matInstance, [aP1uv, aP2uv, aP3uv]));
  23.     }
  24. }

Here is the new way to create the Cylinder:

Actionscript:
  1. var cyl:Cylinder = new Cylinder(new ColorMaterial(0x000000),200,900,5,20,200,true,true,new ColorMaterial(0x8ad51f),new ColorMaterial(0x00FF00));

Here is the full modified Papervision Cylinder.as class:

Actionscript:
  1. package org.papervision3d.objects.primitives {
  2.     import org.papervision3d.Papervision3D;
  3.     import org.papervision3d.core.geom.*;
  4.     import org.papervision3d.core.geom.renderables.Triangle3D;
  5.     import org.papervision3d.core.geom.renderables.Vertex3D;
  6.     import org.papervision3d.core.math.NumberUV;
  7.     import org.papervision3d.core.proto.*; 
  8.  
  9.     /**
  10.     * The Cylinder class lets you create and display Cylinders.
  11.     * <p/>
  12.     * The Cylinder is divided in vertical and horizontal segment, the smallest combination is two vertical and three horizontal segments.
  13.     */
  14.     public class Cylinder extends TriangleMesh3D
  15.     {
  16.         /**
  17.         * Number of segments horizontally. Defaults to 8.
  18.         */
  19.         public var segmentsW :Number;
  20.    
  21.         /**
  22.         * Number of segments vertically. Defaults to 6.
  23.         */
  24.         public var segmentsH :Number;
  25.    
  26.         /**
  27.         * Default radius of Cylinder if not defined.
  28.         */
  29.         static public const DEFAULT_RADIUS :Number = 100;
  30.    
  31.         /**
  32.         * Default height if not defined.
  33.         */
  34.         static public const DEFAULT_HEIGHT :Number = 100;
  35.    
  36.         /**
  37.         * Default scale of Cylinder texture if not defined.
  38.         */
  39.         static public const DEFAULT_SCALE :Number = 1;
  40.    
  41.         /**
  42.         * Default value of gridX if not defined.
  43.         */
  44.         static public const DEFAULT_SEGMENTSW :Number = 8;
  45.    
  46.         /**
  47.         * Default value of gridY if not defined.
  48.         */
  49.         static public const DEFAULT_SEGMENTSH :Number = 6;
  50.    
  51.         /**
  52.         * Minimum value of gridX.
  53.         */
  54.         static public const MIN_SEGMENTSW :Number = 3;
  55.    
  56.         /**
  57.         * Minimum value of gridY.
  58.         */
  59.         static public const MIN_SEGMENTSH :Number = 1;
  60.    
  61.         public var topFace
  62.         // ___________________________________________________________________________________________________
  63.         //                                                                                               N E W
  64.         // NN  NN EEEEEE WW    WW
  65.         // NNN NN EE     WW WW WW
  66.         // NNNNNN EEEE   WWWWWWWW
  67.         // NN NNN EE     WWW  WWW
  68.         // NN  NN EEEEEE WW    WW
  69.    
  70.         /**
  71.         * Create a new Cylinder object.
  72.         * <p/>
  73.         * @param    material    A MaterialObject3D object that contains the material properties of the object.
  74.         * <p/>
  75.         * @param    radius    [optional] - Desired radius.
  76.         * <p/>
  77.         * @param    segmentsW   [optional] - Number of segments horizontally. Defaults to 8.
  78.         * <p/>
  79.         * @param    segmentsH   [optional] - Number of segments vertically. Defaults to 6.
  80.         * <p/>
  81.         * @param    topRadius   [optional] - An optional parameter for con- or diverging cylinders.
  82.         * <p/>
  83.         * @param    topFace  [optional] - An optional parameter specifying if the top face of the cylinder should be drawn.
  84.         * <p/>
  85.         * @param    bottomFace  [optional] - An optional parameter specifying if the bottom face of the cylinder should be drawn.
  86.         * <p/>
  87.         */
  88.         public function Cylinder( material:MaterialObject3D=null, radius:Number=100, height:Number=100, segmentsW:int=8, segmentsH:int=6, topRadius:Number=-1, topFace:Boolean=true, bottomFace:Boolean=true,topMat:MaterialObject3D = null ,bottomMat:MaterialObject3D = null)
  89.         {
  90.             super( material, new Array(), new Array(), null );
  91.    
  92.             this.segmentsW = Math.max( MIN_SEGMENTSW, segmentsW || DEFAULT_SEGMENTSW); // Defaults to 8
  93.             this.segmentsH = Math.max( MIN_SEGMENTSH, segmentsH || DEFAULT_SEGMENTSH); // Defaults to 6
  94.             if (radius==0) radius = DEFAULT_RADIUS; // Defaults to 100
  95.             if (height==0) height = DEFAULT_HEIGHT; // Defaults to 100
  96.             if (topRadius==-1) topRadius = radius;
  97.    
  98.             var scale :Number = DEFAULT_SCALE;
  99.    
  100.             buildCylinder( radius, height, topRadius, topFace, bottomFace,topMat,bottomMat );
  101.         }
  102.    
  103.         private function buildCylinder( fRadius:Number, fHeight:Number, fTopRadius:Number, fTopFace:Boolean, fBottomFace:Boolean ,topMat:MaterialObject3D,bottomMat:MaterialObject3D):void
  104.         {
  105.             var matInstance:MaterialObject3D = material;
  106.            
  107.             var i:Number, j:Number, k:Number;
  108.    
  109.             var iHor:Number = Math.max(MIN_SEGMENTSW, this.segmentsW);
  110.             var iVer:Number = Math.max(MIN_SEGMENTSH, this.segmentsH);
  111.             var aVertice:Array = this.geometry.vertices;
  112.             var aFace:Array = this.geometry.faces;
  113.             var aVtc:Array = new Array();
  114.             for (j=0;j<(iVer+1);j++) { // vertical
  115.                 var fRad1:Number = Number(j/iVer);
  116.                 var fZ:Number = fHeight*(j/(iVer+0))-fHeight/2;//-fRadius*Math.cos(fRad1*Math.PI);
  117.                 var fRds:Number = fTopRadius+(fRadius-fTopRadius)*(1-j/(iVer));//*Math.sin(fRad1*Math.PI);
  118.                 var aRow:Array = new Array();
  119.                 var oVtx:Vertex3D;
  120.                 for (i=0;i<iHor;i++) { // horizontal
  121.                     var fRad2:Number = Number(2*i/iHor);
  122.                     var fX:Number = fRds*Math.sin(fRad2*Math.PI);
  123.                     var fY:Number = fRds*Math.cos(fRad2*Math.PI);
  124.                     //if (!((j==0||j==iVer)&&i>0)) { // top||bottom = 1 vertex
  125.                     oVtx = new Vertex3D(fY,fZ,fX);
  126.                     aVertice.push(oVtx);
  127.                     //}
  128.                     aRow.push(oVtx);
  129.                 }
  130.                 aVtc.push(aRow);
  131.             }
  132.             var iVerNum:int = aVtc.length;
  133.    
  134.             var aP4uv:NumberUV, aP1uv:NumberUV, aP2uv:NumberUV, aP3uv:NumberUV;
  135.             var aP1:Vertex3D, aP2:Vertex3D, aP3:Vertex3D, aP4:Vertex3D;
  136.    
  137.             for (j=0;j<iVerNum;j++) {
  138.                 var iHorNum:int = aVtc[j].length;
  139.                 for (i=0;i<iHorNum;i++) {
  140.                     if (j>0&&i>=0) {
  141.                         // select vertices
  142.                         var bEnd:Boolean = i==(iHorNum-0);
  143.                         aP1 = aVtc[j][bEnd?0:i];
  144.                         aP2 = aVtc[j][(i==0?iHorNum:i)-1];
  145.                         aP3 = aVtc[j-1][(i==0?iHorNum:i)-1];
  146.                         aP4 = aVtc[j-1][bEnd?0:i];
  147.                         // uv
  148.                         var fJ0:Number = j    / iVerNum;
  149.                         var fJ1:Number = (j-1)  / iVerNum;
  150.                         var fI0:Number = (i+1)  / iHorNum;
  151.                         var fI1:Number = i    / iHorNum;
  152.                         aP4uv = new NumberUV(fI0,fJ1);
  153.                         aP1uv = new NumberUV(fI0,fJ0);
  154.                         aP2uv = new NumberUV(fI1,fJ0);
  155.                         aP3uv = new NumberUV(fI1,fJ1);
  156.                         // 2 faces
  157.                         aFace.push( new Triangle3D(this, [aP1,aP2,aP3], matInstance, [aP1uv,aP2uv,aP3uv]) );
  158.                         aFace.push( new Triangle3D(this, [aP1,aP3,aP4], matInstance, [aP1uv,aP3uv,aP4uv]) );
  159.                     }
  160.                 }
  161.                 if (j==0||j==(iVerNum-1)) {
  162.                     for (i=0;i<(iHorNum-2);i++) {
  163.                         // uv
  164.                         var iI:int = Math.floor(i/2);
  165.                         aP1 = aVtc[j][iI];
  166.                         aP2 = (i%2==0)? (aVtc[j][iHorNum-2-iI]) : (aVtc[j][iI+1]);
  167.                         aP3 = (i%2==0)? (aVtc[j][iHorNum-1-iI]) : (aVtc[j][iHorNum-2-iI]);
  168.    
  169.                         var bTop:Boolean = j==0;
  170.                         aP1uv = new NumberUV( (bTop?1:0)+(bTop?-1:1)*(aP1.x/fRadius/2+.5), aP1.z/fRadius/2+.5 );
  171.                         aP2uv = new NumberUV( (bTop?1:0)+(bTop?-1:1)*(aP2.x/fRadius/2+.5), aP2.z/fRadius/2+.5 );
  172.                         aP3uv = new NumberUV( (bTop?1:0)+(bTop?-1:1)*(aP3.x/fRadius/2+.5), aP3.z/fRadius/2+.5 );
  173.    
  174.                         // face
  175.                         if (j == 0) {
  176.                             if(bottomMat)
  177.                             {
  178.                                 if (fBottomFace) aFace.push( new Triangle3D(this, [aP1, aP3, aP2], bottomMat, [aP1uv, aP3uv, aP2uv]) );
  179.                             }
  180.                             else
  181.                             {
  182.                                 if (fBottomFace) aFace.push( new Triangle3D(this, [aP1, aP3, aP2], matInstance, [aP1uv, aP3uv, aP2uv]) );
  183.                             }
  184.                            
  185.                         }
  186.                         else {
  187.                            
  188.                             if(topMat)
  189.                             {
  190.                                 if (fTopFace) aFace.push( new Triangle3D(this, [aP1, aP2, aP3], topMat, [aP1uv, aP2uv, aP3uv]));
  191.                            
  192.                             }
  193.                             else
  194.                             {
  195.                                 if (fTopFace) aFace.push( new Triangle3D(this, [aP1, aP2, aP3], matInstance, [aP1uv, aP2uv, aP3uv]));
  196.                             }
  197.                            
  198.                            
  199.                         }
  200.                     }
  201.                 }
  202.             }
  203.             this.geometry.ready = true;
  204.            
  205.             if(Papervision3D.useRIGHTHANDED)
  206.                 this.geometry.flipFaces();
  207.         }
  208.     }
  209. }

Post to Twitter Post to Delicious Delicious Post to Digg Digg This Post Post to Facebook Facebook Post to StumbleUpon Stumble This Post

Off Topic : Creating a Side Scrolling Fish Game with APE Physics Engine

ape-engine-game

This is getting a little off topic since there is no use of Papervision. This is something we were messing with over at Woven.

View full blog entry

View Fish Game

Post to Twitter Post to Delicious Delicious Post to Digg Digg This Post Post to Facebook Facebook Post to StumbleUpon Stumble This Post

Source: Using Augmented Reality FLARToolkit and Papervision to create a unique 3D experience

woven-interactive-flark-test

DOWNLOAD AND PRINT THIS FIRST!

Example requires a webcam.

When we first saw the GE Smart Grid website all we could think was WOW. Great 3D and messaging. Seeing the Augmented Reality section that mixed the FLARToolkit and Papervision really created something unique.

We found a few examples of people playing with it online but no real amounts of source code. Also did not know the HIRO file format was. It turns out you don't need a *.hiro file, you can swap it out with a *.pat file. There is even an online ARToolKit Maker Generator that is quick and easy to use.

Onto the source code:

This is a modified example taken from the provided example source code (The hello world of the FLARToolKit):

Actionscript:
  1. package net.saqoosha.flartoolkit.example {
  2.    
  3.     import org.papervision3d.materials.BitmapFileMaterial;
  4.     import org.papervision3d.objects.DisplayObject3D;
  5.     import flash.events.Event;
  6.     import flash.events.MouseEvent;
  7.     import org.papervision3d.core.proto.DisplayObjectContainer3D;
  8.     import org.papervision3d.objects.primitives.Sphere;
  9.    
  10.     import org.papervision3d.lights.PointLight3D;
  11.     import org.papervision3d.materials.WireframeMaterial;
  12.     import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
  13.     import org.papervision3d.materials.utils.MaterialsList;
  14.     import org.papervision3d.objects.primitives.Cube;
  15.     import org.papervision3d.objects.primitives.Plane;
  16.    
  17.  
  18.     [SWF(width=700,height=400,frameRate=30,backgroundColor=0x0)]
  19.  
  20.     public class SimpleCube extends PV3DARApp {
  21.        
  22.         private static const PATTERN_FILE:String = "resources/marker16.pat";
  23.         private static const CAMERA_FILE:String = "resources/camera_para.dat";
  24.        
  25.         protected var plane:Plane;
  26.         protected var objectsContainer:DisplayObject3D;
  27.         protected var cube:Cube;
  28.         protected var sphere:Sphere
  29.         protected var wovenCube:Cube;
  30.         protected var imageMat:BitmapFileMaterial;
  31.         protected var fmat:FlatShadeMaterial;
  32.         protected var wmat:WireframeMaterial;
  33.        
  34.         public function SimpleCube()
  35.         {
  36.             addEventListener(Event.INIT, onInit);
  37.             init(CAMERA_FILE, PATTERN_FILE);
  38.         }
  39.        
  40.         private function onInit(e:Event):void
  41.         {
  42.             removeEventListener(Event.INIT, onInit);
  43.            
  44.             //Create light source for shade material
  45.             var light:PointLight3D = new PointLight3D();
  46.             light.x = 1000;
  47.             light.y = 1000;
  48.             light.z = -1000;
  49.            
  50.             //Create Materials
  51.             imageMat = new BitmapFileMaterial("resources/woven-logo.jpg", false);
  52.             fmat = new FlatShadeMaterial(light, 0xFFFFFF, 0x0);
  53.             wmat = new WireframeMaterial(0xff0000);
  54.             wmat.doubleSided = true;
  55.            
  56.             //Create objects
  57.             objectsContainer = new DisplayObject3D();
  58.             plane = new Plane(wmat, 100, 100,1,1);
  59.             wovenCube = new Cube(new MaterialsList( { all: imageMat } ), 150, 150, 150);
  60.             cube = new Cube(new MaterialsList( { all: fmat } ), 20, 200, 20);
  61.             sphere = new Sphere(fmat, 20);
  62.            
  63.            
  64.             //Position elements
  65.             sphere.y = 200;
  66.             wovenCube.z += 100;
  67.             objectsContainer.z += 100;
  68.            
  69.             //Add objects to my container
  70.             objectsContainer.addChild(sphere)
  71.             objectsContainer.addChild(wovenCube)
  72.             objectsContainer.addChild(cube)
  73.            
  74.             //Add to base
  75.             _baseNode.addChild(plane);
  76.             _baseNode.addChild(objectsContainer);
  77.  
  78.         }
  79.        
  80.         override protected function _onEnterFrame(e:Event = null):void
  81.         {
  82.             super._onEnterFrame(e);
  83.             sphere.rotationY += 10;
  84.             wovenCube.rotationZ += 10;
  85.         }
  86.        
  87.     }
  88.    
  89. }

As you can see from this line:

Actionscript:
  1. private static const PATTERN_FILE:String = "resources/marker16.pat";

We replaced the *.hiro file with a *.pat file.

To get this example to work you will have to DOWNLOAD AND PRINT THIS FIRST!

Download the full source

and / or

View the interactive example.

Learn more about the FLARToolKit

If you or your clients need any help getting started feel free to contact our Interactive Agency.

Post to Twitter Post to Delicious Delicious Post to Digg Digg This Post Post to Facebook Facebook Post to StumbleUpon Stumble This Post


Follow WovenCharlie on Twitter

Flash and the City banner
2010 Flash And The City Speaker

RSS Feed