Modifying the scene graph

Today's games very often present jaw-dropping, complex scenes, and levels composed out of hundreds of single objects. So managing these object compositions can become a very challenging task without the right data structure. This is why the principle of the scene graph has become a state of the art technique in video games and computer graphics in general. A scene graph is a hierarchical tree structure that holds information about the scene models' positions, rotations, and parent-child relationships for relative positioning—among many other things.

In this recipe we will take a look at Panda3D's scene graph interfaces and will learn how to place and rotate objects within the scene and how to build a hierarchy of models and actors to allow our scene objects to be placed relative to each other.

Getting ready

Be sure to complete Setting up the game structure in chapter one before you start this recipe, as this project structure forms the basis for the following steps.

How to do it...

Let's see how Panda3D's scene graph works. Follow these steps to create a sample application:

  1. Open Application.py and add the marked code:
    from direct.showbase.ShowBase import ShowBase
    from direct.actor.Actor import Actor
    from panda3d.core import Vec3
    class Application(ShowBase):
    def __init__(self):
    ShowBase.__init__(self)
    self.sun = loader.loadModel("smiley")
    self.sun.reparentTo(render)
    self.sun.setScale(5)
    self.phantom = loader.loadModel("teapot")
    self.phantom.reparentTo(self.sun)
    self.phantom.setScale(0.1)
    self.phantom.setPos(0, -5, 0)
    self.phantom.hide()
    self.earth = loader.loadModel("frowney")
    self.earthCenter = render.attachNewNode("earthCenter")
    self.earth.reparentTo(self.earthCenter)
    self.earth.setPos(20, 0, 0)
    self.panda = Actor("panda", {"walk": "panda-walk"})
    self.panda.reparentTo(self.earth)
    self.panda.setScale(0.1)
    self.panda.setPos(Vec3(0.7, 0, 0.7))
    self.panda.setHpr(0, 0, 40)
    self.panda.loop("walk")
    self.moon = loader.loadModel("box")
    self.moonCenter = self.earthCenter.attachNewNode("moonCenter")
    self.moon.reparentTo(self.moonCenter)
    self.moonCenter.setPos(self.earth.getPos())
    self.moon.setPos(0, 0, 6)
    self.cam.setPos(0, -100, 0)
    
  2. Press F6 to start the application. If you added the code properly, you will see the following scene. Hold down the left mouse button and drag your mouse to pan the camera. Keep the right mouse button pressed while moving the mouse to zoom in and out.
How to do it...

How it works...

If you compare the code used to create this little solar system to Loading models and actors, you will immediately understand how the mesh data is loaded and added to the scene. On the other hand, you just used a few new calls and some already known ones in a new fashion.

The smiley model is the sun in this little solar system, therefore we do not change its position, but scale it to five times its original size with setScale().

Next comes the phantom planet that is a child of the sun, which means that all transforms of the object will happen relative to the sun. So if you decided to set the sun to a different position, this planet's position would change, too, to keep the relative position. This relationship also has an impact on the scale factor, which means that scaling the teapot model that was reparented to the sun by 0.1 really means scaling it by a factor of 0.5, because its parent object was scaled to five times its size before.

All this happens to no avail for the phantom planet, as it is disabled for rendering by the hide() method. A hidden model can easily be made visible again by calling the show() method of the object.

The earth is positioned with the help of an empty scene node you added with the line render.attachNewNode("earthCenter"). Using dummy objects like this one is a great way to simplify complex relative object placements!

On top of the earth, there walks a lonesome panda, which introduces another new method for modifying objects in the scene graph called setHpr(), which is used to make the panda lean to the side. "Hpr" in this case stands for heading, pitch, and roll. Heading makes the panda turn to the left and the right, pitch makes it lean backwards and forwards and roll makes it lean to the left and the right.

Finally, the moon is placed using a new dummy object attached to the earth's placement dummy, and the camera is set to capture this tiny universe in all its glory!

There's more...

Apart from the methods shown in the code sample, there are some more ways to modify the actors and models in your scene. For example, the position and rotation can be set using only one method call with setPosHpr(). Another way to do the same with different measures is to use setMat(), and provide a matrix containing transformation data. But there's even more you can do, as the following paragraphs will show!

Position

Besides setPos(), you can set the position of an object on each individual coordinate axis by using setX(), setY(), and setZ() respectively. In addition, these methods can be made using coordinates that are relative to an object by passing it as the first parameter. For example, adding the line self.earth.setX(self.sun, 5) in the preceding sample would position the earth five units away from the sun's coordinate origin along the x-axis.

Rotation

Just like position, rotation can be modified individually by using the methods setH(), setP(), and setR().

Another way of representing rotations are quaternions, which can be set by using setQuat(). Quaternions are a four-dimensional extension of complex numbers, which allow you to store rotations within only four values, help to circumvent the effect of Gimbal lock (two coordinate axis becoming one after certain rotations, effectively removing one degree of freedom), and can very easily be interpolated.

Scale

The method setScale() used above uniformly scales geometry along all three axis. If you intend to only modify the scale of a model or an actor in your scene along one coordinate axis, you can use the methods setSx(), setSy(), and setSz().

Note

All the methods used to set position, rotation, and scale of objects in the scene graph also provide corresponding getter methods for retrieving data!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset