Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Overview

This document explains the basic steps to setup and debug BSpaces in the Character Tool. It doesn't cover any game-code, AI or CryMannequin specific thing.

Table of Contents
maxLevel3
minLevel2
excludeOverview

Visualizing BSpaces

The best way to get a feeling how BSpaces work internally, is to start a simple 2D-BSpaces, visualize it in the Character Tool and a play around with the different debug options.

  1. Start the Character Tool and load a model.
  2. Select "2D-BSpace_MoveTurn" from the animation list. The character should start to run forward.
  3. If the character runs in place, make sure the checkbox "Animation Driven" is activated.
  4. Once the characters moves, go to "Blend Space Control" and use the first to sliders to change speed and curvature.
  5. Go to the DebugOptions in the Character Tool (right/down corner) and activate InPlaceMovement. This will put the base-character back to the origin. (This is necessary, because for debugging we render the blend-space and the base-character in the same view-port and the camera is attached to the base-character)
  6. Next go to the console and type in ca_DrawVEGInfo 3.5
  7. With the mouse and WASD move the camera back from the origin. On the left you can see the grid for the BSpace and on the right the blended character. To simplify the debug-output it might help to disable the grey ground grid (ShowGrid), or the world coordinate system (ShowBase), or the yellow locomotion locator (ShowLocator) You'll find both check-boxes in DebugOptions in the Character Tool (right/down corner).

Debug parameters of ca_DrawVEGInfo

In SDK 3.5 we improved the CVar parameters slightly for better debug output. The CVar takes a float value in the format ca_DrawVEGInfo 2.344455. By default its ca_DrawVEGInfo 0.0, which means debugging is disabled.

...

d) There is also a green wireframe quat. This shows which assets are currently considered in the blend. In a 2D BSpace we have either triangles (blends between 3 assets) or quats (blends between 4 assets)
e) Inside of a triangle or quat there is always a red flashing cursor. You can control it with the blend-space sliders in the Character Tool and see at any time which assets contribute to the final blend.

The number in front of the comma are now interpreted as bit-fields.

Bit 1:

If set it shows only the pink lines of the blend-space grid (i.e. ca_DrawVEGInfo 1.5). For an 1D-BSpace it's a simple line segment. For an 2D-BSpace it's a plane. For an 3D-BSpace it's a cube.

...

Code Block
languagexml
<Dimensions>
	<Param name="MoveSpeed" min="+0.2" max="+9.5" cells="7"/>
	<Param name="TurnSpeed" min="-3.8" max="+3.8" cells="7"/>
</Dimensions> 

Bit 2: Visualize the Virtual Examples (little blue cubes)

In the XML-example above, the min/max values are the range of the blend-space and the cells are the density of the grid. We map a simple regular grid over the range of the blend-space and then we loop over this 2d- or 3d-array and compute the virtual-examples.

...

Virtual-example grids solve that issue with a simple offline-computation by pre-computing the blend-weights and storing them in a regular-grid. This method is basically a mapping of scattered data to a regular grid structure (line-segments, rectangles, cubes). At runtime, when we move a cursor through this space, we check in which grid-cell it is, read the 2,4 or 8 pre-computed blend-weights from the edges of the grid-cell and do a either a normal interpolation, a bilinear interpolation or a trilinear interpolation. The method is efficient at runtime, since it is a simple lookup and linear interpolation over a regular grid is straightforward. The CPU-time for this is totally independent of the number of motions you have in a blend-space or the complexity of the annotations.

Bit 3: Additional debug information.

These use usually additional text information printed on the screen. Mainly useful for programmers for deep debugging.

Building Blend Spaces

The blend-spaces are XML files and they are edited with a text-editor. In the Character Tool we support hot-loading of files. This means you can change the file with a text editor on disk and the system will update it automatically and render the result. With a bit of experience it's very easy to prototype things and do a lot of experimentation.

We will explain all the concepts and parameters while we build different types of bend-spaces. Almost all parameters in the XML files are identical for 1D, 2D and 3D blend-spaces, so it's recommended to do experiments with 1D or 2D blend-spaces, because its way easier to understand the interactions between assets, annotations and different parameters. Don't start with a huge 3D blend space.

Example1: 1d-bspace_DummyPara1.bspace

This is the simplest blend-space you can build, without any advanced features. The only purpose is to lerp two animations.

...

Note
 In this example1+2 the character can only move on the spot (even if you disable the InPlaceMovement), because we didn't specify yet how to deal with the locator motion. That will happen later in Example 3.

Example2: 1d-bspace_DummyPara2.bspace

