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.
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.
{
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:

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).
{
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:

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:
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:

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.
// 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:

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
