Animating

[WIP] Animating and Animating Techniques (such as retargeting)

Basics

Inverse Kinematics

To be able to animate using inverse kinematics, you have to set it up first. Luckily doing so is fairly straight-forward:

  1. Create an articulated actor in your scene
  2. Expand the bone list actor > Components > animated > bone in the actor editor
    bone_list.png
  3. Right-click the bone for which you want to add an IK chain. This bone will be the effector. Now choose Add IK Control > <ParentBone> from the menu. An IK chain will be created, which will include the <ParentBone>, the effector and all of the bones in-between in the hierarchy.
  4. Scroll down to the bottom of the Components list and you should find a new entry called pfm_ik. Here you will find all of the effectors you've added:
    pfm_ik_effectors.png
  5. Use the viewport transform modes to move the effector position and you should see the IK in action.

The IK configuration data is model-dependent and project-independent. If you use the model of the actor that you've added a IK chain for in another project (or the same one), the pfm_ik component of the new actor should already list all of the IK chains you have created for the model previously, i.e. you only have to create them once per model.

The IK system currently does not support limits. This means that, for instance, an arm can bend in ways that wouldn't be possible in real life.

Expressions and Drivers

This article refers to PFM v0.4.3 and newer and may not be representative of older versions.

Math Expressions

Any animatable actor property (color, radius, position, etc.) can be animated with a math expression (Similar to SFM's expression operators). The implementation is based on the high-performance exprtk library, which includes support for:

Examples

As a basic example, let's say you want to animate the position of your actor, so you move it to [0,30,0] at timestamp 0, [0,50,20] at timestamp 1 and [30,0,-20] at timestamp 2. You can then apply the math expression value *2 to the property, which will double the values, meaning your actor will move from [0,60,0] to [0,100,40] and then to [60,0,-40] instead.

Here are some other basic examples:

Inputs

These are the variables available for use with math expressions:

Constants:

Base Functions
Quaternion Functions

Contrary to SFM's expression operators, PFM's math expressions cannot reference anything outside of the animation channel for the property it's assigned to. To create dependencies between properties, you need to use animation drivers instead.

 

Animation Drivers

Animation drivers are similar to math expressions, with a few key differences:

Since animation drivers are Lua-based, that means you have the entire Lua API available, making them much more powerful tools compared to math expressions. Their purpose is to animate a property programmatically with dependencies to other properties. To do so, animation drivers can have input variables, which can be references to actors, components or component properties.

Examples

Animation drivers cannot be created through PFM yet, so the following are Lua-based examples. These may seem a little daunting, but once the system is integrated into the interface, drivers will be much easier to use.

local actorId = "327b5bb8-74ae-400e-bbf7-61a2ad2020d3" -- Id of the actor for whom we check the distance
local expr = [[
	local dist = trLight:GetDistance(trActor)
	return Color.Red:Lerp(Color.Lime,math.clamp((dist -120) /150.0,0.0,1.0)):ToVector()
]]
lightSource:AddDriver(
	ents.COMPONENT_COLOR,"color",
	game.ValueDriverDescriptor(expr,{
    	-- 'trActor' variable referencing the transform component of the actor
    	["trActor"] = "pragma:game/entity/ec/transform?entity_uuid=" .. actorId,
    	
    	-- 'trLight' variable referencing the transform component of the light
    	["trLight"] = "pragma:game/entity/ec/transform"
    })
)

pfm_animation_driver_1.gif

local camId = "6f964743-faa6-4b2b-b781-41a258e2f7d1" -- Id of the camera actor
local expr = [[
	local angToCamera = self:GetAngles(trCam)
	return EulerAngles(0,angToCamera.y,0)
]]
actor:AddDriver(
	ents.COMPONENT_TRANSFORM,"angles",
	game.ValueDriverDescriptor(expr,{
    	-- 'trCam' variable referencing the transform component of the camera actor
    	["trCam"] = "pragma:game/entity/ec/transform?entity_uuid=" .. camId
    })
)

pfm_animation_driver_2.gif

 

 

Retargeting