Animating only some joints

Hi! It’s me again. I’ve been struggling with something for a few days now and just can’t seem to get it down. I want to animate only some specific joints of a model. For example, having a character walk with their legs while waving their hand. Sound familiar? That’s because it’s from the manual:
https://docs.panda3d.org/1.10/python/programming/models-and-actors/actor-animations
under Half-Body animations. I’ve read this front to back, but I can’t seem to get my model to animate. It’s a single-part actor, for the record. Every time I try to makeSubpart on my actor, I get an assertion error because of line 2036 on Actor.py

assert partName not in self.__subpartDict

indicating that my subpart cannot be made because it doesn’t already exist in __subpartDict… unless I’m missing something, which is very possible, this seems to be contradictory!
If anyone can provide some illumination as to why this might not be working, or how to accomplish what I’m looking for, I would be very grateful!

For what it’s worth, I think that it’s complaining because “partName” is in “__subpartDict”.

That is, my understanding is that an assertion fails when the condition that it holds becomes false–in this case, when it’s not true that “partName not in self.__subpartDict” (i.e. when “partName in self.subpartDict” is true).

… That said, I’m afraid that I don’t have an answer for the actual question. For one thing, I’ve not really used half-body animations, that I recall! ^^;

[edit] Given the assertion error, have you tried omitting the call to “makeSubpart”, treating the model as though it already has the relevant sub-parts?

1 Like

hi! Thanks for your reply :smiley:
I edited Actor.py directly to read out the __subpartDict on makeSubpart before the assertion, and it’s empty except for modelRoot! Sorry, probably should have mentioned that. I omitted makeSubpart like you suggested, but I get an error indicating that the subpart doesn’t exist when I try to animate it. For the record, the subpart isn’t defined anywhere but in the makeSubpart.

Though, if you have a way I can animate only some bones while bypassing subparts and half-body animations entirely, I would be absolutely down for that!

[edit]: AHA! You were right! I was accidentally calling my method for creating sub-parts twice, resulting in the assertion error. Unfortunately, now despite the parts being listed under getPartNames, playing an animation with the part results in an error, saying the part cannot be found.

Hmm… Odd! Maybe it’s somehow getting multiple calls to “makeSubpart”, then?

If you have a debugger, perhaps place a breakpoint in “makeSubpart” and see when and how it’s being called…

Hmm, sort of.

I don’t think that I’ve had two animations playing on different parts of an Actor, aside from blended animations. I thus don’t have an alternative along those lines.

However, depending on your purposes, there is the option of procedural animation: instead of half-body animating two animations, take direct control of the bones related to one or both of the animations and move them yourself.

It’s not an approach that’s terribly suitable for complex animations, short of building your own half-body animation system, but for simple things (like aiming a gun or swinging a sword) it might work.

(And indeed, I have done something similar myself.)

1 Like

You were right, I was calling the “makeSubpart” method twice on accident for each part! gotta love good old fashion user error.
Sorry for the delay in my reply, I was trying to figure out as much as I could to see if I could fix the problem myself. Unfortunately… I could not. I think the animation blending you mentioned might help me with my problem. I can get two animations to play on two separate parts of the body, but each of them only play at half intensity. Is there a way to make them both play at 100% that I’m missing?
Thanks for all the help, by the way!

1 Like

Ah, fair enough–and indeed, that sort of thing happens!

I’m glad that you found that problem, at least!

Unfortunately, no, to the best of my knowledge.

It’s arguably inherent in the way that the blending works: If you blend between the colours black and white, you can get black, white, or shades of grey in-between–but you can’t get black and white. So too, when blending animations, you can get one, the other, or some degree of both–but not all of both.

This is why I didn’t consider blending to be an “alternative” above–it’s not really designed for what you’re doing, I think.

1 Like

Dang! Well thank you for taking the time to help me. Even if I didn’t find a perfect solution to this exact problem, I sure did learn a lot! I’ll probably have to end up building my own half body animation system anyways. Later on I’m going to want to blend premade animations with procedural animation (IKs anyone?), so building my own system is probably inevitable at this point.

1 Like

Hmm… It’s not necessarily inevitable, perhaps–I do think that I’ve seen discussion of runtime-generated animations, if I recall correctly.

But still, this is an area that I’m not enormously familiar with, so I’ll leave further discussion of such to others who might know it better!

That said, I’m glad if I’ve helped. :slight_smile:

1 Like

Could you share your code of how you’re calling it and trying to use it? I can assure you that makeSubpart does in fact work as advertised and should indeed solve your problem, as I’ve used it myself in a game project not too long ago. You just have to be sure that you specify the part name in any animation calls (eg. .play("walk", partName="legs") or whatever). It’s a very nifty system, this type of subpart basically acts as a “joint filter” that says which joints are being affected by a given animation, and you can still combine it with blending and such.

As pointed out, blending them each with 100% weight is not the right approach, as the weights are normalized; you would have to exaggerate the animation by a factor of 2 for this to work, I think. You were on the right track with makeSubpart, and you should be able to get it to work.

2 Likes

I sure can!
I have these methods inside a character class, for the record.

		def make_subparts(self):
		for k, v in self.bone_groups.items():
			self.actor.makeSubpart(k, v, overlapping = True)

	def play_animation(self, anims = []):
		for fullname in anims:
			subpart, name = x.split('-')
			self.actor.play(fullname, partName = subpart)

