UDN
Search public documentation:

PhysicalAnimation
日本語訳
中国翻译
한국어

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UE3 Home > Physics > Physical Animation
UE3 Home > Animation > Physical Animation
UE3 Home > Animators > Physical Animation
UE3 Home > Skeletal Meshes > Physical Animation

Physical Animation


Overview


There are often situations where physics simulations must be performed on attachments to achieve the desired animation. For example, chains on a prisoner that rattle around or rag dolls for an unconscious character that flops around. As the characters moves and blends between different animations, it's impossible to predetermine where things may be. Unreal Engine 3 solves this problem by allowing animators and programmers to define some or all bones in a skeletal mesh as physically simulated rigid body attachments.

A character that has chains attached to the arms that are driven by physics, with the rest of the body driven by blended animations and inverse kinematics.

SkeletalMeshWithPhysicsSimulatedChains.jpg

A character that is using physics to simulate the whole body.

SkeletalMeshRagdoll.jpg

Pipeline


The physical animation system is part of the Unreal Engine 3 animation pipeline. First, the normal animation is processed when blending is handled via the Anim Tree. Secondly, inverse kinematic control is then applied via the Anim Tree. Lastly, the physics is applied to the skeleton via the Physics Asset. The physics sub system then processes the remaining physics, and the graphics sub system then renders the scene.

The physics for the skeleton is calculated based on whether the bone is fixed or not. Fixed bones are never simulated by physics and will be driven by the blended animation and inverse kinematic system. Unfixed bones will be simulated by physics.

Workflow


A programmer and an animator will work together to produce the needed physical animation content. The animator will set up the physics asset which involves locking the bodies and simulating the system to see how it all ties together. The programmer will then be responsible for enabling or disabling physical animation depending on the game play.

Controlling Physics


Types of Physics

There are two types of physics:
  1. Kinematic ("fixed")
    • Goes exactly where you say
    • Ignores collisions
    • Pushes objects it hits very hard
  2. Dynamic ("unfixed")
    • Responds realistically to collisions
    • Need to use forces or constraints to control it

Physics Objects

There are three physics objects:
  1. Forces
    • Used to apply a constant force (such as gravity or wind)
  2. Impulse
    • Used to apply a one off force (such as explosions or gun shots)
  3. Constraint
    • Used to apply a continuous force (such as joints or springs)

Partial physical simulation on skeletal meshes


A common effect in modern games is to have some parts perform physics simulation, while the rest of the character animates using blended animations and inverse kinematics. The easiest way to set this up is to make the character's skeletal mesh contain all bones, including those for the physically simulated parts. Shown below is the skeleton used for the chained character.

SkeletalMeshBones.jpg