Then we can build a generalized one-dimensional blend-space by placing an arbitrary number of clips along a linear scale. This blend-node is doing a lerp between 2 clips adjacent to the input-value.

...

Note
iconfalse
It is important that p0 points to the lower parameter and p1 points the higher parameter of the examples. If the order is reversed or both parameters are identical, the system will halt with an error.

Example3: 1d-bspace_DummyPara3.bspace

In order to get motion-extraction, we have to add these parameters, because BlendWeight doesn't say that directly.

...

If we add these parameters to the previous BSpace, the characters is using its locator motion to move though the world (in this special case the "MoveSpeed" would be enough, because the assets have only forward motion). Also make sure "Animation Driven" is activated and "InPlaceMovement" deactivated. The move speed can be controlled again with the BlendWeight slider. If the assets are clean (we have special rules to create locomotion assets) you can blend between different move-speeds without getting foot-sliding. That's pretty much all about simple animation blending with blend-spaces.

Example4: 1d-bspace_Move1.bspace

And now we move to the main-topic of blend-spaces: Parametric Blending. This is still a simple binary lerp, but we tell the system to extract the parameters directly out of the motions. The parameter "MoveSpeed" tells the system to extract the move-speed out of the root-motion and inserts it into automatically into the blend-space. The result is a blend-space where all assets have a different positions on the x-axis. These positions are what we call the "natural" motion parameters, because they are coming from the motion directly. In this case, the blend-space represents these real motion parameter, which is not the case when you use SetPara0="?" as we did before.

...

Note

This BSpace is a special case where you need SDK 3.5.2, which supports automatic extrapolation for 1D blend-spaces. In previous version it will simply pop to the first asset if you move the cursor outside the range of the fastest/slowest asset. We used pseudo examples to overcome this.

Example5: 1d-bspace_Move2.bspace

This example shows how to create pseudo assets by extrapolating two existing assets. The pseudo assets are rendered with a red cube. These are basically procedurally generated assets.

...

The result of extrapolation can be very unpredictable. Sometimes you get surprisingly interesting results, and sometimes only a weird twisted pose. There is no way to tell in advance whether extrapolation will produce good or bad animations. This feature can be very useful in blend-spaces with higher dimensions. With "extrapolated pseudo examples" you can test several asset-combinations in a blend-space, and see which give acceptable results. It's some kind of controlled extrapolation. If you are not happy with the result, then you have to "patch" the blend-space with new examples. We don't recommend overuse of extrapolation, but if you use it only for a couple of seconds, then it's perfectly fine and it helps to save a lot of memory.

Example6: 1d-bspace_Move3.bspace

This example shows how to create pseudo assets by scaling the playback-rate of existing assets. The pseudo assets are rendered with a green cube. These is yet another method to create procedurally generated assets.

...

This blend-node is using the same asset twice and because of the PlaybackScale="0.1" and PlaybackScale="1.5" we place it at 2 different positions on the line. When you use the Move-slider, then you can generate a parameterized walk in the range [0.1 … 10.0] without foot-sliding.

What's the difference between Extrapolated Examples and Playback Scaled Examples?

Both are pseudo examples and in the previous case both techniques gave visually similar results, because the blend-weights or scale-value was pretty small. But both are totally different techniques and in some cases they will give drastically different results.

...

All these parameters are linked to specialized C++ code, which extracts the values from the root-motion and uses them to drive the blend-spaces. Adding new parameters requires a change in C++ code.

Example7:1D-BSpace_Turn.bspace

So far we had only moving-forward, but it's easy to combine it with a turn animation. All we need are 3 assets: run-forward, run-turn-right and run-turn-left. The curved yellow locator indicates a turning animation. In all cases the character always moves in the direction his body points.

...

With the blend slider "Travel Angle" in the Character Tool you can control the curvature. There is no way to adjust the move-speed. Character moves exactly at the speed the animations are authored. We will show later with 2D-blend spaces how to overcome this.

Example8:1D-BSpace_Slope.bspace

Another practical example is moving uphill and downhill. All we need are 3 assets: walk-forward, walk-up and walk-down. The yellow locator indicates a slope-angle. In all cases the character always moves in the direction his body points.

...

With the blend slider "Slope" in the Character Tool you can control the slope angle. The move-speed is not controllable and the character will moves exactly at the speed the animations are authored. We will show later with 2D-blend spaces how to overcome this.

Example9:1D-BSpace_StrafeMove_8clips.bspace