it’s pretty straightforward. make_subparts is called when the character is initialized, and it reads bone_groups off a standard json file. Anims in play_animations is set up like “upper body-wave”, with the front half of the animation being the bone group, and the back half being the animation name itself. I checked the json files and the animation files exported by Blender and all the names match up with all the cases.
A bone filter is exactly what I was looking for, and I was really hoping that’s what this system is for!
PS, this is the system with all attempts at blending removed. A backup I had saved before dabbling in that. When I run this, the animation plays as expected, but when another animation is played, the new animation overwrites the old, even when they’re on different subparts.

I’m guessing that this is just an error in transcription, but in the code that you give above, I notice that you’re splitting a variable named “x”, rather than “fullname”.

That said, the code shouldn’t run as-is, I daresay, hence my thought that this is just a transcription error. Still, I mention it just in case.

1 Like

In your code, you may need to be passing name to the play() function instead of fullname, and instead of x.split, you may have meant to use fullname.split.

If that’s not the issue, maybe you could add a print statement to print out the exact values you’re passing to either Actor method? Then we can be sure that your logic is correct.

I notice you’re passing overlapping = True, do you have multiple subparts that share the same joints? Note that if you want to play animations on overlapping subparts simultaneously, you would probably need to either enable blending to make that work, or you could decide to split off the overlapping bit into a separate subpart (you can have multiple subparts playing the same animation at the same time).

1 Like

Augh sorry that was a typo. My bad. You guys are right, that is a transcription error (it used to be for x in anims) and has since been rectified. x.split is now fullname.split! I had bulked up both methods with print functions out the wazoo to catch the variable changing names at every step. I removed them to make reading the code easier for y’all. My idea is to futureproof this to create an animation hierarchy using subparts, where the walking animation swings the arms from side to side unless the arms are needed to hold a gun, wave, etc. Before playing an animation on a subpart, it will get a copy of the currently running animations at the current frame of every subpart above it on the hierarchy and force them to play on all their original subparts after playing the new animation, hopefully overwritting any lower ranking subgroups. Hence allowing overlap ahead of time. Since it wasn’t working (and was terribly complicated) I had gutted all that in an attempt to simplify and figure out why two animations won’t play at the same time. In this current test, I have separated just the legs and just the arms into two subparts(the only two that exist). But the walking animation overwrites the waving arms, and the waving arms overwrites the walking animation! It baffles my mind to be sure. I noticed in Actor.py that it returns an error if the subparts aren’t found, so I put in print checks for that specifically. It doesn’t return any errors.
Wow this post is a novel. Sorry about that!

Could you share the print-out for the values you are passing to either method? We don’t have any information to go on at the moment.

Yeah sorry about that, I I was gonna edit my post to share the log but I think I figured it out. The Legs subparts are based on a root bone in my rig, that the arms are also eventually connected to via the shoulder, spine, etc. I connected the legs to the hips instead, and suddenly it started to work. It seems like if one subparts group shares common ancestry with another, one will counteract the other. Does this sound right?
(If this isn’t the solution I’ll immediately share the logs next post)

Hmm… that depends on how the animation is done and whether the shared parent bones are animated, I suppose. Off the top of my head I’m not sure how hierarchy factors into this, sorry.

1 Like

That’s ok! I appreciate the help none the less.
Here’s the log. It’s kind of sparse.

creating subparts…
MAKING SUBPART [left arm] OUT OF BONES [‘Shoulder.L’] k is type <class ‘str’> v is type <class ‘list’>
MAKING SUBPART [right arm] OUT OF BONES [‘Shoulder.R’] k is type <class ‘str’> v is type <class ‘list’>
MAKING SUBPART [lower body] OUT OF BONES [‘Root’] k is type <class ‘str’> v is type <class ‘list’>

actor subparts [‘modelRoot’, ‘[lower body]’, ‘[left arm]’, ‘[right arm]’]

Trying to play… [lower body]-walk
Does subpart [lower body] exist? True
Does animation [lower body]-walk exist? True
Successfully played [lower body]-walk

RECIEVING EVENT FOR wave
events for wave are: []
Trying to play… [right arm]-wave
Does subpart [right arm] exist? True
Does animation [right arm]-wave exist? True
Successfully played [right arm]-wave

“Receiving Event” is to report the press of keybinds, which triggers the action to wave. The walk animation in this instance animates both the legs moving and the arms moving at the same time. I’m aiming for the wave to only stop animating the right arm for the walk cycle to allow it perform the wave animation. But when the wave triggers, the entire walking animation legs and all abruptly stops, and the rest of the model seems to return to the resting pose. The arm does wave, though. When I set [lower body]'s subpart joints to Hip.R and Hip.L, this immediately begins to work as expected.

Hmm… A thought: What happens if you rework your animations such that the “walk” animation doesn’t affect–or indeed reference–the arms at all, with the associated animation being instead implemented as a separate animation affecting the arms alone?

1 Like

Good idea! If we can’t figure something out, I’ll probably end up cutting up all the animations into pieces and doing what you say. It’s just… that would be a pretty massive undertaking considering I’m going to have dozens, if not hundreds, of animations that all need to be cut. Functional subparting would be monumentally easier, but at least I have a backup plan!

1 Like

That is fair!

Let’s see what rdb (or someone else, for that matter) has to say next–perhaps there’s something that’s been missed!

1 Like