Recommendation to get 2 imported GLTF humanoid meshes interacting with each other

I have a few general questions about triggering animations between interacting meshes, that hopefully better gamedevs than me can share insight on. There are no code examples, but ideally this is general enough that they are not needed.

  1. Suppose I have 2 humanoid meshes, created in Blender. Each humanoid has some movement, attack and defend animations.

a. Mesh 1 is at point A
b. Mesh 2 is at point B

  1. Necessarily, the meshes are exported individually from Blender as .glb and then imported to BabylonJS. They cannot be added to e.g a .babylon file and imported together.

  2. I click to move Mesh 1 from point A to point B. The intention is to trigger a fight between the two humanoid characters.

  3. Now for the questions. What is the best way to trigger the fight, and is there a strategy I can pursue for synchronizing the animations so they look believable? Meaning, when Mesh 1 punches Mesh 2, Mesh 2 believably reacts.

Some starting points:

  • Presumably some “ready to fight”-type animations can start when the two meshes are within some proximity to each other. This seems straightforward and although I don’t precisely know how to measure the distance right now, conceptually it makes sense.

  • The animations are canned, pre-created in Blender. This seems to suggest that true physics/a physics engine are not essential, but I’m not 100% sure due to the next point.

  • Therefore, is monitoring intersectsMesh the best way to proceed? This would require precise positioning of each mesh, taking into account the scale of each mesh coming out of Blender, and carefully ensuring that they intersect to trigger animations on the target mesh. Also, I think I would have to use the precise = true format to make sure the bounding boxes stick closely to the actual mesh faces. There will be over 30 humanoid meshes in the scene so I’m not sure if this will cripple the browser, though.

  • All of the meshes use Animation Groups for their animations as this is what exports from Blender, so I’m not sure I can make use of a callback like you can use with scene.beginDirectAnimation or scene.beginWeightedAnimation to assist me in any way.

Interested to hear people’s thoughts about this so I can maybe guide my noob self to a better animated game. Thanks for taking the time.

Is your game singleplayer or multiplayer?
Some answers may depend on it.

Thanks @labris - it’s multiplayer, but turn-based. Neither player will have direct control over the meshes during the combat sequence. Also the attacking mesh (Mesh 1) will always win the fight.

So you need to program ‘avatars’ so that after some event they could fight each other with some predefined and some random settings?

Yes, although the settings will be pre-defined as well. There won’t be randomness at all.

Just a video to have some references to discuss :slight_smile:

I think that precise intersection testing is not needed here, and furthermore as you’ve said there will be quite a few models, it would tank the browser :thinking: For triggering the initial fight, I would probably check if attacking mesh is < than a certain distance to defending mesh. For choreographing the fight itself, I would probably try to rely on Animation Events: Advanced Animation Methods | Babylon.js Documentation (babylonjs.com) to do things like: when the attack animation is at frame Y, start the reaction animation on the defending mesh. This involves a bit of work, but it would be much lighter load to the app than checking intersections.

@PatrickRyan might also have some tips :slight_smile:

To check the distance between two vectors3 just use Vector3.Distance - Vector3 | Babylon.js Documentation
Example - Babylon.js Playground

@genuflect from your description of the mechanics, turn-based with no direct control over the motion of the characters, it seems that for the sake of performance and a lighter code base to maintain, you could “can” your attacks and reactions so as not to resort to a bunch of physics simulations or rag-dolling.

What I mean by this is to author your attacks into categories like low, mid, or high attacks and then author responses to each of these categories. You might also add left/right variations to the attacks which could require different reactions. It also doesn’t have to be a one-for-one attack and resolution either. You could author multiple reactions in each category and randomly pick one. Or you could tie reactions to specific attacks like high attack X causes reaction A, B, or C and you randomly choose one to play every time attack X is executed.

If you want to author the attacks and reactions as realistically as possible, but also have many characters on screen to track, this is the best way to make sure you keep performance high while eliminating any edge case bugs where the physics put your character in an unexpected position. It also allows extensibility of new attacks and reactions as needed rather than needing to experiment with physics responses to the attacks. This puts the problem square in the hands of the artist generating the animation so you can really add some dynamic reactions to the reactions that would be really hard to produce just from a physics simulation.

1 Like

Thanks @labris @carolhmj @PatrickRyan, this helps sort out some workflow questions I had and sheds more light on how to properly generate these animations. Very helpful!

