Panda3D Manual: Scene Graph Manipulations
  <<prev top next>>     

The default scene graphs

By default, there are two different scene graphs created automatically when you start up Panda3D. These graphs are referred to by their top nodes: render and render2d.

You use render most often; this is the top of the ordinary 3-D scene. In order to put an object in the world, you will need to parent it to render (or to some node that is in turn parented to render).

You will use render2d to render 2-D GUI elements, such as text or buttons, that you want to display onscreen; for instance, a heads-up display. Anything parented to render2d will be rendered on top of the 3-D scene, as if it were painted on the screen glass.

The coordinate system of render2d is set up to match that of the mouse inputs: the lower-left corner of the screen is (-1, 0, -1), and the upper-right corner is (1, 0, 1). Since this is a square coordinate system, but the screen is usually non-square, objects parented directly to render2d may appear squashed. For this reason, Panda3D also defines a child of render2d, called aspect2d, which has a scale applied to it to correct the non-square aspect ratio of render2d. Most often, you will parent GUI elements to aspect2d rather than render2d.

Finally, you may see references to one other top-level node called hidden. This is simply an ordinary node that has no rendering properties set up for it, so that things parented to hidden will not be rendered. Older Panda3D code needed to use hidden to remove a node from the render scene graph. However, this is no longer necessary, and its use is not recommended for new programs; the best way to remove a node from render is to call nodePath.detachNode().

Loading models

You can load up a model with a filename path, in the Panda Filename Syntax, to the model's egg or bam file. In many examples, the filename extension is omitted; in this case, Panda will look for a file with either the .egg or .bam extension.

myNodePath = loader.loadModel('my/path/to/models/myModel.egg')

If you want to load multiple copies of a particular model, you can avoid re-reading the disk each time:

teapot1 = loader.loadModelCopy('teapot.egg')
teapot2 = loader.loadModelCopy('teapot.egg')
teapot3 = loader.loadModelCopy('teapot.egg')

The first time you call loadModelCopy() for a particular model, that model is read and saved in a table in memory; on each subsequent call, the model is simply copied from the table, instead of reading the file.

The above calls are appropriate for loading static models; for animated models, see Loading Actors and Animations.

Reparenting nodes and models

One of the most fundamental scene graph manipulations is changing a node's parent. You need to do this at least once after you load a model, to put it under render for viewing:

myModel.reparentTo(render)

And to remove it again:

myModel.detachNode()

As you become more comfortable with scene graph operations, you may find yourself taking more and more advantage of a deeply nested scene graph, and you may start to parent your models to other nodes than just render. Sometimes it is convenient to create an empty node for this purpose, for instance, to group several models together:

dummyNode = render.attachNewNode("Dummy Node Name")
myModel.reparentTo(dummyNode)
myOtherModel.reparentTo(dummyNode)

Since a node inherits its position information from its parent node, when you reparent a node in the scene graph you might inadvertently change its position in the world. If you need to avoid this, you can use a special variant on reparentTo():

myModel.wrtReparentTo(newParent)

The "wrt" prefix stands for "with respect to". This special method works like reparentTo(), except that it automatically recomputes the local transform on myModel to compensate for the change in transform under the new parent, so that the node ends up in the same position relative to the world.

Note that the computation required to perform wrtReparentTo() is a floating-point matrix computation and is therefore inherently imprecise. This means that if you use wrtReparentTo() repeatedly, thousands of times on the same node, it may eventually accumulate enough numerical inaccuracies to introduce a slight scale on the object (for instance, a scale of 1, 1, 0.99999); if left unchecked, this scale could eventually become noticeable.

Beginners tend to overuse this method; you should not use wrtReparentTo() unless there is a real reason to use it.

  <<prev top next>>