ViewportLayers – In depth (Papervision3D)

Andreas | 2010-04-21 | Flash, Tutorial

The more I see where people get stuck, using PV3D, the more I feel the need to create a good tutorial regarding ViewportLayers.
Lets start with the simple task of NOT using any layers. First the document class that just adds our BasicView.

package {
        import flash.display.Sprite;

        public class ViewportLayerTest extends Sprite
        {
                public function ViewportLayerTest()
                {
                        var tView:View3d = new View3d();
                        addChild(tView);
                }
        }
}

Now let’s build up a scene with a ground, a wall stuck to the ground and a sphere that is stuck right in the middle of the wall.
That would look something like this.

package
{
    import org.papervision3d.materials.WireframeMaterial;
    import org.papervision3d.objects.primitives.Cube;
    import org.papervision3d.objects.primitives.Plane;
    import org.papervision3d.objects.primitives.Sphere;
    import org.papervision3d.view.BasicView;

    public class View3d extends BasicView
    {
        private var sphere:Sphere;
        private var cube:Cube;
        private var ground:Plane;
        private var wall:Plane;

        public function View3d()
        {
            super();
            setupScene();
            startRendering();
        }

        private function setupScene()
        {
            camera.x = 660;
            camera.y =  400;
            camera.z = -700;

            ground = new Plane(new WireframeMaterial(0×224422),1000,1000,1,1);
            ground.rotationX = 90;

            wall = new Plane(new WireframeMaterial(0×556655),1000,400,1,1);
            wall.y = 200;

            sphere = new Sphere(new WireframeMaterial(0xff2222));
            sphere.x = -100;
            sphere.y = 100;

            scene.addChild(ground);
            scene.addChild(wall);
            scene.addChild(sphere);
        }
    }
}

Run that swf and you will see this:
bild-11

Let us now put a little more code in and also change the material into solid colour ones (I put a FlastShader on the sphere so we can see the roundness more easily).

package
{
        import org.papervision3d.lights.PointLight3D;
        import org.papervision3d.materials.ColorMaterial;
        import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
        import org.papervision3d.objects.primitives.Cube;
        import org.papervision3d.objects.primitives.Plane;
        import org.papervision3d.objects.primitives.Sphere;
        import org.papervision3d.view.BasicView;

        public class View3d extends BasicView
        {
                private var light:PointLight3D;
                private var sphere:Sphere;
                private var cube:Cube;
                private var ground:Plane;
                private var wall:Plane;

                public function View3d()
                {
                        super();
                        setupScene();
                        startRendering();
                }

                private function setupScene()
                {
                        camera.x = 660;
                        camera.y =  400;
                        camera.z = -700;

                        light = new PointLight3D();
                        light.x = -400;
                        light.z = -1000;
                        light.y = 200;

                        ground = new Plane(new ColorMaterial(0×224422),1000,1000,1,1);
                        ground.rotationX = 90;

                        wall = new Plane(new ColorMaterial(0×446644),800,400,1,1);
                        wall.y = 200;

                        sphere = new Sphere(new FlatShadeMaterial(light,0xff2222),100,10,10);
                        sphere.x = -100;
                        sphere.y = 100;

                        scene.addChild(ground);
                        scene.addChild(wall);
                        scene.addChild(sphere);
                }
        }
}

Run it and witness this:

bild-2

Now that aint right! This is just the Z-fighting I talked about in an earlier post. Looking at the wireframe one can see that the “centerpoint” of the left triangle in the ground is actually closer to the than many of the sphere and walls centrepoint so that is why we get that strange phenomena. It just is drawn later than it should.

Now lets use layers just like in Flash 2D. (well sort of).

What are ViewportLayers?

As I assume that you are familiar to the Flash environment and AS3, I will descripe the ViewportLayers just like layered movieclips on top of each other in a normal DisplayList. The Viewport is rendering all these layers one by one in the order it is told to which gives you the power to control when something is going to be rendered.

Now, the PV3D team has been very ambitious when it comes to layers and therefo you will find many different ways of creating one or even handling one.

First of all, let me say that we already got 2 layers. One is the actual Viewport.containerSprite that is the “root” of every layer.

If we write

trace(viewport.containerSprite.childLayers.toString());

you will see a layer underneath as well. This is what we got this far.

One approach to working with layers is to just set up a structure of empty layers at first and then fill in the objects that needs to be in which layer.

Let’s try this on our testscene. Put this script after you add the objects to the scene:

// create 3 new layers, null says that it will be empty initially.
var sphereLayer:ViewportLayer = new ViewportLayer(viewport,null);
var wallLayer:ViewportLayer = new ViewportLayer(viewport,null);
var groundLayer:ViewportLayer = new ViewportLayer(viewport,null);

// add the layers as childs to the "root"-layer
viewport.containerSprite.addLayer(sphereLayer);
viewport.containerSprite.addLayer(wallLayer);
viewport.containerSprite.addLayer(groundLayer);

// set the sorting of all childlayers to sort by index
viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT;