A classical motion example for games is strafing-movement where the character keeps his body-direction constant (i.e. always looking forward), but wants to move with his legs forward, sideways or backwards. A simple way to do this with blend-spaces is to take 4, 6 or 8 assets which cover all move-directions we need, and represent each direction by a radiant. Moving forward is always a value of 0.0. All values between 0.0 and -3.147 are movements to the right. All values between 0.0 and +3.147 are movements to the left. The values +3.147 and -3.147 both represent a perfect backwards motion. To cover a full circle we need a blend-space that ranges from -3.147 to +3.147. Or 2pi if you want.

...

It is probably not immediately obvious why SetPara0="-3.147" and SetPara0="+3.147" are needed. Why do we need to set this values manually? Why can't we extract them automatically out of the file? As mentioned before, to cover a full circle we need a blend-space that ranges from -3.147 to +3.147 (or from -pi to +pi). Unfortunately it is impossible for an artist to create two different assets, one that moves -3.147 and one that moves +3.147. Technically both are the same assets and with automatic extraction both would end up at the same position in the blend-space. That is an illegal case. The only way to use it in the context of a linearized blend-space is to set the parameter directly and place the same asset at different positions in the space. In order words, the parameter SetParaX is yet another way to create pseudo assets to populate a blend-space.

How many assets do we need for 360-degree movement?

The absolute minimum is 4 assets; forward, left, right, backwards. This will cover all directions, but the diagonal blends usually don't look good, because forward-motions and sideway-motions are not really a compatible for blending. You will always get with foot-sliding, foot-crossing and feet dipping through the ground. That's why 8 assets is recommended.

Another classical issue with strafing is the hip-rotation. Usually the hips point to the right, when strafing right and to the left when strafing left. This feels more natural for the mocap actor. The problem is that doing quick left/right strafes always looks like Samba dancing. That's why it is recommended to keep the hip-orientation static per blend-spaces, and create a new blend-space for each hip-rotation and play an explicit transition to adjust the gate. For such a solution you might need 16 assets for a single speed.

Example9:1D-BSpace_StepRot.bspace

Another practical example are IdleStep-Rotations where a character is turning on the spot.

...

The problem is more extreme for the Idle2Moves. Just imagine a character leans in to start a 90-degree-to-the left run, and the user suddenly decides he wants to run in a different direction. if we change the blend-weights immediately, the animation would look weightless and implausible. With the flag set, the BSpace only takes new inputs when it is pushed into the queue or when the animation reaches the end of the cycle and loops.

The parameter deltaextraction="1" is a used for distance-based motion extractions and is necessary for step-rotations and idle2Moves.

Example10:1D-BSpace_I2M_left.bspace

Another practical example are Idle2Move animations, where a character is stating in an idle pose and then starts a run-transition into any direction.

...

If we pass a parameter between -3.15 and +3.15, then we just need to check if the parameter is inside the range of at least one of those BSpaces and pick it to execute the blend. Of course, we have to make sure that the BSpaces don't overlap.

2D-Blend Spaces

So far we were able to change only one single parameter at a time. But there are many cases in a game where it is required to smoothly change two aspects of a motion simultaneously and independently. This means when we change one parameter, the other parameter stays constant and vice versa.

Example: 2D-BSpace_MoveTurn1.bspace

A classical example for a 2D blend space could be a character who moves at different speeds (i.e. slow, fast, sprint) and also changes his body orientation (i.e. turn left/right at different speeds) while he moves. When we change the speed, we don't want to change the turn-radius and when we change the turn-radius it should have no impact on the speed.

...

General rule for 2D annotations: if you look from birds-eye view onto the blend-space in the Character Tool, then all annotations happen counter-clockwise for triangles and quats. Triangles are not allowed to have overlapping points. Quats are not allowed to have overlapping points or a twisted shape.

Example: 2D-BSpace_MoveSlope.bspace

In the same way we did the MoveTurn, we can also build MoveSlope. When we change the speed, we don't want to change the slope-angle and when we change the slow-angle it should have no impact on the speed.

Example: 2D-BSpace_MoveTurn2.bspace

The previous blend-space had a large area that was not covered by real examples. If you move the cursor into such an area then the blending behaviors is undefined. Since SDK3.5.2 all blend-space type support automatic extrapolation (which means the system is talking the closest annotation and extends it) but it is not recommended to rely on it. A much better way is to use extrapolated pseudo-examples to cover the whole space.

...

