how to optimize egg files

I’ve been struggling for a while in trying to figure out how to build efficient character rigs for the panda engine. At the moment, I have no way of seeing what the engine ultimately reads. We’re currently using a dual skeleton setup in which one skeleton drives the weighted skeleton - a fairly standard setup these days in gaming.

however, the egg file sees everything…all 388 nodes. I have no idea what the bam file strips out and i can’t seem to get egg-optchar to reduce the nodes.

does anyone have any advice…it’s getting to the point where I’m going to have to stop production on building characters until this is worked out. The export method for panda is very black box and any clues/hints/help anyone might have would be greatly appreciated.

jeff cooperman
lead animator
autumn moon entertainment

By “nodes”, do you mean joints (bones), or do you mean meshes?

You can list the joints in your final model with:
actor.listJoints()
You can list the meshes with:
actor.ls()

Egg-optchar will remove unused joints from your model, where an unused joint is defined as one that is either unanimated, or contains no geometry assigned to it. If you have a hierarchy of joints that are used solely to drive other joints, and have no geometry directly attached to them, then egg-optchar should eliminate the one hierarchy, leaving only the hierarchy that actually contains geometry. Egg-optchar will tell you which joints its is removing and why.

For performance tuning, it should also be helpful to know how much time Panda spends animating the joints, versus how much time it spends animating the vertices. Watching your animation in PStats will tell you this, since PStats will break down the animation time between joints and vertices. This may help you to understand where you need to direct your efforts.

Can you tell me more about specifically what information you are looking to discover?

David

ok…up at www.coopdesign.org/client/mayaRig.zip are 3 maya files.

ballrigBind.ma which is what i’d like the engine to see
ballRigA.ma, which is a simple rig.
BallRig_Dual, which has a parallel skeleton that has the rig applied to it.

how can i strip out the nodes i don’t want to the engine effectively sees ballrigBind?

jeff

Well, I can’t inspect your Maya files, since we have only Maya 6.0 here.

But let me clarify a point: it doesn’t matter to Panda which rig is the controlling rig. Panda doesn’t know about the constraints and relationships you set up between different rigs; all it sees is a bunch of moving joints, some of which have geometry assigned to them and some of which don’t.

At the end of the day, the only joints that matter to Panda are the ones that have geometry assigned to them.

You can’t decide which rig Panda sees. It sees all of them, and egg-optchar can be used to strip out the joints that have no geometry assigned to them, so that Panda only spends time animating the joints that matter.

If you’re looking to have higher-level control over your character, for instance by using controlJoint() to animate one of your high-level joints that in turn controls several low-level joints, sorry, you can’t do that in real-time Panda. That would require implementing a full IK and constraint system similar to Maya’s.

If you’re not using controlJoint(), though, it doesn’t matter what the joint hierarchy looks like inside Panda, since it will exactly reproduce whatever it looked like in Maya–constraints and all. This works because the maya2egg program lets Maya compute all the constraints, and just outputs the result of that computation to the egg file. Then Panda can optimize it further for runtime performance, but the resulting visual effect is the same.

On the other hand, if you do want to use controlJoint() to set up a smart hierarchy like this, your best solution is probably to implement the appropriate joint constraints entirely in Python: for instance, set up a table such that animation joint X really animates joint A and joint B. Then you use controlJoint() on joint A and B, and expose a Python interface to “animate” joint X by animating joints A and B instead.

David

i resaved the files as maya 6…i’m still a little unclear on how to optimize out the egg files and view the results.

I’m not clear on exactly what your goal is. You use the word “optimize”, implying your goal is to improve frame rate; but you also say you have a particular rig that you’d like the engine to see.

Which is your concern–do you need to have Panda animate a particular rig, or is it just that you want it to run as fast as possible? Panda can make its own decisions as to which bones it needs, you don’t specify that. So if you want it to run as fast as possible, run it through egg-optchar and accept whatever you get.

Is there a particular problem with the results of egg-optchar? It’s not clear whether you’re unsatisfied with the results, or whether you’re just confused as to how to observe the results.

David

Maybe I can help clarify coop’s question. We’re actually working on the same project. He has a maya rig that has several layers of joints. Some joints actually represent the joints that animations are applied to and ultimatly will be used in the game. Some joints are just a “helper” control rig he uses to animate the character more easily within maya.

When we export his file using maya2egg the resulting egg file contains all of the skeleton joints and the helper joints. Ideally we would like to strip out the extra “helper” joints and leave the core skeleton joints.

