Multipart Actors not finding joints

Here are the results of calling .ls() on my actor:

PandaNode skeleton
Character __Actor_Fire_Hat
GeomNode (1 geoms: S:(MaterialAttrib))
Character __Actor_Character
GeomNode (2 geoms: S:(MaterialAttrib))
PandaNode head T:m(pos 0.0189913 6.47164 0.00643191 hpr -0.572898 -1.77025e-05 179.431) E:(CharacterJointEffect)
PandaNode head T:m(pos 0.018991 6.47164 0.006432 hpr -0.572967 0 179.431) E:(CharacterJointEffect)

There are my head joint nodes, all exposed as needed, but when I try and attach the hat to the head:

:Actor(warning): head not found!

Here is the code:

        self.character.exposeJoint(None,"Character","head")
        self.character.exposeJoint(None,"Fire_Hat","head")
        self.character.ls()
        self.character.attach("Fire_Hat", "Character", "head")

Looking at the Actor source, it looks like the joint only needs to be exposed. I can’t figure out why it isn’t working.

I can do this:

        h=self.character.find("**/" + "head")
        f=self.character.find("**/" + "__Actor_Fire_Hat")
        f.reparentTo(h)

though the result isn’t quite what I’d like and I’m not sure it is the same as attach would do.

How can I use attach?

Edit: This results in what I want:

n=self.character.exposeJoint(None,"Character","head")
self.character.controlJoint(n,"Fire_Hat","head")

I’m sure I can work out an automated way to make all the bones on the subparts controlled by the bones of the same name on their parents in a recursive structure, but this seems like it will have a significant amount of overhead (lots of copies of lots of bones being controlled through lots of added node paths). Is there a better approach (perhaps I can make attach do this?)

Actor.attach() is meant to be used on two different “parts” within an Actor, which are typically loaded from two different egg files via different calls to Actor.loadModel() (or via passing a dictionary of model parts to the Actor constructor).

Thus, it works on entire parts only. It does not constrain one joint within a part to track another joint.

If you want to use it to stick a hat onto your head, you should export the hat and the head in different egg files. But if your hat doesn’t have any animation of its own (no bouncing feather or anything), then you don’t need to go through all this trouble; just load the rigid hat model separately and parent it to the head joint yourself.

David

I’m loading the hat from a different egg file than the character (double nested animations dics and all), and exposing/controlling the joints requires passing the part name, and that does work, so I do have multiple parts. Attach just seems to fail to find the exposed joint.

While that hat has no animations, things like my swappable robes do have animations, and need to track most of the bones in the character. I’d also like to support things like swards that include attack animations that are blended into controlling some of the character’s joints (partial animations that may include bones in both the parent model and the child model). My idea is that models will include all the bones they attach to or animate, and will be merged into the parent model in a way that it can work. My current scheme of just controlling all joints of the sub models with the parent models works for everything except some of my animation plans I think.

We should be able to figure out why attach() isn’t working for you, though I don’t see anything obviously wrong. You could try inserting a pdb.set_trace() call into Actor.py at the point where it prints the message “head not found!”, to take a look at the node that it is searching under; maybe that will provide some insight.

Still, I’m not convinced that attach() is what you need if you just want synchronized animation from different files. If you have animated the hat and the character together, or the sword and the character or the robe and the character, then all of these pieces should already have the animation channels they require to remain in place with the corresponding animation on the character, and you only need to play them both at the same time (and actor.play() will do that).

You need to use attach() in the specific case in which you have pieces that are designed to be used with a range of different character skeletons that might have different heights, number of joints, or whatever, and so they have to inherit their animation from the scene graph instead of using the built-in animation system. This will work for cases like a hat with a feather than bounces in time with the character’s stride. But it won’t work for a robe, which will almost certainly need to be animated specifically for each character it is applied to.

David

I have some models that will be character specific (robes and such) and a lot that won’t be (hats, swards, floating orbs). I have an importer that searches for the character specific one first, then looks for a general one. All the character models will have armatures with the same bones, but different proportions and animations.

I guess what I want is a way to merge bones. I want to add a part to the model, and use the existing bones from the model its getting added to for the ones that have matching names. This would work for things that simple need to get attached to a bone, as well as models that need to work with the character’s animations (use to multiple character bones)

You are right that I do have animations for the robes that do work, but they are the exact same animations that I have for the character, and having 2 copies of all the bones, and a copy of each animation associated for every model seems like a waste of space and performance (but yes, it does work, its what I was using before).

I wasn’t sure what attach really did (I can’t make it work, and it seems to have no samples), but based on your description, I’ll agree that it won’t do what I need.

Thanks!

You can use egg-optchar to remove most of the duplicate joints in your auxiliary pieces. With its default options, it will remove any joints that do not directly animate any vertices in an existing model, recomputing the child joints as necessary to retain the same animations. Thus, if you apply egg-optchar to a hat model that contains a complete copy of your character’s armature but is entirely animated by the “head” joint, then egg-optchar will leave you with an egg file and animation file that contain only the “head” joint that has a complex animation.

David

What about the character.mergeBundles() ?

That’s true, you could conceivably use Character.mergeBundles to unify your two skeletons. This method was really designed to unify the multiple LOD’s of a single model, but if you design all of your pieces to use the exact same hierarchy, you could load them all into one Actor and then merge the hierarchies into a single hierarchy.

David

I have combined this approach with the one I had so now models with the whole skeleton get merged by the LOD merge (I load them all into the same part) and other models (mostly things like hats that just get mounted somewhere) get their joints controlled to attach them. Now both my simple and complex models work, and it should be pretty efficient.

Thanks! It seems to work great for the models I have so far.