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