// set the sort index of the new layer
groundLayer.layerIndex = 1;
wallLayer.layerIndex = 2;
sphereLayer.layerIndex = 3;

// add our objects to the new layers
groundLayer.addDisplayObject3D(ground);
wallLayer.addDisplayObject3D(wall);
sphereLayer.addDisplayObject3D(sphere);

And here’s the result:

bild-3

Now the layers are like 3 “sprites” drawn separately on the viewport. First the ground (as it has the lowest index), then the wall, overwriting all of the ground. Finally the sphere. Notice that even though the sphere was half stuck into the wall, we can see the whole sphere now.
As you can put “childLayers” in other layers you can also experiment with nesting layers into each other and sorting them differently depending on your needs.
As I mentioned there are several approaches to creating layers.
If you just erase what we just added we will try another approach.

// this time, let’s use the viewport to create layers, through objects.
// true means that if ’sphere’ does not belong to a layer, create one for it and put it there.
var sphereLayer:ViewportLayer = viewport.getChildLayer(sphere, true);
var groundLayer:ViewportLayer = viewport.getChildLayer(sphere, true);
var wallLayer:ViewportLayer = viewport.getChildLayer(sphere, true);
viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT;

// set the sort index of the new layer
groundLayer.layerIndex = 2;
wallLayer.layerIndex = 1;
sphereLayer.layerIndex = 3;

As I changed the indexorder, the result now looks like this:
bild-4

Notice that viewport.getChildLayer() does create a new layer, put the object in it and also puts the layer in the structurelist of the containerSprite. Easy and simple, but maybe with a little less control of the layers placement in the “layertree”.
A last way of creating layers I want to bring up today is the DO3D.useOwnContainer
It automatically creates a layer for just that object which gives you great control over effects like:
DO3D.filters
DO3D.blendMode
DO3D.alpha

Try to set this simple variable to true and experiment with these 3 parameters. I know that people are asking a lot about alpha and effects and this is such an easy way to get that.

As long as you think of the layers as single Sprites/MovieClips on top of each other you will be able to come up with great effects. Are you having a problem getting a great buttonMode on all your objects? Put them in a layer and call: layer.buttonMode = true

You want some of your cubes to glow? Why don’t you try layer.Filters?

You even have unique control over how OFTEN that special layer will be rendered. In my game I will consider a static overview camera for lowperformance computers. This means that I will only render the ground and the whole Arena ONCE and then only render the units, bullets and explosions. Really a processorsaver! How to do it?

Well, put all layers that will be rendered into an array, eg aLayers:Array

Now send that array into: renderer.renderLayers(scene, camera, viewport, aLayers)

This will tell the renderer to only render those layers.

ViewportLayers holds a lot of secrets and great functionality but I stop here and will probably come out with a more advanced tutorial later on. Now you got the basics to take control over your renderings!

/Andreas


Responses


  1. A big thank you!
    This made it really clear …
    Three ways to achieve the same result, that´s why so many people got confused, including me :)



  2. hi
    thanks for tutorial

    can you help me with my test
    i load collada model and i don’t know why there holes in it
    you can check it http://miles.coil.ru/pv3d/
    and here’s code http://miles.coil.ru/pv3d/test.as

    thanks



  3. However if the scene is rotated, the object sorting will become incorrect, how should we fix this?



  4. Gordon – to answer your question, I found that is indeed a problem with this method. Rotatin the scene will not work, you’ll see objects z-sorted incorrectly. However, I found you can fix this if you change the sortMode to an ORIGIN_SORT:

    viewport.containerSprite.sortMode = ViewportLayerSortMode.ORIGIN_SORT;

    Therefore, if you use that method, you can also remove the layerIndex code since you wouldn’t be using it. That worked for me.



  5. If only more than 46 people would read this!



  6. Hi!

    And what to do, when I don’t have a 3 objects in separates way else a big one object with faces clipping problem? :S

    I tried with renderEngine.clipping = new FrustumClipping(FrustumClipping.ALL); but nothing… my collada object still look without some faces…



  7. i just started pv today. this tutorial is very detailed and so easy a cave man can do it =) thanks



  8. Nice tutorial. Ever run into an issue with one DO3D.useOwnContainer nested inside another DO3D.useOwnContainer and not being able to affect the alpha of the child layer?



  9. Nice ~thx a lot,



  10. Sorry for my bad english. Thank you so much for your good post. Your post helped me in my college assignment, If you can provide me more details please email me.



  11. Great read! You might want to follow up to this topic???



  12. A big thank you! This made it really clear … Three ways to achieve the same result, that´s why so many people got confused, including me :)



  13. Hi! And what to do, when I don’t have a 3 objects in separates way else a big one object with faces clipping problem? :S I tried with renderEngine.clipping = new FrustumClipping(FrustumClipping.ALL); but nothing… my collada object still look without some faces…



  14. However if the scene is rotated, the object sorting will become incorrect, how should we fix this?



LEAVE COMMENT