This is also a good case to observe how extrapolated pseudo examples work. Just move the cursor into a corner of the blend-space, i.e. MoveSpeed 10m/sec and TurnSpeed 3.14rad/sec. You can see that the strides are much wider and the upper body swings like crazy. This is an extremely exaggerated version of real examples. Such an effect is not possible with pseudo example where you simply change the playback speed.

Example: 2D-BSpace_I2M_left.bspace

It's also possible to have Idle2Moves with different speeds. In the next example we can blend between walkStart and runStart when doing a transition into a walk or run. This XML also uses a combination of real examples and scaled example to cover the whole blend-space.

...

Code Block
languagexml
<Dimensions>
	<Param name="MoveSpeed" min="+.50" max="+6.00" cells="9" JointName="Bip01 Root" skey="0.9" ekey="1.0"/>
	<Param name="TurnAngle" min="0.00" max="+3.15" cells="9" JointName="Bip01 Root" skey="0.0" ekey="1.0" locked="1" deltaextraction="1"/>
</Dimensions> 

Example: 2D-BSpace_MoveStrafe1.bspace

Another example for a 2D blend space is a character who moves at different speeds (i.e. slow, fast, sprint) and also changes his move orientation (i.e. forward/left/right/backwards) while he moves. When we change the speed, we don't want to change the move-direction and when we change the move-direction it should have no impact on the speed.

...

Code Block
languagexml
<Dimensions>
	<Param name="MoveSpeed" min="+1.0" max="+4.5" cells="19" />
	<Param name="TravelAngle" min="-3.14" max="+3.14" cells="17" />
</Dimensions> 

Example: 2D-BSpace_MoveStrafe2.bspace

In the previous strafe example we had walk and run assets for different speeds. Sometimes you need only a slight variations of move-speeds where the visual difference in the assets is so small that you don't want to create new assets. In this example we took the crouch strafe and use PlaybackScale to create a pseudo assets with different move-speeds. So every asset is used twice, but with a different speed. Because the duplicated assets also have different positions it the space, we can use them to build a blend space with 2 dimensions. With this simple trick we can generate move-speeds between 0.2m/sec and 2.5m/sec by scaling the speed of original assets.

...

Code Block
languagexml
<ParaGroup>
	<Dimensions>
		<Param name="MoveSpeed" min="+0.20" max="+2.50" cells="9" />
		<Param name="TravelAngle" min="-3.14" max="+3.14" cells="29" />
	</Dimensions>
	<ExampleList>
		<Example AName="crouch_tac_walk_rifle_bwd_slow_3p_01" SetPara1="-3.147" PlaybackScale="0.15" />
		<Example AName="crouch_tac_walkCross_rifle_bRgt_slow_3p_01" PlaybackScale="0.15"/>
		<Example AName="crouch_tac_walkStr_rifle_rgt_slow_3p_01" PlaybackScale="0.15" />
		<Example AName="crouch_tac_walk_rifle_fwd_slow_3p_01" PlaybackScale="0.15" />
		<Example AName="crouch_tac_walkCross_rifle_fLft_slow_3p_01" PlaybackScale="0.15" />
		<Example AName="crouch_tac_walkStr_rifle_lft_slow_3p_01" PlaybackScale="0.15" />
		<Example AName="crouch_tac_walk_rifle_bwd_slow_3p_01" SetPara1="+3.147" PlaybackScale="0.15" />
		<Example AName="crouch_tac_walk_rifle_bwd_slow_3p_01" SetPara1="-3.147" PlaybackScale="4.50" />
		<Example AName="crouch_tac_walkCross_rifle_bRgt_slow_3p_01" PlaybackScale="6.00" />
		<Example AName="crouch_tac_walkStr_rifle_rgt_slow_3p_01" PlaybackScale="3.50" />
		<Example AName="crouch_tac_walk_rifle_fwd_slow_3p_01" PlaybackScale="3.40" />
		<Example AName="crouch_tac_walkCross_rifle_fLft_slow_3p_01" PlaybackScale="4.40" />
		<Example AName="crouch_tac_walkStr_rifle_lft_slow_3p_01" PlaybackScale="4.40" />
		<Example AName="crouch_tac_walk_rifle_bwd_slow_3p_01" SetPara1="+3.147" PlaybackScale="4.40" />
	</ExampleList>
	<Blendable>
		<Face p0="6" p1="5" p2="12" p3="13" />
		<Face p0="5" p1="4" p2="11" p3="12" />
		<Face p0="4" p1="3" p2="10" p3="11" />
		<Face p0="3" p1="2" p2="9" p3="10" />
		<Face p0="2" p1="1" p2="8" p3="9" />
		<Face p0="1" p1="0" p2="7" p3="8" />
	</Blendable>