I have a followup question about making the pre-fight animations blend together (Mesh 1 walking toward the fight and “put up your dukes” part as both meshes get ready for battle).

  1. Since I am using Animation Groups accessed from the mesh, is there a canonically best way to smoothly interpolate between idle animation group and another group?

Some examples I’ve found on the forums here are:

A) https://playground.babylonjs.com/#IQN716#9
B) https://playground.babylonjs.com/#6I67BL#321
C) https://playground.babylonjs.com/#IRJ10K#6
D) https://www.babylonjs-playground.com/#PSR2ZX#33

  • A) This one blends animations using animation weights, but accessed through the scene object. Mine will need to be accessed through the .glb mesh, and there doesn’t appear to be a beginWeightedAnimation method for animation groups.

  • B) This makes use of AnimationGroup.MakeAnimationAdditive and MakeAnimationAdditive seems to be best used when characters are standing still.

  • C) This one by Drigax appears to be used when all animations are on the same NLA track. Mine will be on separate tracks, so not sure if that applies. This playground doesn’t seem to work properly but came from a forum thread here: Weighted animations from animation group ? (with web example) - #10 by bghgary

  • D) This one makes use of scene.AnimationPropertiesOverride and this seems the most promising. However, he accesses the animation group through the scene object and mine will need to be accessed through the .glb mesh directly. Is an Animation Group a valid target for overrides or am I missing something here?

Which one do you think is best for the use case of pre-determined animation groups accessed through the .glb?

Thanks all for your time looking into this, answers have been very helpful already!

@genuflect, there must be something in the water, because everyone is blending skeletal animations these days. There are a couple of things to point out from your last message.

Even if your animation groups are coming from a loaded glb, all animation groups are owned by the scene. When you play, pause, or stop an animation group, you are doing so at the scene level, even if you are seeing the result of your animation on a particular mesh that was loaded from a glb. The important thing here is that the animation group itself contains the target for all animatables contained in the group.

One way that you can handle this is that you load each animation group through a central file or files so that the scene has one copy of every animation group you will need in the scene. Then you simply need to clone the needed animation for a mesh, reassign the target within the animatables, and then play the animation group using animation overrides. This means that if you have 30 characters on screen at once, you need to have one animation group playing for each one (an idle animation for example), then when you need to have them move and attack, you clone your move and attack animation groups, assigning them to the active character, play them with overrides in sequence, and then dispose of the animation groups when you are done.

This is because every animation group affects one skeleton, so for every character to have access to every animation group, they would each need their own copy of every animation they can play. This can be super heavy to keep in memory and manage, so cloning/playing/disposing would be a much cleaner method and means you don’t need to keep track of what is currently playing on any mesh.

I just made an example of retargeting an animation from one glb to another glb, and went back in to add the animation overrides part. So you can see this working both from the standpoint of retargeting an animation as well as blending between multiple animation groups.

This version works best for replacing one animation group with another rather than adding multiple animation clips together to modify a base animation. We are starting some feature work to make managing and blending animations easier and more powerful so we are actively working to make the whole system better.

2 Likes

Thanks @PatrickRyan for this example. I will ultimately have unique animations for many meshes…there will be some overlap but a lot of unique animation groups regardless. I guess I’ll have to see how much of a burden this becomes on the browser/machines.

I’ll attempt to adapt the blending shown in your example into my app and report back, and look forward to seeing more updates to the engine.

Thanks for taking the time!

@PatrickRyan to follow up on your playground example, I’m not seeing weight as a property that exists on the TargetedAnimation type. (Using Typescript, ofc).

I am using ES6 @babylonjs/core version 5.13.2 and I noticed that the playground is at 5.24. However, even if I upgrade to 5.24 this error doesn’t go away, and the property isn’t listed in the BJS typedoc for TargetdAnimation. Was this change made after 5.13.2 or is there something I’m doing wrong?

@genuflect, unfortunately, there isn’t a weight parameter on targeted animation as the animation groups class does not play well with weighted animations. In that playground example, I am using an animation override to blend between the animation groups which behaves kind of like weighted animations, however the override blend amount is a universal setting for the scene, not a per-animation control. This is the limiting factor with using animation groups to blend animations.

We are looking at animation blending as a whole in features for 6.0 so this will be improving but we are in the early stages right now. In the mean time, the override is the way to blend between animation groups, but you won’t have precise control over the blend speed - or playing multiple animations at once with partial weights - with the current system.

Here is quick but cruel draft PG - https://playground.babylonjs.com/#8SW41I#23 :slight_smile:

3 Likes

FATALITY! :rofl: