SmartBody : Configuring Motion Blends/Parameterized Animation

 

Characters can utilize sets of parameterized animations, called blends, which are represented by a single or group of animations. Blends can be connected to each other via transitions, and an a blend-transition graph can be constructed to guide a character through valid blends. All characters start in a 'PseudoIdle' blend which represents the hierarchical set of controllersand can transition to any other blend that has been constructed in the scene. For example, a character can be idling (PseudoIdle blend) then transition to a walk (Walk blend) then transition to a jump (Walking-Jump blend) then transition to a falling down (Falling Down blend), and so forth.

The advantage of using blends, rather than simply playing animations are:

  1. Blendscan contain multiple animations parameterized along a number of different dimensions.
  2. Animation offsets are automatically applied to the characters.
  3. Transitions to and from blends can be customized to ensure smooth animation when moving between blends.

A blend can be used to, for example, parameterize a pointing animation as to allow your character to point at anythin in front of them. Likewise, a blend can be used to parameterize a jumping motion given two jumps of differing heights or distances, and thus generate a set of jumps of any height or distance.

Creating Blends

Note that blends can be constructed with SmartBody's Blend tools.

Blends can be parameterized along one, two or three different parameters, denoted as a one-dimensional, two-dimensional or three-dimensional blend. Each parameter represents a different aspect of the animation (such as 'turning angle', or 'speed', or 'jump height', etc.) In addition, a simple blend has no parameterization, and consists only of one animation (a zero-dimensional blend). To set up a blend:

  1. Create the blend
  2. Add motions to the blend
  3. Specify the parameters associated with the blend
  4. Set up correspondences between the animations

To create a blend, specify it's name and dimensionality:

blendManager = scene.getBlendManager()
blend1 = blendManager.createBlend1D("myblend")

where 'myblend' is the name of the blend. In this case, we are specifying a one-dimensional blend. Then we add motions to the blend. Note that when adding motions to a 1-, 2- or 3- dimensional state, you need to add the parameter associated with that motion:

blend1.addMotion("motion1", 10)

this indicates that the motion 'motion1' will be added to the blend and activated when the parameter desired is '10'. Likewise:

blend1.addMotion("motion2", 20)

 

this indicates that the motion 'motion2' will be added to the blend and activated when the parameter desired is '20'. SmartBody will parameterize the blend such that if parameter value '15' is requested, an animation with equal contributions from 'motion1' and 'motion2' will be generated and played back on the character.

In addition to specifying the parameters, motions that participate in a blend often will have differing lengths, which necessitates shrinking and stretching one or both motions such that the motions are aligned properly before being interpolated. Motions can be aligned in a blend by using a set of  correspondence points. Each correspondence point indicates places along each motion which should be aligned to each other. For example, when constructing a blend of motions involving locomotion, a correpondence point can be assigned to each motion during the heel or toe strike. To set correspondence points:

m1 = scene.getMotion("motion1")
m2 = scene.getMotion("motion2")
motions = StringVec()
motions.append("motion1")
motions.append("motion2")

points = DoubleVec()
points.append(0)
points.append(0)
points.append(.5)
points.append(.7)
points.append(m1.getDuration())
points.append(m2.getDuration())
blend1.addCorrespondencePoints(motions, points)

 

This will construct three sets of correspondence points: the first connects time 0 of motion1 to time 0 of motion2, the second connects time .5 of motion1, to time .7 of motion2, the third connects the end of motion1 to the end of motion2. 

Once the correspondence points have been added to the 1-dimensional blend, the blendcan be activated via the <blend> BML command, such as:

 

Please see the section on Specifying Blend Behaviors for more details.

 

Constructing 0D Blends

A zero-dimensional (0D) blend will have no parameterization, and is represented by a single animation. Such a blend can be activated using the following BML:  <blend name="myblend0D"/>

blendManager = scene.getBlendManager()
blend0 = blendManager.createBlend0D("myblend0D")
blend0.addMotion("motion1")

Constructing 1D Blends

A one-dimensional (1D) blend can have any number of animations, each with a single parameter. Since multiple animations are specified, correspondence points are necessary in order to properly timewarp the animations. Such a blend is activated by specifying the blend parameter, which will blend between the two animations with parameters closest to the one specified.If the parameter specified is the same as a single animation, then the blend will playback the contents of that animation only without blending. Such a blend can be activated using the following BML:

  <blend name="myblend1D" x="15"/>
blendManager = scene.getBlendManager()
blend1 = blendManager.createBlend0D("myblend1D")
blend1.addMotion("motion1")
blend1.addMotion("motion2")
motions = StringVec()
motions.append("motion1")
motions.append("motion2")

points = DoubleVec()
points.append(0)
points.append(0)
points.append(.5)
points.append(.7)
points.append(m1.getDuration())
points.append(m2.getDuration())
blend1.addCorrespondencePoints(motions, points)


Constructing 2D Blends

A two-dimensional (2D) blend can have any number of animations, each with two parameters. Since multiple animations are specified, correspondence points are necessary in order to properly timewarp the animations. Such a blend is activated by specifying the two blend parameters, which will blend between three animations closest to the two parameters specified in a two-dimensional plane. Thus, such a blend requires a set of triangles to be specified that indicate how the blend will be activated. If the two parameters specified are the same parameter values of a single animation, then the blend will playback the contents of that animation only without blending. Such a blend can be activated using the following BML: 

 <blend name="myblend1D" x=".4" y=".7"/>
blendManager = scene.getBlendManager()
blend2 = blendManager.createBlend0D("myblend2D")blend2.addMotion("motion1", 0, 0)
blend2.addMotion("motion2", 1, 0)
blend2.addMotion("motion3", 0, 1)
blend2.addMotion("motion4", 1, 1)
motions = StringVec()
motions.append("motion1")
motions.append("motion2")
motions.append("motion3")
motions.append("motion4")
points = DoubleVec()
points.append(0)
points.append(0)
points.append(0)
points.append(0)
points.append(m1.getDuration())
points.append(m2.getDuration())
points.append(m3.getDuration())
points.append(m4.getDuration())
blend2.addCorrespondencePoints(motions, points)

 

A triangular parameterization must be specified to indicate how to blend the parameters together, such as:

blend2.addTriangle("motion1", "motion2", "motion3")
blend2.addTriangle("motion3", "motion2", "motion4")
 

Which separates the parameter space into two triangles: one containing motions 1,2 and 3, the other containing motions 2,3 and 4.

Constructing 3D Blends

A three-dimensional (2D) blend can have any number of animations, each with three parameters. Since multiple animations are specified, correspondence points are necessary in order to properly timewarp the animations. Such a blend is activated by specifying the threeblend parameters, which will blend between four animations closest to the three parameters specified in a three-dimensional space. Thus, such a blend requires a set of tetrahedrons to be specified that indicate how the blend will be activated. If the three parameters specified are the same parameter values of a single animation, then the blend will playback the contents of that animation only without blending. Such a blend can be activated using the following BML: 

 <blend name="myblend1D" x=".4" y=".7" z=".8"/>
 blendManager = scene.getBlendManager()
blend3 = blendManager.createBlend0D("myblend2D")
blend3 .addMotion("motion1", 0, 0, 0)
blend3 .addMotion("motion2", 0, 0, 1)
blend3 .addMotion("motion3", 1, 0, 1)
blend2.addMotion("motion4", 0, 1, 0)
motions = StringVec()
motions.append("motion1")
motions.append("motion2")
motions.append("motion3")
motions.append("motion4")
points = DoubleVec()
points.append(0)
points.append(0)
points.append(0)
points.append(0)
points.append(m1.getDuration())
points.append(m2.getDuration())
points.append(m3.getDuration())
points.append(m4.getDuration())
blend2.addCorrespondencePoints(motions, points)

 

A tetrahedral parameterization must be specified to indicate how to blend the parameters together, such as:

blend2.addTetrahedron("motion1", "motion2", "motion3", "motion4")
 

Note that a greater number of animations would require the specification of more than one tetrahedron.

Specifying Blend Parameters Automatically

Blend parameters can be set by using the Python API available for the motion assets. For example, if the parameter desired is linear velocity, the getJointSpeed() method can be used to extract it automatically from the motion data. For example:

skeleton = scene.getSkeleton("common.sk")
baseJoint = skeleton.getJoint("base")
motion = scene.getMotion("motion1")
motion.getJointSpeed(baseJoint, 0, motion.getDuration())

 

which will determine the average linear velocity of the joint called 'base' for the entire motion.

ParameterDescription 
getJointAngularSpeed()Determines the average angular velocity of a joint 
getJointAngularSpeedAxis()Determines the average angular velocity of a joint around the X, Y or Z axis 
getJointSpeed()Determines the average linear velocity of a joint 
   
getJointSpeedAxis()Determines the average linear velocity of a joint around the X, Y or Z axis 

 

 

Creating Transitions Between Blends

Characters can transition between blends by specifying a transition. A transition indicates how a character will utilize one source blend when transitioning to a destination blend. Transitions indicate a moments where the source blend will being fading out, and the destination blend will start fading in. Currently, only one fade-in point can be specified on the destination blend, while multiple fade-out points can be specified on the source blend.

A transition can be specified as follows:

blendManager = scene.getBlendManager()
transition = blendManager.createTransition('blend1", "blend2")
transition.setEaseInInterval("motionOnBlend2", 0, 2)
transition.addEaseOutInterval("motionOnBlend1", 4, 6)
transition.addEaseOutInterval("motionOnBlend1", 7, 9)


This will create a transition between blends 'blend1' and 'blend2', where 'blend1' will start fading out between seconds 4 and 6 and start fading in to 'blend2' between seconds 0 and 2. If the motion in 'blend1' has already passed the 4 second mark, then the second fading out point will begin at second 7 and last until second 8.

Automatically Transitions Between Blends

Triggers can be constructed that automatically transitions between blends based on various aspects of the simulation, such as character location, attributes, objects in the scene, and so forth.

To construct such a trigger, you build a rule that is then attached to the transition:

class MyTransitionRule(TransitionRule):
   def check(self, character, blend):
      blendManager = scene.getBlendManager()
      vec = blendManager.getCurrentBlendParameters(character.getName())
      if (vec.getData(0) < 2.0):
         return True
      else:
         return False


myrule = MyTransitionRule()
blendManager = scene.getBlendManager()
transition = blendManager.getTransition('blend', 'blend2')
transition.setTransitionRule(myrule)

In this case, the transition rule will trigger if the value of the first parameter of the blend is less than 2.