</ParaGroup>

3D-Blend Spaces

All the concepts we learned about 1D and 2D apply to 3D blend-spaces as well. There is nothing special about 3D blend-spaces, except the fact that we have an additional dimension.

The only issue we have with 3D and higher dimension is, that it starts to get harder to visualize and to debug.

Example: 3D-BSpace_MoveTurnSlope.bspace

One application for 3d is to put move-speed on X, turn-speed on Y, slope-angle on Z. You can see in which direction this is going: each new control-parameter is actually a new dimension in the Blend-Space. In 3D we can control uphill/downhill motion and we can combine this with all different speeds and turn-angles.

...

Each volume has a ground plane (3-4 points) and a tip (1-2 points). If the tip points up, the vertices on the ground plane must be annotated counter clockwise. If the tip points down, the vertices on the ground plane must be annotated clockwise.

Example: 3D-BSpace_MoveTurnSlope_Combination.comb

3D blend spaces are more difficult to debug, even with a very structured design. Fortunately, many higher dimensional blends are a combination of simple lower-dimensional blends. This relationship makes it possible to combine two 2D spaces into a 3D space and two 3D spaces into a 4D space. These are simple linear combinations. We want to show how to recreate the previous "3D-BSpace_MoveTurnSlope.bspace" with a simple combination of 2D blend-spaces. This is also a good example to show another application of the *.COMB file.

...

The same concept works with higher dimensions as well. For C3 we took two 3D blend-spaces and combined them into a 4D blend-space. That was just a proof of concept how far we can push it with blend-space algebra.

Rules of Annotations

With blend-spaces we treat animation-blending as a geometrical problem. The setup and the internal structures of a blend-space is similar to a model-mesh with a vertex-buffer and an index-buffer: Each animation-clip in the ExampleList represents a point in a coordinate-system. In other words we associate each animation with a 1D, 2D or 3D position in a space and the list of all examples is the vertex-buffer. The tricky part of course is to covert animations into positions in a space. In our case the positioning of animations can happen either manually(with SetParaX=?) or with automatic extraction(which is recommended if you want proper parametric blending).

...

Here are the basic rules to annotate the blend-spaces:

1D-Annotations

In 1D-blend spaces all the points are on a line and that's why we use line-segments for annotations. It is important that p0 points to the lower parameter and p1 points the higher parameter of the examples. If the order is reversed or both parameters are identical, the system will halt with an error.

It is also important to make sure that there are no gaps in the line (holes that are not covered with a line-segments) or overlapping line-segments. This might lead to undefined behavior. At runtime we check if the input-parameter is inside of one those line-segments and then interpolate between those two animations. In the ideal situation the input-parameter should always be inside of a line-segment. Since SDK3.5.2 we added automatic extrapolation (which is pretty predicable for 1D spaces), but a bit slower compared to a properly annotated space.

2D-Annotations

In 2D-blend spaces all the points are on a plane. You look from birds-eye view onto the blend-space in the Character Tool, then all annotations happen counter-clockwise for triangles and quats.

It is important to make sure that there are no gaps in the space (holes that are not covered with a face) or overlapping triangles and quats. This might lead to undefined behavior. At runtime we check if the input-parameter is inside of one those triangles (3 animations) and quats (4 animations) and then interpolate between those animations. In the ideal situation the input-parameter should always be inside of a face.

3D-Annotations

In 3D blend spaces we have tetrahedrons, pyramids and prisms. All of them have a ground plane (3-4 points) and a tip (1-2 points). If the tip points up, the vertices on the ground plane must be annotated counter clockwise.

...

It is important to make sure that there are no gaps in the space (holes that are not covered with a volume) or overlapping volumes. This might lead to undefined behavior. At runtime we check if the input-parameter is inside of one those volumes and then interpolate between those animations. In the ideal situation the input-parameter should always be inside of a volumes.

Workflow to annotate blend-spaces

We are aware that the setup process with a text-editor is a bit inconvenient. But if you use the hot-loading feature in a correct way, you can reduce this process to 1-5 minutes for most blend-spaces.

...

Note
The hot-loading system tries to catch most errors, i.e. typos that break the XML-format, invalid parameters, not existing file-names. If such an error is detected, the BSpace is deactivated and there is an error-messages in the log. There are still some entries possible that are hard to catch and create a fp-exception on the lowest level. In such a case restart Sandbox is the only option.

Additive and Override Animation

Just like a single animation, blend-spaces can be played on any animation layer (not restricted to layer 0).

...