找回密码
 立即注册
查看: 373|回复: 0

UE5中如何优化动画?

[复制链接]
发表于 2022-8-9 08:08 | 显示全部楼层 |阅读模式
在构建动画时,您应该牢记一些做法,以确保项目中的动画尽可能顺利地运行。其中一些是默认启用的,而另一些则需要您考虑设置动画蓝图时采用的方法。其他工作可以通过 C++ 执行,这也将授予您对动画更新方式和时间的一些控制,从而提高性能。
多线程动画更新

这允许更多动画工作在工作线程中运行,并且默认启用,您可以在项目设置中找到:

  • 在General Settings > Anim Blueprints下的Project Settings中,确保启用 Allow Multi Threaded Animation Update


这控制默认情况下我们是否允许在非游戏线程上执行动画蓝图图表更新。这也启用了动画蓝图编译器中的一些额外检查,当尝试不安全操作时会发出警告。在您的动画蓝图中,您还需要确保将其设置为使用多线程动画更新

  • Class Settings下的 Animation Blueprint 中,确保启用 Use Multi Threaded Animation Update 。


这背后的主要驱动力是更紧密地控制跨线程的数据访问。为此,许多动画图访问的数据已从UAnimInstance名为FAnimInstanceProxy. 这个代理结构是找到大量数据UAnimInstance的地方。
通常,UAnimInstance不应从 AnimGraph 节点(更新/评估调用)中访问或改变 ,因为这些可以在其他线程上运行。有一些锁定包装器 (GetProxyOnAnyThreadGetProxyOnGameThread) 可以防止访问执行中的FAnimInstanceProxy任务。这个想法是,在最坏的情况下,任务等待完成,然后才允许在代理中读取或写入数据。
从 Anim Graph 的角度来看,只有FAnimInstanceProxy可以从动画节点访问,而不是UAnimInstance. 必须在 或 中与代理交换数据(通过缓冲、复制或其他策略FAnimInstanceProxy::PreUpdateFAnimInstaceProxy::PreEvaluateAnimation。任何需要被外部对象访问的数据都应该从FAnimInstanceProxy::PostUpdate.
UAnimInstance这与在执行任务时可以从其他类访问成员变量的一般用例相冲突。作为建议,尽量不要从其他类直接访问 Anim Instance。相反,动画实例应该从其他地方提取数据。
示例自定义原生 AnimInstance

下面的代码块是一个示例,说明如何使用 new 构建自定义原生 AnimInstance 类FAnimInstanceProxy,授予对内部工作的访问权限并避免在代理和实例之间复制共享数据:
USTRUCT()

struct FExampleAnimInstanceProxy : public FAnimInstanceProxy

{

    GENERATED_BODY()

    FExampleAnimInstanceProxy()

    : FAnimInstanceProxy()

    {}

    FExampleAnimInstanceProxy(UAnimInstance* Instance);

    virtual void Update(float DeltaSeconds) override

    {

        // Update internal variables

        MovementAngle += 1.0f * DeltaSeconds;

        HorizontalSpeed = FMath::Max(0.0f, HorizontalSpeed - DeltaSeconds);

    }

public:

    UPROPERTY(Transient, BlueprintReadWrite, EditAnywhere, Category = "Example")

    float MovementAngle;

    UPROPERTY(Transient, BlueprintReadWrite, EditAnywhere, Category = "Example")

    float HorizontalSpeed;

};

UCLASS(Transient, Blueprintable)

class UExampleAnimInstance : public UAnimInstance

{

     GENERATED_UCLASS_BODY()

private:

    // The AllowPrivateAccess meta flag will allow this to be exposed to Blueprint,

    // but only to graphs internal to this class.

    UPROPERTY(Transient, BlueprintReadOnly, Category = "Example", meta = (AllowPrivateAccess = "true"))

    FExampleAnimInstanceProxy Proxy;

    virtual FAnimInstanceProxy* CreateAnimInstanceProxy() override

    {

        // override this to just return the proxy on this instance

        return &Proxy;

    }

    virtual void DestroyAnimInstanceProxy(FAnimInstanceProxy* InProxy) override

    {

    }

    friend struct FExampleAnimInstanceProxy;

};动画快速路径

Animation Fast Path提供了一种优化AnimGraph更新内部变量访问的方法。这使引擎能够在内部复制参数,而不是执行蓝图代码(这涉及调用蓝图虚拟机)。编译器当前可以优化以下结构:成员变量否定布尔成员变量和嵌套结构的成员。
默认情况下,在Project Settings中启用 Animation Fast Path 选项:

  • 在General SettingsAnim Blueprints下的Project Settings中,确保启用 Optimize Anim Blueprint Member Variable Access 。


要使用动画路径路径,请确保在动画蓝图的 AnimGraph 中未执行任何蓝图逻辑。在下图中,我们正在读取几个浮点值,这些值用于驱动多个混合空间资产和一个混合,从而产生我们的最终动画姿势。右上角用闪电图标表示的每个节点都在使用快速路径,因为没有执行任何逻辑。


如果我们要更改此网络以包含任何形式的计算,例如下图所示的示例,则关联节点将不再使用快速路径。


上面,由于我们现在正在执行蓝图逻辑来生成馈送TEST_Blend2D节点的值,它不再使用快速路径(并且照明图标将被移除)。
快速路径方法

为了让您的动画蓝图使用快速路径,请确保它们:
直接访问成员变量
下面我们通过直接访问和读取布尔变量的值来使用快速路径来确定我们的姿势。


在下一个示例中,我们没有使用快速路径,因为我们正在执行逻辑来确定布尔变量是否等于 true。


访问否定的布尔成员变量
下面我们通过读取取反的布尔值来使用快速路径来确定我们的姿势。


在下一个示例中,我们没有使用快速路径,因为我们正在执行逻辑来确定布尔变量是否不等于 true。


访问嵌套结构的成员
下面我们打破我们的 rotator 变量来直接访问我们的 Pitch 和 Yaw 变量来提供我们的 Aim Offset。


使用“Break Struct”节点访问成员
下面我们使用 Break Struct 节点将我们的 rotator 变量分解为 XYZ 值,以提供我们的 Aim Offset。


一些Break Struct节点(如Break Transform)目前不会使用 Fast Path,因为它们在内部执行转换,而不是简单地复制数据。
警告蓝图使用

为确保您的动画蓝图使用快速路径,您可以启用警告蓝图使用选项,这将导致编译器在从 AnimGraph 调用蓝图虚拟机时向编译器结果日志发出警告。

  • 要启用关于蓝图使用的警告,请在优化下启用动画蓝图的类设置中的选项。


当编译器识别出任何未使用快速路径的节点时,它们将显示在编译器结果日志中。


上面,由于我们在 AnimGraph 中执行蓝图逻辑并启用了警告选项,因此我们会在编译器结果中收到一条警告消息,并且可以单击它以将我们带到有问题的节点。这可以帮助跟踪需要进行的优化,并使您能够识别可能是问题根源的节点。
一般提示

当您开始考虑动画使用的性能时,以下是您在执行优化时可能需要遵循的一些准则。
根据项目的规模和范围,可能需要进行更具侵入性的更改,但这通常是一个不错的起点。

  • 确保满足并行更新的条件

    • 在UAnimInstance::NeedsImmediateUpdate您可以看到所有必须满足的条件才能避免在游戏线程上运行的动画更新阶段。如果角色移动需要根动作,则无法执行并行更新,因为角色移动不是多线程的。



  • 避免调用蓝图虚拟机

    • 考虑将蓝图原生化为 C++ 代码。
    • 将动画蓝图中的事件图表保持为空。使用自定义UAnimInstance和FAnimInstanceProxy派生类并在代理中完成所有工作,FAnimInstanceProxy::Update或者FAnimInstanceProxy::Evaluate在工作线程上执行这些工作。
    • 确保动画蓝图的Anim Graph中的节点以它们使用Fast Path的方式构造。
    • 确保在Project Settings中启用Optimize Anim Blueprint Member Variable Access ,因为这将控制直接访问其类的成员变量的 Animation Blueprint 节点是否应使用优化的路径以避免蓝图 VM 的 thunk。
    • 通常,AnimGraph 执行中成本最高的部分是避免调用虚拟机是从动画蓝图获得最大性能的关键。



  • 使用更新率优化 (URO)

    • 这将防止您的动画过于频繁地滴答作响。控制如何应用它取决于您的游戏,但我们建议在许多角色的适当距离处移动到 ~15Hz 和低于更新率,并禁用插值。
    • 要启用,请将您的骨架网格体组件设置为启用更新率优化并参考AnimUpdateRateTick()。

      • 或者,您还可以启用Display Debug Update Rate Optimizations以启用正在应用的 URO 的屏幕调试。


  • 启用组件使用固定骨架边界

    • 在您的骨架网格体组件中,启用组件使用骨架边界选项。
    • 这将跳过使用物理资源,而是始终使用骨架网格体中定义的固定边界。
    • 这也将跳过为每帧剔除重新计算边界体积,从而提高性能。

其他注意事项

分析您的项目时,您可能会看到FParallelAnimationCompletionTask在工作线程完成后,它正在主线程上为骨架网格体运行。一旦满足并行更新的条件,这将是您将在配置文件中看到的大部分主线程工作,并且通常包括几件事,具体取决于您的设置:

  • 移动你的组件,例如更新骨骼的物理对象。

    • 尝试避免为实际上不需要的东西更新物理,因为这将是减少这种情况的关键。

  • 触发动画通知。

    • 这些应该是非蓝图,再次避免调用蓝图 VM 以提高效率。
    • 这些也需要在游戏线程上执行,因为它们会影响动画对象的生命周期。

  • 如果启用了 URO,则进行动画插值。
  • 如果正在使用材质或变形目标曲线,则混合曲线。
重要提示:

Unreal软件电脑配置的要求是比较高,特别是实时渲染,前期的硬件成本是比较高的,目前有云端解决方案,使用呆猫云桌面,即使本地普通的电脑也能运行Unreal软件,且普通电脑也能享受行业最高端的CPU和GPU,极大提高制作效率和使用体验,且使用方便快捷,全面支持3D应用软件插件运行,随时调用百余款软件插件,高效作业。
呆猫云桌面在科学计算、渲染、游戏、办公等应用场景下的表现自不必说,玩大型游戏更是小菜一碟,拥有呆猫相当于把超级电脑放进口袋,随时随地都可畅享高配,可以满足移动办公、人工智能、三维建模、视觉设计、影视制作、教育培训、动画渲染、娱乐畅玩等多场景应用。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-6-16 22:00 , Processed in 0.090340 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表