The Animation Budget Allocator is a plugin, you can use in Unreal Engine, to constrain the computation time allotted for animation data running on specified skeletal meshes. You can use the Animation Budget allocator to reduce the cost of many animating characters, by setting a processing budget, that the Budget Allocator will dynamically throttle Skeletal Mesh Component animation ticking. By setting a fixed CPU budget for animation data, you can maximizing perceived animation quality with minimal system overhead when animating many characters at once.
The Animation Budget Allocator determines a fixed budget, that can be adjusted on a per-platform basis, in milliseconds of work to perform on the game thread. The Budget Allocator then determines if it can update all necessary animation updates, or if optimiziation are needed. If optimizations are required, the Budget Allocator determines the Significance of the requested updates, and identifies targets, based on several criteria, with the goal of dynamically adjusting the load to fit within the fixed game thread budget.
The following are targeted areas the Budget Allocator makes optimizations to reduce the performance load:
-
Stop ticking on individual skeletal mesh components, and favors any present Leader Pose Component.
-
Performs animation updates at a lower rate.
-
Chooses whether or not to Interpolate between updates.
Prerequisites
-
Enable the Animation Budget Allocator Plugin. Navigate in the Menu Bar to Edit > Plugins and locate the Animation Budget Allocator, listed under the Animation section, or by using the Search Bar. Enable the Plugin and restart the editor.
-
A Skeletal Mesh character with a character blueprint.
-
An animation to play on the character.
Set Up the Animation Budget Allocator
In order to take advantage of the Animation Blueprint Allocator, you must set the character blueprint's mesh component's Component Class to use the SkeletalMeshComponentBudgeted class.
To set the character's component class, navigate in the character's blueprint to the Components panel and select the Mesh component to open the Details panel. Set the Component Class property to the SkeletalMeshComponentBudgeted option from the drop-down menu.
Alternativly, you can also add the following C++ code to your ACharacter
subclass constructor:
: Super(ObjectInitializer.SetDefaultSubobjectClass<USkeletalMeshComponentBudgeted>(ACharacter::MeshComponentName))
In the Budgeting section enable Auto Calculate Significance and ensure Auto Register with Budget Allocator is enabled.
Create and connect the Enable Animation Budget node to the Event Begin Play node in the Character's Blueprint Event Graph, and check the Enabled property.
You can now add the character blueprint to the level, by dragging the asset from the Content Browser into the level viewport, or by spawning the character using blueprints. The Budget Allocator will be enabled by default when beginning the simulation. You can observe the processing load, using the graph that is rendered over the scene in the viewport.
Both the Enable Animation Blueprint Budget node and the feature must be enabled for the budget allocator to operate. By default the feature is enabled, but can be toggled using the a.Budget.Enabled
console command during simulation. You can enter a console command using the backtik (`) key, and input the command in the field.
You can toggle the Animation Budget Allocator's debug overlay, to observe its operations in real-time during your project's simulation with the a.Budget.Debug.Enabled
console command.
Using the Animation Budget Allocator
The Animation Budget Allocator impliments optimizations to being the total animation processing load within the budget, while retaining the maximize animation quality that the system can produce. It will favor the closest, most significant meshes, running their animations at the highest framerate it can while reducing the framerate and quality of less significant meshes.
The Animation Budget Allocator's debug graph observes the project's processing load, along the y-axis, over time, along the graph's x-axis, and updates in real-time. The project's budget for the total animation system is rendered as the dotted line and is labeled Budget, along the right side of the graph.
The solid line represents the Performance of the animation system at the individual moments along the graphs observed time.
The performance will vary based on the amount of work that needs to be done, when factoring in the Animation Budget Allocator's chosen optimizations.
You can view additional information about the processes of the Budget Allocator by enabling the stat overlay. To enable the stat overlay, navigate in the viewport menu to Stat > Advanced and toggle the AnimationBudgetAllocator option.
You can now view additional information when beginning the project simulation.
Here you can reference a list of the information present the Animation Budget Allocator's stat overlay:
Statistic | Description |
---|---|
Initial Tick | You can use the Initial Tick to observe the initial tick stats when the budget allocator is activated. Using this category you can observe the initial tick's Inclusive Average, Inclusive Max, Exclusive Average and Exclusive Max times in milliseconds (ms). |
Demand | Here you can observe the demand the Budget Allocator is being operated with. You can observe the Average, Maximum (Max) and Minimum (Min) number of objects that the Budget Allocator is processing. |
Num Registered Components | Here you can observe the number of registered skeletal mesh components the Budget Allocator is processing, including the multiple skeletal mesh components that comprise modular characters. You can observe the Average, Maximum (Max) and Minimum (Min) number of skeletal mesh objects. |
Throttled | Here you can observe the number of throttled skeletal mesh objects the Budget Allocator is optimizing. You can observe the Average, Maximum (Max) and Minimum (Min) number of skeletal mesh objects. |
Num Ticked Components | Here you can observe the number of skeletal mesh objects the Budget Allocator is optimizing per tick. You can observe the Average, Maximum (Max) and Minimum (Min) number of skeletal mesh objects. |
Budget | Here you can observe the number of skeletal mesh objects the Budget Allocator is able to optimize per tick. You can observe the Average, Maximum (Max) and Minimum (Min) number of skeletal mesh objects. |
Interpolated | Here you can observe the number of skeletal mesh objects the Budget Allocator is choosing to interpolate rather than render actual animation frames. You can observe the Average, Maximum (Max) and Minimum (Min) number of skeletal mesh objects. |
SmoothedBudgetPressure | Here you can observe the Budget Allocator's smoothing budget pressure, or the amount of pressure to choose interpolation over animation frame selection. |
Always Tick | Here you can observe the Always Tick's status, and fall off times. Always Tick bypasses the budget allocators processing to allow the mesh to always update its animation data. |
Average Work Units (ms) | Here you can observe the time each process cycle takes to complete in milliseconds (ms). You can observe the Average, Maximum (Max) and Minimum (Min) clock times. |
Each Skeletal Meshes that is being optimized with the Animation Budget Allocator will be rendered with a unique overlay containing debug information.
The number value indicates the rate at which the mesh is being updated. A value of one means that the mesh is being updated and ticking every frame. A value of five would mean that the mesh is updated and tick every five frames.
The other present information indicates at what fidelity the animation data is being processed. The following are the options the Animation Budget Allocator will process animation data:
- Hi (high detail) - the Skeletal Mesh components and running more expensive logic.
- Lo (low detail) - that expensive logic (such as extra character parts or more expensive work that can be skipped at a distance) is not running.
- I (interpolating) - the Skeletal Mesh is interpolating between frames.
When using Modular Characters, you can view individual groups of debug information for each skeletal mesh component that comprises the modular character.
Platform Scaling
When developing Unreal Engine projects for multiple platforms, you can control the Animation Budget Allocator's settings on a per-platform basis.
In most cases, it is recommended to set the cvar
inputs to the system from the scalability settings for the specific platforms that you are targeting.
For example, you can add a DefaultScalability.ini
file to set the budget for the Animation Budget Allocator's target budget, based on the View Distance Quality setting:
[ViewDistanceQuality@0]
a.Budget.BudgetMs=1.0
[ViewDistanceQuality@1]
a.Budget.BudgetMs=1.5
[ViewDistanceQuality@2]
a.Budget.BudgetMs=2.0
[ViewDistanceQuality@3]
a.Budget.BudgetMs=2.5
You can then override these values within the platform specific scalability settings.
For more information about creating profiles for specific platforms see the Customizing Device Profiles and Scalability for Android for an example of building a profile for android devices.
Animation Budget Allocator C++ API
You can access the C++ files for Animation Budget Allocator within your project Engine
installation folder under:
Engine\Plugins\Runtime\AnimationBudgetAllocator\Source\AnimationBudgetAllocator\Public\
Here you can reference the IAnimationBudgetAllocator.h
file:
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
#pragma once
class USkeletalMeshComponentBudgeted;
class UWorld;
struct FAnimationBudgetAllocatorParameters;
/**
* Dynamically manages skeletal mesh component tick rates to try to maintain a specified budget.
*/
class IAnimationBudgetAllocator
{
public:
/** Get the budgeter for the specified world */
static ANIMATIONBUDGETALLOCATOR_API IAnimationBudgetAllocator* Get(UWorld* InWorld);
/**
* Register a component with the budgeter system. If the component is already registered this function does nothing.
* Once this is called:
* - Default tick function will be disabled
* - URO will be disabled
* - Parallel anim tasks will be re-routed to the budgeter
*/
virtual void RegisterComponent(USkeletalMeshComponentBudgeted* InComponent) = 0;
/**
* Unregister a component from the budgeter system. If the component is not registered this function does nothing.
* Once this is called:
* - Default tick function will be re-enabled
* - URO will be re-enabled
* - Parallel anim tasks will be re-routed back to internal functions
*/
virtual void UnregisterComponent(USkeletalMeshComponentBudgeted* InComponent) = 0;
/**
* Update the prerequisites of this component. Should be called when prerequisites may have changed externally.
*/
virtual void UpdateComponentTickPrerequsites(USkeletalMeshComponentBudgeted* InComponent) = 0;
/**
* Set the significance and other flags for the specified component.
* This information is used to dynamically control the tick rate of the component.
*/
virtual void SetComponentSignificance(USkeletalMeshComponentBudgeted* Component, float Significance, bool bNeverSkip = false, bool bTickEvenIfNotRendered = false, bool bAllowReducedWork = true, bool bForceInterpolate = false) = 0;
/** Set the specified component to tick or not. If the budgeter is disabled then this calls Component->SetComponentTickEnabled(bShouldTick). */
virtual void SetComponentTickEnabled(USkeletalMeshComponentBudgeted* Component, bool bShouldTick) = 0;
/** Get whether the specified component is set to tick or not */
virtual bool IsComponentTickEnabled(USkeletalMeshComponentBudgeted* Component) const = 0;
/** Inform that we reduced work for a component */
virtual void SetIsRunningReducedWork(USkeletalMeshComponentBudgeted* Component, bool bInReducedWork) = 0;
/** Set the tick time */
virtual void SetGameThreadLastTickTimeMs(int32 InManagerHandle, float InGameThreadLastTickTimeMs) = 0;
/** Set the completion task time */
virtual void SetGameThreadLastCompletionTimeMs(int32 InManagerHandle, float InGameThreadLastCompletionTimeMs) = 0;
/** Tick the system per-frame */
virtual void Update(float DeltaSeconds) = 0;
/** Set whether this budget allocator is enabled */
virtual void SetEnabled(bool bInEnabled) = 0;
/** Get whether this budget allocator is enabled */
virtual bool GetEnabled() const = 0;
/** Set the various parameters */
virtual void SetParameters(const FAnimationBudgetAllocatorParameters& InParameters) = 0;
};
Additional Console Commands
Here you can reference a list of the available console commands you can use when working with the Animation Budget Allocator, and a description of their functionality:
| Command | Values | Description | | --- | --- | --- | |a.Budget.AlwaysTickFalloffAggression
| Range [0.1, 0.9], Default = 0.8 | Controls the rate at which `always ticked' components fall off under load. Higher values mean that we reduce the number of always ticking components by a larger amount when the allocated time budget is exceeded. |
a.Budget.BudgetFactorBeforeAggressiveReducedWork |
Range > 1, Default = 2.0 | Reduced work will be applied more rapidly when budget pressure goes over this amount. |
a.Budget.BudgetFactorBeforeReduceWork |
Range > 1, Default = 1.5 | Reduced work will be delayed until budget pressure goes over this amount. |
a.Budget.BudgetFactorBeforeReducedWorkEpsilon |
Range > 0.0, Default = 0.25 | Increased work will be delayed until budget pressure goes under a.Budget.BudgetFactorBeforeReducedWork 's value minus this command's value. |
a.Budget.BudgetMs |
Values > 0.1, Default = 1.0 | The time in milliseconds that we allocate for Skeletal Mesh work to be performed. When over budget, various other console variables come into play, such as a.Budget.AlwaysTickFalloffAggression and a.Budget.InterpolationFalloffAggression . |
a.Budget.BudgetPressureSmoothingSpeed |
Range > 0.0, Default = 3.0 | How much to smooth the budget pressure value that is used to throttle reduced work. |
a.Budget.Debug.Enabled |
Values: 0/1 | Controls whether to render the Animation Budget Allocator's debug graph in the viewport, in builds that it is supported. |
a.Budget.Debug.Force |
Values: 0/1 | Enables overriding the budget settings on all meshes to specific values. |
a.Budget.Debug.Force.Interp |
Values: 0/1 | Toggle interpolation, when a.Budget.Debug.Force is enabled. A value of 1 will enable interpolation, and a value of 0 will disable interpolation. |
a.Budget.Debug.Force.Rate |
Values: > 0 | Overides the number of frames per animation tick, when a.Budget.Debug.Force is enabled. For example, a vaule of 5 means animations will be updated once every 5 frames. |
a.Budget.BudgetMs |
Values: > 0.0 | Lowers the threshold for the budgeter to take effect on your animation system, when a.Budget.Debug.Force is enabled. For example, a value of 0.1 will greatly reduce the threshold of when the budgeter will take effect. |
a.Budget.Debug.ShowAddresses |
Values: 0/1 | Controls whether the debug render also displays addresses of component data. |
a.Budget.Enabled |
Values: 0/1 | Controls whether the Skeletal Mesh batching system is enabled. Should be set when there are no running Skeletal Meshes. |
a.Budget.GBudgetPressureBeforeEmergencyReducedWork |
Range: > 0.0, Default = 2.5 | Controls the budget pressure where emergency reduced work (applied to all components except those that are bAlwaysTick). |
a.Budget.InitialEstimatedWorkUnitTime |
Values: > 0.0, Default = 0.08 | Controls the time in milliseconds we expect, on average, for a Skeletal Mesh component to execute.The value only applies for the first tick of a component, after which we use the real time the tick takes. |
a.Budget.InterpolationFalloffAggression |
Range [0.1, 0.9], Default = 0.4 | Controls the rate at which interpolated components falloff under load. Higher values mean that we reduce the number of interpolated components by a larger amount when the allocated time budget is exceeded. Components are only interpolated when the time budget is exceeded. |
a.Budget.InterpolationMaxRate |
Values > 1, Default = 6 | Controls the rate at which ticks happen when interpolating. |
a.Budget.InterpolationTickMultiplier |
Range [0.1, 0.9], Default = 0.75 | Controls the expected value an amortized interpolated tick will take compared to a 'normal' tick. |
a.Budget.MaxInterpolatedComponents |
Range >= 0, Default = 16 | Max number of components to interpolate before we start throttling. |
a.Budget.MaxTickedOffsreen |
Values >= 1, Default = 4 | The maximum number of off screen components we tick (most significant first). |
a.Budget.MaxTickRate |
Values >= 1, Default = 10 | The maximum tick rate we allow. If this is set then we can potentially go over budget but keep the quality of individual meshes to a reasonable level. |
a.Budget.MinQuality |
Values [0.0, 1.0], Default = 0.0 | The minimum quality metric allowed. Quality is determined simply by NumComponentsTickingThisFrame / NumComponentsThatWeNeedToTick. If this is anything other than 0.0 then we can potentially go over our time budget. |
a.Budget.ReducedWorkThrottleMaxInFrames |
Range [1, 255], Default = 20 | Prevents reduced work from changing too often due to system and load noise. Max value used when under budget pressure. |
a.Budget.ReducedWorkThrottleMaxPerFrame |
Range [1, 255], Default = 4 | Controls the max number of components that are switched to/from reduced work per tick. |
a.Budget.ReducedWorkThrottleMinInFrames |
Range [1, 255], Default = 2 | Prevents reduced work from changing too often due to system and load noise. Min value used when over budget pressure (for example: aggressive reduction). |
a.Budget.StateChangeThrottleInFrames |
Range [1, 128], Default = 30 | Prevents throttle values from changing too often due to system and load noise. |
a.Budget.WorkUnitSmoothingSpeed |
Values > 0.1, Default = 5.0 | The speed at which the average work unit converges on the measured amount. |