Billboarding in Papervision3D 2.0 using DisplayObject2D

As mentioned on the about page Tweetpond displays tweet content using standard Flash TextFields that are rendered as part of the 3D scene. This is often called billboarding or point sprites.

Tweetpond DisplayObject2D

Our DisplayObject2D implementation is based on the following sources:

  1. DisplayObject2D by Blitz Agency
  2. Revision for Papervision3D 2.0 by Sleepy Design.

Our implementation solves the Z-ordering issues reported when using DisplayObject2D with Papervision3D 2.0.

We recently received a request to share our version with the community so here you go! You can download the ActionScript3 class files below:

This code is released under the MIT licence, same as Papervision3D. To get an idea on how to use this class please see this post by Blitz Agency and source comments.

Please feel free to share your project that makes use of DisplayObject2D below!

This entry was posted in Technology and tagged , , , , . Bookmark the permalink. Both comments and trackbacks are currently closed.

22 Comments

  1. Posted 16 Sep 2009 at 8:08 pm | Permalink

    A reader recently asked for some examples on how to use the DisplayObject2D class so I’ve attached some example code below to illustrate.

    The magic is in having everything on their own individual layers that Papervision3D can the z-order correctly. I also highly recommend installing http://www.monsterdebugger.com/ so you can see what’s happening in your application in real time. Good luck!

    var parentLayer:ViewportLayer;
    var vpl:ViewportLayer;
     
    // create an empty parent viewport layer and add it to the container
    parentLayer = new ViewportLayer(viewport, null);
    viewport.containerSprite.addLayer(parentLayer);
     
    // create shape
    var shape = new Sphere(material, SIZE);
     
    // create layer and add to scene
    shape.useOwnContainer = true;
    vpl = parentLayer.getChildLayer(shape, true);
    scene.addChild(shape);
     
    // create text box (movieclip)
    var box = new Box();
    //...set box properties here...
     
    // create do2d that encapsulates the movieclip
    var label = new DisplayObject2D(box as DisplayObject, parentLayer, 0, null, SIZE*1.25, 0);
     
    // create layer and add to scene
    label.useOwnContainer = true;
    vpl = parentLayer.getChildLayer(label, true);
    scene.addChild(label);
    
  2. Fernando
    Posted 07 Dec 2009 at 6:47 pm | Permalink

    Hello from Spain,

    “A reader recently asked for some examples on how to use the DisplayObject2D class so I’ve attached some example code below to illustrate.”

    I started to program in papervision recently not for profesional job. I readed your post.

    ¿Could you give me an code source example for a movieclip like ‘circle’?

    Thank for all,

  3. Posted 09 Dec 2009 at 7:34 am | Permalink

    Hi Fernando, sounds like you’re trying to run the original example from Blitz Agency.

    “Circle” is not defined in ActionScript at all, it is a movieclip you can find in the Library of the DisplayObject2DTest.fla project:

    DisplayObject2d Library: Circle

    You will also notice under the “linkage” column how this movieclip has been exported to ActionScript as class “Circle”. In the Library, right click on the Circle and select Properties to view and change symbol properties.

    Hope this helps.

    Cheers, Jussi

  4. Posted 07 Mar 2010 at 4:09 am | Permalink

    Hi… I´m trying yor classes and at this moment I can see various displayObject3d and a displayObject2d on the stage. This displayObject2d is a child of one of those displayObject3d. I want both to rotate at the same time but when I rotate the displayObject3d the displayObject2d doesn`t change its rotation.

    By the way, Tweetpond is great.

    Thank you.

  5. Posted 11 Mar 2010 at 10:38 am | Permalink

    Hi Iker,

    I assume you’re trying to rotate the DisplayObject2D around its Z-axis, similar to what changing the standard Flash rotation property would do (i.e. “obj._rotation = angle”)?

    I don’t think this will work, as the whole idea behind billboarding is that the DisplayObject2D is always facing the same way on the two-dimensional plane (your screen).

    If you’re looking for something that ‘participates’ more fully in the 3D world, including rotations around X, Y and Z axes, perhaps you can look into org.papervision3d.objects.Plane class (with a suitable material such as bitmap).

    Hope this helps.

    Cheers, Jussi

  6. Posted 26 May 2010 at 12:33 pm | Permalink

    Your do2d is great to me, and I have encountered an issue that I am unable to make the z-sorting work correctly when my do2ds on the stage with other collada objects.
    It seems it always in front of other 3d models:
    http://www.busysuzie.com/testing/#/opening

    I wonder if my code add the do2d wrongly:

    var parentLayer:ViewportLayer;
    parentLayer = new ViewportLayer(viewport, null);
    viewport.containerSprite.addLayer(parentLayer);
    
    //create table models and loaded successfully
    .
    .
    //
    tables.useOwnContainer = true;
    parentLayer.getChildLayer(tables, true);
    scene.addChild(tables);
    
    
    //create middle column models and loaded successfully
    .
    .
    //
    middleColumn.useOwnContainer = true;
    parentLayer.getChildLayer(middleColumn, true);
    scene.addChild(middleColumn);
    
    //loop for creating paddle and character on a do3d and add do3d to scene
    for(var i:int = 0; i<6; i++)
    {
    	personHolderArr[i] = new DisplayObject3D();
    	
    	//create paddle and loaded successfully
    	.
    	.
    	//
    	paddleArr[i].useOwnContainer = true;
    	parentLayer.getChildLayer(paddleArr[i], true);
    	personHolderArr[i].addChild(paddleArr[i]);
    	
    	var do2D:DisplayObject2D = new DisplayObject2D(new Character() as DisplayObject, parentLayer, 180);
    	personHolderArr[i].addChild(do2D);
    	
    	scene.addChild(personHolderArr[i]);
    }
    

    I suppose it is due to layering, but I cannot figure out where I code it wrongly.
    I would be very appreciated if you can inspire me for any solution. Thanks

  7. Posted 26 May 2010 at 3:41 pm | Permalink

    Hi Gordon,

    this is a bit of a stab in the dark but looking at these lines:

    personHolderArr[i].addChild(paddleArr[i]);
    
    personHolderArr[i].addChild(do2D);
    

    I am wondering if you should add the paddles and characters directly to the scene by calling scene.addChild(paddleArr[i]) and scene.addChild(do2D) instead?

    Just an idea, let me know how you go.

    Cheers, Jussi

  8. Posted 26 May 2010 at 6:54 pm | Permalink

    Thanks for your rapid respond, the DO2D and paddle is put to a DO3D with purpose, so that I can assign that DO3D always face to the camera instead of assigning them individually.

    I just wonder if the issue is related to the:

    viewport.containerSprite.addLayer(parentLayer);
    

    And I tried to change the sortMode of viewportlayer to index_sort, z_sort, nothing help /~\

    This is the simplified file package, hope you may interest and see if there is any solution:
    http://snap-f.net/do2D_z_Issue.zip

  9. Posted 27 May 2010 at 10:56 am | Permalink

    Hi Gordon,

    I won’t be able to have a detailed look at your code, however I did notice that you’ve commented out the following:

    //paddleArr[i].useOwnContainer = true;
    //parentLayer.getChildLayer(paddleArr[i], true);
    
    //do2D.useOwnContainer = true;
    //parentLayer.getChildLayer(do2D, true);
    

    From memory, correct z-sorting using these classes depends on the fact that all child objects have their own individual layer – hence the explicit ‘true’ for the createNew parameter in the method call.

    I’d recommend you try these classes out in a clean Flash project first and make sure DO2D’s behave correctly in terms of z-ordering. Then drop in some DO3D’s and confirm that objects are still sorted properly. Once this works you can then apply same logic to your actual project.

    Also make sure you have a debugger on hand to be able to see inside your project at runtime. It’s really helpful to see object properites, how they nest etc.

    Cheers, Jussi

  10. Posted 27 May 2010 at 1:16 pm | Permalink

    I finally figure that, sadly not a solution yet, dae model is always behind the do2d…
    I use your sample code and add one more dae model, no matter how I change the z, the dae model is covered by the box and do2d~

  11. Posted 27 May 2010 at 1:19 pm | Permalink

    Anyway, big thanks to you, Jussi, at least I can put movieclip to the 3d environment in a pretty way. Just keep on digging into collada import procedure to see if there is any hint to solve the issue~ Thank you.

  12. Posted 27 May 2010 at 1:22 pm | Permalink

    No worries at all Gordon, I’m sure you will find a good solution soon. Cheers, Jussi

  13. Wayne
    Posted 23 Oct 2010 at 3:09 am | Permalink

    hi Jussi
    Great update, easy to impliment so far however was just wondering if it allowed for mouse events. I have tried both mouse events and e:InteractiveScene3DEvent but no joy. I am a slight newbie so forgive me if i have overlooked something simple.

    Thanks
    w

  14. Posted 23 Oct 2010 at 11:12 am | Permalink

    Hi Wayne,

    good question, I’ve tried mouse events in the past but they didn’t seem to work properly. If I remember correctly the click events were received fine, however the event target wasn’t always correct, so in the current version of Tweetpond clicking on objects is not enabled. I believe this is unrelated to the DisplayObject2D implementation.

    I’ve posted some sample code below on setting up the events, perhaps someone else can have a look and work out why this doesn’t always work correctly when there are lots of objects in the scene?

    Cheers, Jussi

    public class MyView extends BasicView {
      // constant for our interactive setting	
      public static const INTERACTIVE = true;
    
      public function MyView() {
        // interactive viewport allows clicking on objects
        super(stage.stageWidth, stage.stageHeight, true, INTERACTIVE, CameraType.TARGET);
    
        var obj:DisplayObject3D = createShape();
    
        // name displayobject
        obj.name = "my_sphere_001";
    
        // add event listeners
        obj.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, objClicked);
    
        ...
      }
    
      private function createShape():DisplayObject3D {
        var material:MaterialObject3D = new FlatShadeMaterial(LIGHT, COLOUR, AMBIENT_COLOUR);
        var materialsList:MaterialsList = new MaterialsList();
    
        material.interactive = INTERACTIVE;
        materialsList.addMaterial(material, "all");
    
        return new Sphere(material, SIZE);
      }
    
      private function objClicked(myEvent:InteractiveScene3DEvent):void {
        trace ("Clicked on " + myEvent.target.name);
      }
    }
    
  15. Wayne
    Posted 25 Oct 2010 at 6:13 pm | Permalink

    Hi Jussi
    Thanks for your speed response. Would this still apply to making the 2d object clickable. I have loaded in a movieclip in to the 2d object. Rollovers work but cant get any joy from tracing a click? I have also tried a normal mouse event. At the moment I have

    var parentLayer:ViewportLayer;
    var vpl:ViewportLayer;

    parentLayer = new ViewportLayer(viewport, null);
    viewport.containerSprite.addLayer(parentLayer);
    // create text box (movieclip)
    var box = new MenuCrossBtn();
    var menu = new DisplayObject2D(box as DisplayObject, parentLayer, 0, null, 5*1.25, 0);
    // create layer and add to scene
    menu.useOwnContainer = true;
    vpl = parentLayer.getChildLayer(menu, true);
    menu.z=200;
    menu.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, click1);
    menu.name=”myBtn”;
    scene.addChild(menu);

  16. Wayne
    Posted 25 Oct 2010 at 7:52 pm | Permalink

    Hi again, forget that, I have used normal mouse events on the box movieclip which seems to work now instead of the 2d display object. lol

  17. Posted 26 Oct 2010 at 9:56 am | Permalink

    Sounds good, I’m glad you got it working. Cheers

  18. Wayne
    Posted 16 Nov 2010 at 1:13 am | Permalink

    Hi again, I have hit another stumbling block and wondered if theire was a simple solution, im probably being silly, I am trying to remove the display2d object. I have added 5 menu’s using your class, each as a seperate 2dobject and put each one ino an array, I can trace the object in the array but will not remove it? Could it be something like viewport.containerSprite.parent.removeChild(menu);?

    Thanks again, this class is very handy.

  19. Posted 16 Nov 2010 at 9:44 am | Permalink

    Hi Wayne,

    here’s how the removing of objects is done in Tweetpond:

    // remove from array
    shape = shapeArray.pop();
    
    // remove from scene
    if (shape.scene) shape.scene.removeChild(shape);
    	
    // dispose
    shape = null;
    

    Hope this helps.

  20. wayne
    Posted 17 Nov 2010 at 10:24 am | Permalink

    thanks jussi, Thanks for the response, I think im missing something here. I think im adding each menu to the array then deleting all items in one go, but it does not delete any. It does however add to 2 new 2d objects(which is correct); is it to do with how i am adding them, im not sure if this is the correct way but seems to work?? Sorry to keep bothering you.

    public function addBtns():void
    {
    	max = tempArray.length;
    	var parentLayer:ViewportLayer;
    	var vpl:ViewportLayer;
    	// create an empty parent viewport layer and add it to the container
    	parentLayer = new ViewportLayer(viewport,null);
    	viewport.containerSprite.addLayer(parentLayer);
    	// adding individual 2d oobjects with different x and y etc
    	for (var i:int = 0; i < max; i++)
    	{
    		box = new menuHolder();
    		// create text box (movieclip);
    		// create do2d that encapsulates the movieclip
    		menu = new DisplayObject2D(box as DisplayObject,parentLayer,0,null,5 * 1.25,0);
    		// create layer and add to scene
    		menu.useOwnContainer = true;
    		//vpl = parentLayer.getChildLayer(menu,true);
    
    		menu.x = tempArray[i].x;
    		menu.y = tempArray[i].y;
    		menu.z = tempArray[i].z;
    		// drop down stuff
    		var bodyDrop:DropDown = new DropDown(this[listArray + i],tempArray[i].title,true,this[listArray + i].length * 30);
    		bodyDrop.addEventListener(DropDown.ITEM_SELECTED, newSelect);
    
    
    		box.addChild(bodyDrop);
    		box.name = "box" + i;
    		menu.name = "menu" + i;
    		menuArray.push(menu);
    		scene.addChild(menu);
    		//menu.alpha = 1;
    
    		trace(menuArray[i]);
    	}
    	trace("starting menu",menu.scene);
    }
    
    // button to remove
    public function removeHorseBtns():void
    {
    	for (var i:int = 0; i < max; i++)
    	{
    		menu = menuArray[i];
    		// remove from scene
    		if (menu.scene)
    		{
    			menu.scene.removeChild(menu);
    			// dispose
    			menu = null;
    		}
    
    	}
    	//this will be added to 
    	menuArray=[];
    }
    
  21. Posted 17 Nov 2010 at 11:02 am | Permalink

    Hi Wayne, the code seems right at a quick glance but unfortunately I can’t look into it in more detail.

    Have you tried looking at your running project using a debugger? Tools like De MonsterDebugger really help work out where the issues lie.

  22. Wayne
    Posted 17 Nov 2010 at 11:37 pm | Permalink

    thanks, I use the monster debugger, they are good lads. For anybody else I think I found a solution however am not sure if it is the most effecient but it works! I put the movie clip into an array instead of the 2dobject and deleted that. It just would not delete the 3d object in the scene, but im happy for now!

    box = new menuHolder();
    // create do2d that encapsulates the movieclip
    menu = new DisplayObject2D(box as DisplayObject,parentLayer,0,null,5 * 1.25,0);
    menuArray.push(box);

    //then deleted it by
    var item = menuArray[i];
    item.parent.removeChild(item);