This also means you should create a PhysicsAsset for the skeletal mesh using the PhAT tool, including the bones that you want to be physical simulated. You can preview how these physics parts will look in PhAT by 'fixing' all but those bodies (which can be easily done by right-clicking in the tree view and choosing Unfix All Bodies Below.. or Fix All Bodies Below... You can also set the fixed status of individual rigid bodies by clicking on the bone and checking or unchecking the Fixed property.

SetFixedBodies.jpg

During simulation in the tool, you can assign an AnimSet in the Preview Anim Set option, and pick an animation (such as a run cycle) from the drop down on the tool bar to loop. Press the play button to loop the animation, or the stop button to stop the animation. You can change the animation on the fly without having to stop the simulation. You can also check the Blend On Poke property, which will allow you to use the left mouse button to poke the skeletal mesh and have it blend between partial and full physical simulation.

PlayAnimationWithSimulatingUnfixedBodies.jpg

Make sure to assign the PhysicsAsset to your character in game, and set bHasPhysicsAssetInstance to true.

SetupSkeletalMeshActor.jpg

Now when you run the game, and type nxvis collision in the console, you should see white shapes for the physics objects of your character. However they aren't physically simulating just yet.

ShowPhysicsCollision.jpg

What needs to be considered is how the physics for these bones will be blended into the animations of your character. Normally you use the PhysicsWeight parameter on the skeletal mesh component to choose how much to blend between the output of the physics engine and the output of the animation system. In this case, you want to have these particular bones to always use the output of the physics engine, even when PhysicsWeight is zero. To do this, there is a parameter called bAlwaysFullAnimWeight on each rigid body within the physics asset. Set this to true for all these bones. You will also need to set bEnableFullAnimWeightBodies to true on the skeletal mesh component.

SettingAlwaysFullAnimWeight.jpg

When an actor's physics is PHYS_RigidBody, rigid bodies default to the fixed state that is defined in the physics asset. However, characters that are running around are normally are usually in PHYS_Walking or PHYS_Falling etc, all rigid bodies default to fixed; regardless of what is defined in the physics asset. In order to have the physics simulate on our these rigid bodies, it is required to explicitly 'unfix' them in code. There is a helpful function called SetFullAnimWeightBonesFixed within PhysicsAssetInstance. If you look at SkeletalMeshActor you can see an example of unfixing the flagged rigid bodies inside PostBeginPlay.

SkeletalMeshActor.uc
simulated event PostBeginPlay()
{
  // grab the current mesh for replication
  if (Role == ROLE_Authority && SkeletalMeshComponent != None)
  {
    ReplicatedMesh = SkeletalMeshComponent.SkeletalMesh;
  }

  // Unfix bodies flagged as 'full anim weight'
  if (SkeletalMeshComponent != None &&
      //SkeletalMeshComponent.bEnableFullAnimWeightBodies &&
      SkeletalMeshComponent.PhysicsAssetInstance != None)
  {
    SkeletalMeshComponent.PhysicsAssetInstance.SetFullAnimWeightBonesFixed(FALSE, SkeletalMeshComponent);
  }

  if(bHidden)
  {
    SkeletalMeshComponent.SetClothFrozen(TRUE);
  }
}

Once you have done all of these steps, you should see your parts moving physically in-game. If there are problems, it is good to use the nxvis collision option. If you are not seeing any white shapes, then there is something wrong with the physics asset, or the way it is assigned, or perhaps there is no PhysicsAssetInstance for some reason. If you see white shapes, but the rigid bodies are not being simulated, then there is something wrong with the unfixing of these rigid bodies. If you see the white rigid bodies moving correctly, but the bones are not, there is something wrong with them being blended into the final result.

Having partial physics simulation on skeletal meshes that are attached using Unreal attachment methods to other skeletal meshes can be tricky. This is mainly a problem when the base skeletal mesh component uses physics as well - for example if you wanted to attach a ponytail skeletal mesh to a character skeletal mesh, and the character then falls down using physics. This will usually result in a one-frame lag between the ponytail and the head, because Unreal code has to execute after the body has been simulated in order to update the fixed body location of the pony tail root to the attached location. One way to get around this is to instead create a physics joint between the pony tail and the head in code, rather than using Unreal attachment methods. This is a little complex though - an example can be seen in the UT hoverboard function SetHoverboardRiderPhysics, where the feet of a physics rider are jointed to the physics hoverboard. Or you can set bForceUpdateAttachmentsInTick to reupdate attachments; but this can be expensive.

A final thing you may want to adjust is collision. To have rigid bodies collide with the rest characters animated physics bodies, you will first need to set BlockRigidBody to true. Then you need to make sure that whatever RBChannel is set to is also set to true in the RBCollideWithChannels container. For a character, this is normally RBCC_Pawn. Currently it is not easy to have rigid bodies parts collide only with their owners limbs, and not with limbs of other characters. In this example, one of the chains that is attached to the characters arms is colliding with the crate below.

RigidBodyCollision.jpg

Full physical simulation on skeletal meshes


  • bHasPhysicsAssetInstance must be true. This will ensure that the physics sub system instances the physics asset for this skeletal mesh. This is not necessary for per-bone line checks on the skeletal mesh.
  • The actor that owns the skeletal mesh does not require the physics mode be set to PHYS_RigidBody. This just ensures that the actor's location and rotation matches the root body's location and rotation.
  • Unfix the rigid body instances that you want to be dynamic by calling SetFixed(false) which is defined in RB_BodyInstance.
  • Ensure physics is blended in for those bodies
    • Set PhysicsWeight to a value greater than zero in the skeletal mesh component.
    • Set bEnableFullAnimWeightBodies to true in the skeletal mesh component.
    • Set bAlwaysFullAnimWeight to true in RB_BodySetup.

YourPawn.uc
simulated function bool Died(Controller Killer, class<DamageType> DamageType, vector HitLocation)
{
  if (Super.Died(Killer, DamageType, HitLocation))
  {
    Mesh.MinDistFactorForKinematicUpdate = 0.f;
    Mesh.SetRBChannel(RBCC_Pawn);
    Mesh.SetRBCollidesWithChannel(RBCC_Default, true);
    Mesh.SetRBCollidesWithChannel(RBCC_Pawn, false);
    Mesh.SetRBCollidesWithChannel(RBCC_Vehicle, false);
    Mesh.SetRBCollidesWithChannel(RBCC_Untitled3, false);
    Mesh.SetRBCollidesWithChannel(RBCC_BlockingVolume, true);
    Mesh.ForceSkelUpdate();
    Mesh.SetTickGroup(TG_PostAsyncWork);
    CollisionComponent = Mesh;
    CylinderComponent.SetActorCollision(false, false);
    Mesh.SetActorCollision(true, false);
    Mesh.SetTraceBlocking(true, true);
    SetPhysics(PHYS_RigidBody);
    Mesh.PhysicsWeight = 1.0;

    if (Mesh.bNotUpdatingKinematicDueToDistance)
    {
      Mesh.UpdateRBBonesFromSpaceBases(true, true);
    }

    Mesh.PhysicsAssetInstance.SetAllBodiesFixed(false);
    Mesh.bUpdateKinematicBonesFromAnimation = false;
    Mesh.SetRBLinearVelocity(Velocity, false);
    Mesh.ScriptRigidBodyCollisionThreshold = MaxFallSpeed;
    Mesh.SetNotifyRigidBodyCollision(true);
    Mesh.WakeRigidBody();

    return true;
  }

  return false;
}

You can of course reverse the process to allow a rag dolled character to get back up again.

Unreal Editor


  • SkeletalMeshActor and its children are capable of using physics to simulate some bones on skeletal meshes.
  • KAsset and its children may be placed in the level to do full physics simulation on skeletal meshes.

Useful console commands


  • nxvis collision - shows the collision bodies used by the physics simulation. Use this over show collision, as show collision only shows the collision hulls used for the Unreal physics sub system.

NxvisCollisionConsoleCommand.jpg

  • show bones - shows the bone's location and rotation used to render the animated skeletal mesh.

ShowBonesConsoleCommand.jpg

  • show prephysbones - shows the bone's location and rotation after blended animation and inverse kinematics is applied but before physics is applied. Notice how the bones of the chains is pointing straight out, this is because there is no predefined animations made for them. But after physics is applied, the chains are in the correct position.

ShowPrePhysicsBonesConsoleCommand.jpg

Examples


A general purpose Actor was created for all examples below. For each example the Unrealscript logic flow is listed.

Unrealscript

HitReactionPawn.uc
class HitReactionPawn extends SkeletalMeshCinematicActor;

// Death animation
var(HitReaction) Name DeathAnimName;
// Bone names to unfix when hit reaction is simulated
var(HitReaction) array<Name> UnfixedBodyNames;
// Bone names to enable springs when hit reaction is simulated
var(HitReaction) array<Name> EnabledSpringBodyNames;
// Linear bone spring strength to use when hit reaction is simulated
var(HitReaction) float LinearBoneSpringStrength;
// Angular bone spring strength to use when hit reaction is simulated
var(HitReaction) float AngularBoneSpringStrength;
// Radius of the force to apply
var(HitReaction) float ForceRadius;
// Force amplification
var(HitReaction) float ForceAmplification;
// Maximum amount of force that can be applied
var(HitReaction) float MaximumForceThatCanBeApplied;
// Blend in time for the hit reaction
var(HitReaction) float PhysicsBlendInTime;
// Physics simulation time for the hit reaction
var(HitReaction) float PhysicsTime;
// Blend out time for the hit reaction
var(HitReaction) float PhysicsBlendOutTime;
// Full body rag doll
var(HitReaction) bool FullBodyRagdoll;

var Name PreviousAnimName;

event TakeDamage(int DamageAmount, Controller EventInstigator, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser)
{
  local AnimNodeSequence AnimNodeSequence;

  Super.TakeDamage(DamageAmount, EventInstigator, HitLocation, Momentum, DamageType, HitInfo, DamageCauser);

  if (SkeletalMeshComponent == None || SkeletalMeshComponent.PhysicsAssetInstance == None)
  {
    return;
  }

  if (IsTimerActive(NameOf(SimulatingPhysicsBlendIn)) || IsTimerActive(NameOf(SimulatingPhysics)) || IsTimerActive(NameOf(SimulatedPhysicsBlendOut)))
  {
    return;
  }

  if (FullBodyRagdoll)
  {
    if (DeathAnimName != '')
    {
      AnimNodeSequence = AnimNodeSequence(SkeletalMeshComponent.Animations);

      if (AnimNodeSequence != None)
      {
        PreviousAnimName = AnimNodeSequence.AnimSeqName;
        AnimNodeSequence.SetAnim(DeathAnimName);
        AnimNodeSequence.PlayAnim();
        AnimNodeSequence.bCauseActorAnimEnd = true;
        return;
      }
    }
    else
    {
      TurnOnRagdoll(Normal(Momentum) * FMin(DamageAmount * ForceAmplification, MaximumForceThatCanBeApplied));
    }
  }
  else
  {
    if (DeathAnimName != '')
    {
      AnimNodeSequence = AnimNodeSequence(SkeletalMeshComponent.Animations);

      if (AnimNodeSequence != None)
      {
        PreviousAnimName = AnimNodeSequence.AnimSeqName;
        AnimNodeSequence.SetAnim(DeathAnimName);
        AnimNodeSequence.PlayAnim();
        AnimNodeSequence.bCauseActorAnimEnd = true;
        return;
      }
    }
    else
    {
      TurnOnRagdoll(Vect(0.f, 0.f, 0.f));
      // Apply the impulse
      SkeletalMeshComponent.AddRadialImpulse(HitLocation - (Normal(Momentum) * 16.f), ForceRadius, FMin(DamageAmount * ForceAmplification, MaximumForceThatCanBeApplied), RIF_Linear, true);
      // Wake up the rigid body
      SkeletalMeshComponent.WakeRigidBody();
    }
  }

  BlendInPhysics();
}

event OnAnimEnd(AnimNodeSequence AnimNodeSequence, float PlayedTime, float ExcessTime)
{
  TurnOnRagdoll(Vect(0.f, 0.f, 0.f));
  BlendInPhysics();
  AnimNodeSequence.bCauseActorAnimEnd = false;
}

function TurnOnRagdoll(Vector RBLinearVelocity)
{
  // Force update the skeleton
  SkeletalMeshComponent.ForceSkelUpdate();

  // Fix the bodies that don't need to play a part in the physical hit reaction
  if (UnfixedBodyNames.Length > 0)
  {
    SkeletalMeshComponent.PhysicsAssetInstance.SetNamedBodiesFixed(false, UnfixedBodyNames, SkeletalMeshComponent,, true);
  }
  else
  {
    SkeletalMeshComponent.PhysicsAssetInstance.SetAllBodiesFixed(false);
  }

  // Enable springs on bodies that are required in the physical hit reaction
  if (EnabledSpringBodyNames.Length > 0)
  {
    SkeletalMeshComponent.PhysicsAssetInstance.SetNamedRBBoneSprings(true, EnabledSpringBodyNames, LinearBoneSpringStrength, AngularBoneSpringStrength, SkeletalMeshComponent);
  }

  SkeletalMeshComponent.bUpdateKinematicBonesFromAnimation = false;
  SkeletalMeshComponent.SetRBLinearVelocity(RBLinearVelocity, true);
  SkeletalMeshComponent.WakeRigidBody();
}

function BlendInPhysics()
{
  // Set the timer for the physics to blend in
  if (PhysicsBlendInTime > 0.f)
  {
    SetTimer(PhysicsBlendInTime, false, NameOf(SimulatingPhysicsBlendIn));
  }
  else
  {
    SkeletalMeshComponent.PhysicsWeight = 1.f;
    SimulatingPhysicsBlendIn();
  }
}


function SimulatingPhysicsBlendIn()
{
  if (PhysicsTime == 0.f)
  {
    SimulatingPhysics();
  }
  else
  {
    // Set the timer for the physics to stay
    SetTimer(PhysicsTime, false, NameOf(SimulatingPhysics));
  }
}

function SimulatingPhysics()
{
  local AnimNodeSequence AnimNodeSequence;

  // Set the timer for the physics to blend out
  SetTimer(PhysicsBlendOutTime, false, NameOf(SimulatedPhysicsBlendOut));

  if (PreviousAnimName != '')
  {
    AnimNodeSequence = AnimNodeSequence(SkeletalMeshComponent.Animations);

    if (AnimNodeSequence != None)
    {
      AnimNodeSequence.SetAnim(PreviousAnimName);
      AnimNodeSequence.PlayAnim(true);
    }
  }
}

function SimulatedPhysicsBlendOut()
{
  // Set physics weight to zero
  SkeletalMeshComponent.PhysicsWeight = 0.f;
  SkeletalMeshComponent.ForceSkelUpdate();

  if (FullBodyRagdoll)
  {
    SkeletalMeshComponent.PhysicsAssetInstance.SetAllBodiesFixed(true);
    SkeletalMeshComponent.bUpdateKinematicBonesFromAnimation = true;
  }
  else
  {
    SkeletalMeshComponent.bUpdateKinematicBonesFromAnimation = true;

    if (UnfixedBodyNames.Length > 0)
    {
      SkeletalMeshComponent.PhysicsAssetInstance.SetNamedBodiesFixed(true, UnfixedBodyNames, SkeletalMeshComponent,, true);
    }
    else
    {
      SkeletalMeshComponent.PhysicsAssetInstance.SetAllBodiesFixed(true);
    }

    // Disable springs on bodies that were required in the physical hit reaction
    if (EnabledSpringBodyNames.Length > 0)
    {
      SkeletalMeshComponent.PhysicsAssetInstance.SetNamedRBBoneSprings(false, EnabledSpringBodyNames, 0.f, 0.f, SkeletalMeshComponent);
    }
  }

  // Put the rigid body to sleep
  SkeletalMeshComponent.PutRigidBodyToSleep();
}

function Tick(float DeltaTime)
{
  Super.Tick(DeltaTime);

  if (IsTimerActive(NameOf(SimulatingPhysicsBlendIn)))
  {
    // Blending in physics
    SkeletalMeshComponent.PhysicsWeight = GetTimerCount(NameOf(SimulatingPhysicsBlendIn)) / GetTimerRate(NameOf(SimulatingPhysicsBlendIn));
  }
  else if (IsTimerActive(NameOf(SimulatedPhysicsBlendOut)))
  {
    // Blending out physics
    SkeletalMeshComponent.PhysicsWeight = 1.f - (GetTimerCount(NameOf(SimulatedPhysicsBlendOut)) / GetTimerRate(NameOf(SimulatedPhysicsBlendOut)));
  }
}

defaultproperties
{
  Begin Object Name=SkeletalMeshComponent0
    bHasPhysicsAssetInstance=true
    bUpdateJointsFromAnimation=true
  End Object

  ForceRadius=64.f
}

Physically simulated hit reactions

To add extra realism in games, characters should react as realistically as possible to the forces applied to them. Whether this is from an object in the world banging into them, or when they receive hits from a gun. There are two possibilities that can happen when a character is hit by a gun; depending on realistic you want your game to be.

Arcade simulation

Arcade simulation only is used in games where movement and aim should not be impeded by the hit reaction. Thus players always retain full movement and aiming capabilities. This would be important in games such as Unreal Tournament 3 since the player should always be in control.

This simulation will only apply physical changes to the upper part of the body, enable stiff angular springs in the hands and head to keep the gun and head pointing in the right direction.

The properties of HitReactionPawn to achieve this are:

ArcadeHitReaction.jpg

Unrealscript logic flow:

  • TakeDamage is called when the player shoots the HitReactionPawn
  • Check if there is a valid skeletal mesh component, physical asset instance and if the script is not currently in the middle of simulating physics
  • FullBodyRagdoll is false and DeathAnimName is empty, thus turn on physics, apply a radial impulse to simulate the weapon hit and wake up the rigid body
    • Unfix bodies defined in UnfixedBodyNames. If that is empty, it will unfix all bodies.
    • Enable bone springs is defined in EnabledSpringBodyNames, and set the strengths of them using LinearBoneSpringStrength and AngularBoneSpringStrength.
    • Bones no longer need to be updated via the animation, bUpdateKinematicBonesFromAnimation is set false.
  • Blend In timer is set.
  • When blend in timer is called, it will call the physics stay timer.
  • When physics stay timer is called, it will call the blend out timer.
  • After blending out, the process above is reversed.
  • If the blend in timer is running, or the blend out timer is running, tick blends between animation and physics by adjusting the PhysicsWeight by finding the percentage of time passed with the timers.

The neck and right clavicle bones are less likely to be affected by the player's shots, but the rest of the upper body reacts according.

ArcadeHitReactionShot.jpg

Realistic simulation

In games where realism is the main factor, it may be useful to allow players to prevent enemies from aiming at them by firing at them or to stop enemies from charging and running away by shooting the enemies legs.

The properties of HitReactionPawn to achieve this are:

RealisticHitReaction.jpg

The unrealscript logic flow is the same above however, bone springs and their strengths have been set. This helps keep those bones as close as possible to the animation without it being too stiff.

The whole body is affected by the player's shot. Additional logic could be added to cause the affected pawn to trip and fall if desired (Blend into another animation, blend out physics, after some times blend in physics again to simulate the fall).

RealismHitReactionShot.jpg

Death animations that blend into a rag doll

Rather than instantly rag dolling upon death, it may be desired for a short animation to play first. When the animation ends, the rag doll then blends in.

The properties of HitReactionPawn to achieve this are:

AnimatedRagdoll.jpg

Unrealscript logic flow:

  • TakeDamage is called when the player shoots the HitReactionPawn
  • Check if there is a valid skeletal mesh component, physical asset instance and if the script is not currently in the middle of simulating physics
  • FullBodyRagdoll is false and DeathAnimName is not empty.
  • Play the death animation and ensure that the anim node sequence that is playing it will call OnAnimEnd when the animation finishes.
  • When OnAnimEnd is called, enable physics. For best results, do not set a blend in time otherwise the death sequence can be odd!
    • Unfix bodies defined in UnfixedBodyNames. If that is empty, it will unfix all bodies.
    • Enable bone springs is defined in EnabledSpringBodyNames, and set the strengths of them using LinearBoneSpringStrength and AngularBoneSpringStrength.
    • Bones no longer need to be updated via the animation, bUpdateKinematicBonesFromAnimation is set false.
  • Blend In timer is set.
  • When blend in timer is called, it will call the physics stay timer.
  • When physics stay timer is called, it will call the blend out timer.
  • After blending out, the process above is reversed.
  • If the blend in timer is running, or the blend out timer is running, tick blends between animation and physics by adjusting the PhysicsWeight by finding the percentage of time passed with the timers.

This allows animators to create animated sequences which handle the initial fall, so that it feels like the body is reacting to the fall as well. In this case, there is a special animation played back when the body is continuously hit by the Stinger weapon in Unreal Tournament 3. Rag doll simulation begins at the end of the animation.

AnimatedRagdollShot.jpg

Downloads


  • Download the content used in this document. Please compile the UDN package before loading PhysicalAnimationBMap.udk.