Smooth Character Motion in Source Engine Using $blend Animation Blending
Learn how to use Source Engine’s $blend QC directive to smoothly transition between idle and run animations, with a worked example, verification steps, and performance considerations.
29 Aug 2025, 04:58 UTC

Problem: Jerky Transitions Between Idle and Walk
When a character switches from an idle pose to a walk or run cycle, the abrupt change in bone poses can cause a visible pop or jitter. This is especially noticeable in fast‑paced games where the player’s speed changes frequently. The visual glitch breaks immersion and can make controls feel unresponsive.
Thesis: The $blend Directive Provides Runtime Interpolation
Source Engine’s QC system lets you define two or more sequences and blend them at runtime with the $blend directive. By interpolating bone weights between a base animation (e.g., idle) and a motion animation (e.g., run) based on a normalized parameter (0‑1), the engine produces a smooth transition without noticeable pops.
Setting Up the QC File
First, ensure both source animations share the exact same bone hierarchy and naming. Mismatched bones will trigger warnings and cause artifacts.
$modelname "character.mdl"
$cdmaterials "models/character/"
$sequence idle "idle.smd" loop fps 30
$sequence run "run.smd" loop fps 30
$blend idle run 0.5 // placeholder; actual value set at runtime
The 0.5 is a default; the real blend factor will be overridden by code.
Driving the Blend Parameter from Speed
In the character’s animation controller (typically a C++ class derived from CBaseAnimating), expose a pose parameter that matches the blend name. The following snippet shows how to update it each frame based on the character’s forward velocity.
// In your character’s UpdateAnimation() method
void CMyCharacter::UpdateAnimation()
{
float speed = GetAbsVelocity().Length2D();
// Normalize speed to 0‑1 range; adjust maxSpeed to your game’s top speed
float maxSpeed = 320.0f; // example value for Source
float blend = clamp(speed / maxSpeed, 0.0f, 1.0f);
SetPoseParameter("blend", blend); // "blend" must match the $blend name
BaseClass::UpdateAnimation();
}
When the character is idle, blend approaches 0, showing mostly the idle sequence. As speed rises, the blend shifts toward the run sequence, producing a fluid motion.
Verification and Diagnostic Steps
- In‑game: Open the console (
~) and runcl_showanimstate 1. Select the character and watch the Blend Weight field change smoothly as you move. - Model Viewer: Load the compiled
character.mdlinhlmv. Use the pose‑parameter slider labeled “blend” to scrub between 0 and 1; the mesh should deform without seams or sudden limb twists. - Log Check: Launch the game with
+developer 1and look for any lines containinganimation blend warning. Their absence indicates the bone hierarchies match.
Trade‑offs and Limitations
Blending adds a modest CPU cost per blended model because the engine must compute weighted bone matrices each frame. On older hardware or when many characters are on screen simultaneously, this can impact frame rate. The engine provides the console variable cl_showanimstate to profile blend costs.
More importantly, the source animations must have identical bone layouts and similar timing. If the idle and run sequences differ significantly (e.g., different foot placement or extra bones), blending can produce limb twisting or unexpected poses. In such cases, consider using animation layers or a state machine instead of blending.
Actionable Closing
To adopt this technique:
- Prepare idle and run (or any two) animations with matching skeletons.
- Add a
$blendline in the QC file, using a placeholder value. - Expose a pose parameter in your character’s animation controller and drive it with a normalized speed value each frame.
- Verify in‑game with
cl_showanimstate 1and inhlmv; watch for warnings in the developer console. - Profile with
cl_showanimstate 1orstat anim; if CPU usage becomes a concern, limit blending to nearby characters or use LOD models with simpler animations for distant entities.
By following these steps, you can replace jarring animation switches with smooth, responsive motion that enhances player immersion while keeping performance under control.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.