We are using “controlJoint” and “exposeJoint” in a few instances. Namely to attach objects/items to our characters and to control morph targets. We are also making use of actor.makeSubPart(…) to allow us to play different animations on various parts of our actors. All of these methods require there to be some named joints in the actor file that we can get out at run time.

However, when I run egg-optchar on the .egg file and it’s associated animation files it seems to get rid of all our joints including the ones that are part of the heirarchy we want. For example:

Before Optimization:

>egg-optchar model.egg -ls

Character: MON_bind
MON:CON
  MON:CONjo_PROP_L_HandINH
    MON:jo_PROP_L_HandCON_GRP
  MON:CONjo_PROP_R_HandINH
    MON:jo_PROP_R_HandCON_GRP
  MON:CONjo_PROP_R_ShoulderINH
    MON:jo_PROP_R_ShoulderCON_GRP
 ....<LOTS OF JOINTS>  ....
 
MON:world
MON:facialshapes.0
MON:facialshapes.1
MON:facialshapes.14
MON:facialshapes.15
MON:facialshapes.3
MON:facialshapes.5
MON:facialshapes.7
MON:facialshapes.9
MON:facialshapes.10
MON:facialshapes.11
MON:facialshapes.12
MON:facialshapes.13
MON:facialshapes.4
MON:facialshapes.6
MON:facialshapes.2
MON:facialshapes.8
175 joints.

Then I run the optimization on this model and an animation that will be applied to it:

>egg-optchar -d testdir model.egg anim.egg

MON_bind has 191 components.
MON_Walk has 221 components.
  175 original joints in MON_bind
   26 identity joints
  149 unanimated joints
 ----
    0 joints remaining

  205 original joints in MON_Walk
   26 identity joints
  116 unanimated joints
   63 empty joints
 ----
    0 joints remaining

Writing testdir/model.egg
Writing testdir/anim.egg

The new joint heirarchy for the model becomes:

>egg-optchar model.egg -ls
<NOTHING>

That is no heirarchy seems to exist anymore

The joint heirarchy for the animation becomes:

>egg-optchar anim.egg -ls
Character: MON_Walk
MON:facialshapes.0
MON:facialshapes.1
MON:facialshapes.10
MON:facialshapes.11
MON:facialshapes.12
MON:facialshapes.13
MON:facialshapes.14
MON:facialshapes.15
MON:facialshapes.2
MON:facialshapes.3
MON:facialshapes.4
MON:facialshapes.5
MON:facialshapes.6
MON:facialshapes.7
MON:facialshapes.8
MON:facialshapes.9
0 joints.

