Merging animation sequences

Blitz3D Forums/Blitz3D Programming/Merging animation sequences

CakeMonitor(Posted 2006) [#1]
Hi,

say I create a 3d model, and amoung it's animation sequences are:

strafe left, run forward, swing weapon

I want the character to strafe and run and swing the weapon at the same time.

At first I thought I would have to create an animation sequence for every action *and* for every possible combination of actions!!! This is a lot of work and would involve 1000's of frames per model (a huge drain on resources when I have 100's of models loaded)

I posted on gamedev.net and was told to combine parts of the animation info from 2 different sequences.

Researching this on these forums I found the following:


"I heard that you should manipulate the bone AFTER UpdateWorld(). Not sure though "
.
.
.
"You an also use this method to merge 2 animations (if your carefull).

If you have a mesh with bones, with the main part of the animation, then a second mesh,.. which is just the bones, with your second animation. Then you can map the bones you want, from the second mesh, onto your visible mesh. "



Is this plausable?
Can I realistically combine 3 sequences using this method for many different characters at once?

If not, what is the best solution to this probelm?

Many thanks!


jhocking(Posted 2006) [#2]
Basically, yeah, the second skeleton thing is good a way to do this. What you're talking about is animation masking (closely related to animation blending.)

Referring to the specific situation, it isn't clear to me why you need to combine strafe left and run forward. Either they're separate animations, or strafe is done by turning the character's torso in the run animation.

Incidentally, creating an animation sequence for every combination isn't just a lot of work, it is impossible. There is no way to know at what point in the character's run cycle the weapon swing begins. Or, to put it another way, the player could hit the button to attack at any point during the run animation.


scribbla(Posted 2006) [#3]
you could split the model in 2 parts, torso and legs

separate anims demo


CakeMonitor(Posted 2006) [#4]
ok,

Thanks for the help guys.

BTW joe, you're right about the running & strafing thing ... that was a case of Problem Exists Between Keyboard And Chair.

So would the folling code be along the right lines?
(in particular the MergeBones function at the bottom)


player = CreatePivot() 

playerMesh = LoadAnimMesh( "player.b3d" , player)	; player mesh + animated skeleton
bones = LoadAnimMesh( "bones.b3d" , player)		; just the animated skeleton (identical animation frames)

ExtractAnimSeq( playerMesh,0,20 )  ; sequence 1 = run
ExtractAnimSeq( bones,0,20 )

ExtractAnimSeq( playerMesh,21,30 ) ; sequence 2 = attack
ExtractAnimSeq( bones,21,30 )

moveSequence = 1
otherSequence = 2


Repeat
	If moveSequence <> 0 And otherSequence <> 0 Then
		Animate playerMesh, 1, 1, otherSequence
		Animate bones, 1, 1, moveSequence
		mergeSequences = True

	Else If moveSequence <> 0
		Animate playerMesh, 1, 1, moveSequence
		mergeSequences = False

	Else If otherSequence <> 0 
		Animate playerMesh, 1, 1, otherSequence
		mergeSequences = False

	Else
		mergeSequences = False

	EndIf
	
	UpdateWorld()

	If mergeSequences = True Then
		MergeBones( bones, playerMesh, "LeftUpperLeg" )		; (see below)
		MergeBones( bones, playerMesh, "RightUpperLeg" )
		MergeBones( bones, playerMesh, "LeftLowerLeg" )
		MergeBones( bones, playerMesh, "RightLowerLeg" )
		MergeBones( bones, playerMesh, "LeftFoot" )
		MergeBones( bones, playerMesh, "RightFoot" )
	EndIf
	
	RenderWorld()

	Flip()
Until KeyHit(1)

End

Function MergeBones( sourceBones, destMesh, boneName$ )
	source = FindChild( sourceBones, boneName$ )
	dest = FindChild( destMesh, boneName$ )
	PositionEntity dest, EntityX(source), EntityY(source), EntityZ(source)
	RotateEntity dest, EntityPitch(source), EntityYaw(source), EntityRoll(source)
End Function


Obviously in the 'real' game moveSequence might be anything from 1 to 5 and otherSequence might be anything from 6 to <numSequences>

Thanks again.


jhocking(Posted 2006) [#5]
More or less. Have you actually tried running this code with an animated mesh?


Barliesque(Posted 2006) [#6]
You'll obviously need to be careful how you construct your skeleton, so that the upper body animations don't interfere with the lower body, and vice versa.


CakeMonitor(Posted 2006) [#7]
I haven't tried the code yet... I haven't made an animated model yet ;) - I'm working on it.

Barliesque: I thought that the whole point of using this long-winded animation merging method is to *avoid* the need to make rigid looking animations where the upper body movements don't cause the lower body to move (and vice versa)

If I was to construct skeletons where one half didn't effect the other I might as well use the simple method scribbla suggested of splitting the model into 2 parts and animating them as two seporate entities, but moving them as one. No?


jhocking(Posted 2006) [#8]
Actually, no. Animation masking is functionally identical to having the model split into two parts which are animated separately. The point of using animation masking instead of two separate entities is so that the character has a continuous skin, with no seam between the two parts.


Barliesque(Posted 2006) [#9]
What you'll need to do with your skeleton is have the upper body and the lower body branching from a root node that's not effected by either... but then that's pretty much how it's done anyway. You just need to be a little extra cautious, that's all.

For instance, let's say the bones of the lower body are children of the pelvis bone. The pelvis will probably be a child of the root node, which never moves at all. The upper body may then also be a child of the pelvis. You need to be sure that your upper body animations don't rely on specific rotations of the pelvis, since the pelvis should be controlled by the lower body animations. As the pelvis rises and falls, due to the walking motion, so will the upper body. The trouble is, you will want for the pelvis to be able to twist slightly with the walking motion--and this will cause the whole of the upper body to rotate with it...

So here's what I suggest, to fix that problem: For the upper body, make a lower-back bone as a child of the pelvis, with the rest of the upper body being a child of that lower-back bone. After applying upper and lower body animations, always set the Y-rotation (if not all three axes) of the lower-back to 0 (or to their initial rotations). That should allow the lower body to twist naturally, while the upper body doesn't mechanically twist with it. And since you're using a smooth mesh, with weighted vertices, that twisting action should be smoothly applied between upper and lower body.

Hope this helps!


Makepool(Posted 2006) [#10]
Right, some of the above posts confused me a little however I came across this same problem in my game and created a solution so I thought I'd share the concept behind it and let you decide who has the best way.

Firstly I loaded all of the animations that I needed to play on the one model. Second I created a multidimensional array for each bone in the character. Before the main loop is reached I have a routine to play all of the animations through and captured the rotations of each bone at each frame into the arrays. Finally I have another function or functions that sets the bones’ orientations of the model in the scene, usually the legs and hips take the rotations from one animation whilst the upper body takes the rotations from another animation.

Make sure you use the right global options for reading and setting bones' orientations as I ran into many weird errors early on because I was using the wrong ones or mixtures! It should actually be relative to their parent rotations not an absolute rotation. A silly but easy mistake to make.

Sorry if this wasn't very clear, I'd post my code but it's very kludgy and I really ought to have rewritten it myself.


Barliesque(Posted 2006) [#11]
...I created a multidimensional array for each bone in the character...

Not that there's anything terribly wrong with your multi-dimensional approach, it's really not necessary. What you're doing is creating a duplicate of data that the Blitz engine stores internally. If you load your animated model (just once) and then create a hidden copy of it, you have a reference that gives you the exact same information, without using up additional memory resources. Simply set the hidden copy to whatever frame you want to refer to, and then have a look at the bone rotations. Which also means you can refer to frame 134.678 (an interpolation between two frames) ...which you couldn't do with your array of data. If you use a locked frame rate then that's not an issue for you, but if you use delta timing, then that certainly would be an issue.

It should actually be relative to their parent rotations not an absolute rotation.

This is the kind of difficulty I was referring to. You do need to be careful when mixing animations like this, because rotations are relative to their parent, and their parent's parent, etc. So by organising the upper body and lower body as I've described, you can get round this problem.