Manipulating a Piece of a Model

Every model, when loaded, becomes a ModelNode in the scene graph. Beneath the ModelNode are one or more GeomNodes containing the actual polygons. If you want to manipulate a piece of a model, for instance, if you want to change the texture of just part of a model, you need a pointer to the relevant GeomNode.

In order to obtain such a pointer, you must first ensure that the relevant geometry is in a GeomNode of its own (and not merged with all the other geometry). In other words, you must ensure that panda’s optimization mechanisms do not cause the geometry to be merged with the geometry of the rest of the model. While normally this optimization is a good thing, if you want to change textures on a specific part of the model (for example, just a character’s face) you will need this geometry to be separate.

There are two different ways that you should do this, according to the type of model it is.

Animated (skeleton animation) models

If your model is animated via keyframe animation in a package such as 3DSMax or Maya–that is, the sort of model you expect to load in via the Actor interface–then Panda will be aggressive in combining all of the geometry into as few nodes as possible. In order to mark particular geometry to be kept separate, you should use the egg-optchar program.

The name “optchar” is short for “optimize character”, since the egg-optchar program is designed to optimize an animated character for runtime performance by removing unused and unneeded joints. However, in addition to this optimization, it also allows you to label a section of a model for later manipulation. Once you have labeled a piece of geometry, Panda’s optimization mechanisms will not fold it in to the rest of the model.

Your first step is to note the name of the object in your modeling program. For example, suppose you want to control the texture of a model’s head, and suppose (hypothetically) the head is labeled “Sphere01” in your modeling program. Use egg-optchar to tell panda that “Sphere01” deserves to be kept separate and labeled:

egg-optchar -d outputDir -flag Sphere01=theHead modelFile.egg anim1.egg anim2.egg

Note that you must always supply the model file(s) and all of its animation files to egg-optchar at the same time. This is so it can examine all of the joints and determine which joints are actually animated; and it can remove joints by operating on all the files at once. The output of egg-optchar is written into the directory named by the “-d” parameter.

The “-flag” switch will ensure that panda does not rearrange the geometry for the named polyset, folding it into the model as a whole. It also assigns the polyset a meaningful name. Once you have labeled the relevant piece of geometry, you can obtain a pointer to it using the find() method:

myModelsHead = myModel.find("**/theHead")

With this NodePath, you can manipulate the head separately from the rest of the model. For example, you can move the piece using set_pos(), or change its texture using set_texture(), or for that matter, do anything that you would do to any other scene graph node.

Unanimated (environment) models

Other kinds of models, those that do not contain any skeleton or animations, are not optimized as aggressively by the Panda loader, on the assumption that the model’s hierarchy was structured the way it is intentionally, to maximize culling (see Pipeline Tips). Thus, only certain nodes are combined with others, so it’s quite likely that an object that you modeled as a separate node in your modeling package will still be available under the same name when you load it in Panda. But Panda doesn’t promise that it will never collapse together nodes that it thinks need to be combined for optimization purposes, unless you tell it not to.

In the case of an unanimated model, the way to protect a particular node is to insert the <Model> flag into the egg file within the particular group. The way to do this depends on your modeling package (and this documentation still needs to be written).