When I try to play back this animation on our model, it doesn’t work (not suprising because it doesn’t have any joints.

It seems to me that either egg-opchar’s default behavior is too aggressive for us in how it removes joints, or it doesn’t support animations being in seperate files from models or I’m simply using it wrong.

At any rate, I think the root of the problem is that our models have a whole bunch of joints, some we want to see in the game and some we don’t. We’re looking for a simple way to export the ones we want and not export the ones we don’t.

My current solution plan is to write a simple mel script that allows our animators to tag the joints that should and should not be exported so we can pass this info to egg-optchar to get rid of or keep various joints using its “-keep” and “-drop” commands.

The other idea is to put the control joints and the skeleton joints in some kind of “selection set” so that during export time we only export the selection set that has the skeleton heirarchy that we actually want in the game.

Naturally, if anyone knows of a better solution for this problem within panda we’d be happy to hear it.

Thanks,
Aaron

Ah, the light dawns. No, you are simply using egg-optchar wrong. :slight_smile:

The problem is that your model and your animation have mismatched names–one is named MON_bind and one is named MON_walk–so egg-optchar sees them as unrelated to each other. It observes that none of the joints in your model file have any animation, so it can optimize all of them away; and then it observes that none of the joints in your animation file have any geometry, so it can optimize all of them away.

Note that you would observe the same problem with pview. If you ran pview, specifying the model and animation egg file on the command line, it would not recognize them as related, unless you also specified the -i option to ignore the character names.

Panda uses the character names to inform it which animation files are intended to be bound to which animation. These should be the same for files that use the same rig. Use the -cn parameter to maya2egg to set these to the same string for all animations that involve the same rig. (However, the fact that MON_bind and MON_walk appear to have a different number of joints from each other is somewhat disturbing. Are they, in fact, the same rig?)

Once you have corrected this problem, egg-optchar will remove only the joints that are actually unanimated or have no geometry, which will be a large fraction of them, I’ll wager. In order to preserve certain joints for controlJoint or exposeJoint purposes, use the -keep option to egg-optchar.

David

Wow, what a big difference a little bit of advice makes. I re-exported the model and the animation using the "-cn " flag as you suggested. Now egg-optchar is happy as heck. The model and animation used 179 joints before and now they’re only using 66.

The animation seems to work and I was able to test the model and animation together in pview (which I have tried but never got working before).

As a side note, I also tried using the “-optimal” flag which seems to have moved a few joints around in the heirarchy but generally produced a similar result (after I ran egg-optchar on the files again).

coop the upshot of all this I belive is you can pretty much rig the models however you want w/o worrying too much about extra joints. Egg-optchar seems to be pretty smart about leaving the joints we need for doing animation (as long as it’s used correctly :wink: ) . I’m guessing that the “-optimal” flag might even be able to fix the rig to some degree in case something’s really kooky.

As a side note/question that pertains to this. What do “Characters” mean in Panda?

I’ve seen references to “Character” and characters in the documentation but never really understood their significance. The class for Character seems to be mainly for accessing joints and sliders.

The manual entry labelled “Actors and Characters” doesn’t seem to actually mention characters. I’m assuming there is some correllation between an Actor and a Character?

Perhaps characters are just an internal idiom I should ignore for the most part (except in the use of opt-char) and be satisfied w/using the Actor module instead? Or is there something important I should know about the internals of panda as they relate to characters.

As a side-side note, I tried using the Character.findSlider() method and ran into some issues using the following code:

from direct.actor.Actor import Actor
import direct.directbase.DirectStart
from pandac.PandaModules import Character

myActor = Actor("model",{"walk":"anim"})
myActor.reparentTo(render)
myActor.loop("walk")
charNode = myActor.find("**/+Character")
slider = charNode.node().findSlider("MON:facialshapes.0")
run()

this code gives me the following errors:

 
slider = charNode.node().findSlider("MON:facialshapes.0")
AttributeError: 'libpanda.Character' object has no attribute 'findSlider'

On a scan of the documentation I noticed that the class that findSlider() is supposed to return “CharacterSlider” doesn’t have a documentation page (findJoint seems to work ok strangely, old documentation?).

Thanks for your help,
Aaron

Try to import all classes in pandac.pandaModules. Does that work?

Importing all of pandac.PandaModules doesn’t help

from direct.actor.Actor import Actor
import direct.directbase.DirectStart
from pandac.PandaModules import Character
from pandac.PandaModules import *

myActor = Actor("model",{"walk":"anim"})
myActor.reparentTo(render)
myActor.loop("walk")
charNode = myActor.find("**/+Character")
slider = charNode.node().findSlider("MON:facialshapes.0")
#joints work...
#slider = charNode.node().findJoint("MON:jo_Root")

run()

to recap…

basically what i want to do is have the ability to improve or make the control objects more complex without affecting the underlying skeletal hierarchy.

I'm guessing that the "-optimal" flag might even be able to fix the rig to some degree in case something's really kooky.

Right, that’s its main purpose. It’s primarily useful for automatically fixing characters with broken skeletons; for instance, a character whose fingers are constrained to follow its hand, but are not actually parented to the hand. Skeletons like this will optimize better, blend better, and compress better, if the finger joints are actually parented to the hand, so they can inherit the hand’s transform rather than duplicating it. But I wouldn’t recommend using -optimal unless you actually have a degenerate skeleton like this; and even then, you might be better off doing the appropriate reparenting by hand with the -p option.

This is probably the best answer. The Character class is the C++ low-level implementation of the animation system. A Character is a node that contains a skeleton/morph hierarchy and is the parent of a hierarchy of dynamic geometry. It generally corresponds to a single egg model file.

The Actor class is a high-level layer on top of Character. Actor is written in Python. An Actor usually contains only one Character, but it might contain several; for instance, each LOD of a multi-LOD Actor, or each part of a multi-part Actor, will be a different Character.

It turns out that the CharacterSlider class was inadvertently omitted from the Python layer. This means that findSlider() was automatically omitted from the Python layer as well. I’ll go ahead and correct this minor oversight now, though there’s not much you can do with a CharacterSlider object anyway.

Right, you have that ability. Make the control objects as complex as you like; egg-optchar will remove any controls that don’t themselves contain any geometry.

David