如何实现追踪源过滤

学习如何实现追踪源过滤以优化Animation Insights追踪。

Choose your operating system:

Windows

macOS

Linux

前置主题

为了能够理解并使用此页面中的内容,请确保您已掌握以下主题:

在本指南中,你将通过实现两个范例来学习如何将追踪源过滤用于项目。 例如,在实现第二用例后,追踪源过滤系统可以在你的玩家Pawn的光线投射命中站立的Actor时过滤Actor(如以下视频所示)。

Notice how Actors filter in

必要的设置

在本指南中,我们将使用 游戏 > 第三人称模板 项目,并启用 C++ 无初学者内容包(No Starter Content) 设置, 动画初学者包(Animation Starter Pack) (可在 Epic Games商城 中获取)。

  1. 添加一个站立和一个蹲伏骨骼网格体Actor到场景中。

    在右侧使用Equip_Rifle_Standing,在左侧使用Crouch_Idle_Rifle_Ironsights。

  2. 选择并用"Standing"Actor标签标记站立骨骼网格体Actor。

  3. 重复上一步骤,并标记蹲伏骨骼网格体Actor。

    HT_ReqSetup_2.png

追踪源过滤

概述

在大型项目上使用Animation Insights时,务必限制应用程序的开销和硬盘空间用量。在以下范例中,Animation Insights将输出场景中所有Actor的追踪数据。

如该项目发展为包含上千对象,将会难以发现性能问题。

若要减少Animation Insights追踪数据,可使用追踪源过滤来选择哪些gameplay对象可以输出追踪数据。执行以下步骤即可启用追踪源过滤:

  1. Animation Insights 中,选择 菜单(Menu)>(过滤)追踪源过滤((Filtering) Trace Source Filtering)

    HT_TraceSourceFiltering_1.png

  2. 追踪源过滤(Trace Source Filtering) 中,启用选项(Options)> 可视化(Visualize)> Actor过滤(Actor Filtering)

    HT_TraceSourceFiltering_2.png

  3. 要验证在编辑器中运行的追踪源过滤,可在激活关卡编辑器视口(PIE会话)中运行关卡。你将看到以下内容:

    追踪源将渲染此场景中所有Actor周围的盒体。

  4. 要实现追踪源过滤器,启用选项(Options)> 可视化(Visualize)> 仅通过过滤的Actor(Only Actor(s) passing Filtering)

    HT_TraceSourceFiltering_3.png

如果在PIE会话中运行关卡,并同时启用Actor过滤(Actor Filtering)和仅通过过滤的Actor(Only Actor(s) passing Filtering),则由于尚未实现过滤器,追踪源过滤功能将显示场景中所有Actor。

HT_TraceSourceFiltering_EndResult.png

已启用追踪源过滤的Animation Insights

启用追踪源过滤后,你可以实现部分过滤器以限制Animation Insights将输出的追踪数据量。本指南的剩余章节将展示部分范例,包括各用例的蓝图和C++(原生)过滤器实现。

用例1

假定我们要实现位于玩家Pawn位置的指定距离内的已标记Actor过滤器。根据此用例,我们将实现以下过滤器:

实现类型

过滤器命名

用法

蓝图

HasTag

过滤具有已定义Actor标签的Actor。

原生

DistanceToPlayer

过滤玩家Pawn位置的指定距离内的Actor。将默认距离定义为300虚幻单位(cm)。

实现过滤器后,我们将组合它们,以便在已标记的Actor位于玩家Pawn的指定距离内时滤入Actor,Animation Insights可以记录其的追踪数据。在本章最后,还应确保过滤器满足用例要求,将过滤器逻辑如下设置:

过滤器逻辑

返回true

返回false

DistanceToPlayer AND HasTag

滤入Actor

滤出Actor

定义过滤器逻辑时,建议将需求写成完整句子,因为这样可有助于在实现之前发现逻辑中的潜在缺陷。

HasTag蓝图过滤器

  1. 追踪源过滤(Trace Source Filtering) 中,选择 添加过滤器(Add Filter)>新建过滤器蓝图(Create new Filter Blueprint)

    HT_HasTagBPFilter_1.png

  2. 显示"资产另存为(Save Asset As)"菜单时,在"/Game/"中新建FilterBP文件夹。

    HT_HasTagBPFilter_2.png

  3. /Game/FilterBP/ 下,将资产另存为HasTag。

  4. 在HasTag蓝图编辑器(HasTag Blueprint)中,选择 函数(Functions)>(函数)重载((Function) Override)> Actor通过过滤器(Does Actor Pass Filter)

    HT_HasTagBPFilter_3.png

  5. 添加包含以下细节的新变量:

    • 变量命名: ActorTag

    • 变量类型: 字符串

    • 可编辑实例: 已启用

    • 提示文本: Actor标签命名

  6. 编译蓝图即可定义默认值。

  7. 在细节面板中,将默认值设为`ACTOR TAG`。

    HT_HasTagBPFilter_4.png

  8. 使用以下蓝图定义 Actor通过过滤器 功能。

    点击查看大图。

  9. 在"我的蓝图"面板上的"追踪源过滤"分类中,右键点击 获取工具提示文本(Get Tool Tip Text) 函数,然后选择 实现函数(Implement Function)

    HT_HasTagBPFilter_6.png

  10. 使用以下蓝图定义 获取工具提示文本(Get Tool Tip Text) 函数:

    点击查看大图。

    文本本地化

  11. 使用以下蓝图定义 获取显示文本(Get Display Text) 函数。

    点击查看大图。

  12. 编译、保存并关闭HashTag蓝图编辑器,以在过滤器区域查看HashTag蓝图过滤器。

    点击查看大图。

    添加过滤器(Add Filter)

  13. 点击HashTag过滤器,然后将ACTOR标签(ACTOR TAG)改为 Crouching 即可定义 Actor TAG

    HasTag过滤器

  14. 运行PIE会话即可验证是否已在必要设置(Required Setup)部分正确标记Actor。

    在PIE会话期间,被标记为蹲伏(左侧)的Actor将滤入。

    验证HashTag蓝图过滤器预期工作后,即可实现DistanceToPlayer原生过滤器。

    如HasTag未滤入Actor,则验证Actor标签命名是否与指定到Actor标签命名变量的命名相同。如命名相同,则检查蓝图中的bug。

DistanceToPlayer原生过滤器

  1. 将空C++类添加到项目,并命名为"DistanceToPlayer"。

  2. 在项目的`*.Build.cs`文件中,添加"SourceFilteringTrace"、"SourceFilteringCore"和"SourceFilteringEditor"公共依赖性模块命名:

    // 版权所有 1998-2019 Epic Games, Inc。保留所有权利。
    
    using UnrealBuildTool;
    
    public class TraceSourceFilterHT :ModuleRules
    {
        public TraceSourceFilterHT(ReadOnlyTargetRules Target) : base(Target)
        {
            PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
    
            PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "SourceFilteringTrace", "SourceFilteringCore", "SourceFilteringEditor" });
        }
    }
  3. 在 `DistanceToPlayer.h`中,添加以下代码:

    //在项目设置的描述页面中填写版权声明。
    
    #pragma once
    
    #include "DataSourceFilter.h"
    #include "DistanceToPlayer.generated.h"
    
    UCLASS(NotBlueprintable)
    class UDistanceToPlayer : public UDataSourceFilter
    {
        GENERATED_BODY()
            UDistanceToPlayer();
    public:
        UPROPERTY(Category = Filtering, EditAnywhere)
            float Distance;
    protected:
        virtual bool DoesActorPassFilter_Internal(const AActor* InActor) const override;
        virtual void GetDisplayText_Internal(FText& OutDisplayText) const override;
    };
  4. 在 `DistanceToPlayer.cpp`中,添加以下代码:

    //在项目设置的描述页面中填写版权声明。
    
    #include "DistanceToPlayer.h"
    #include "GameFramework/PlayerController.h"
    #include "GameFramework/Pawn.h"
    #include "Engine/World.h"
    
    #define LOCTEXT_NAMESPACE "UDistanceToPlayer"
    
    /**
    将初始距离设置为300虚幻单位(cm)。|
    */
    UDistanceToPlayer::UDistanceToPlayer() :Distance(300.0f)
    {
    }
    
    /**
    检查Actor和玩家Pawn间的距离。
    */
    bool UDistanceToPlayer::DoesActorPassFilter_Internal(const AActor* InActor) const
    {
        if (InActor)
        {
            UWorld* World = InActor->GetWorld();
            if (World)
            {
                if (APlayerController* Controller = World->GetFirstPlayerController())
                {
                    if (APawn* Pawn = Controller->GetPawn())
                    {
                        / **如Actor和玩家Pawn间的距离小于距离阈值,则返回true。*/
                        return Pawn->GetDistanceTo(InActor) < Distance;
                    }
                }
            }
        }
        return false;
    }
    
    /**
    玩家可自定义距离值。
    */
    void UDistanceToPlayer::GetDisplayText_Internal(FText& OutDisplayText) const
    {
        OutDisplayText = FText::Format(LOCTEXT("DisplayText", "Distance to Player Pawn < {0}"), { Distance });
    }
    #undef LOCTEXT_NAMESPACE // "UDistanceToPlayer"
  5. 添加过滤器(Add Filter) 下拉菜单中,编译代码以查看 DistanceToPlayer 过滤器。

    HT_DistanceToPlayerNativeFilter_1.png

  6. 选择 DistanceToPlayer 即可将新原生过滤器添加到过滤器区域。

  7. 右键点击"蹲伏(Crouching)"标签,然后选择 移除过滤器(Remove Filter) ,将过滤器区域中的HashTag蓝图过滤器移除。

    DistanceToPlayer过滤器

  8. 运行PIE会话即可验证DistanceToPlayer过滤器。

    滤入玩家Pawn过滤器300虚幻单位(cm)内的Actor。

验证DistanceToPlayer原生过滤器预期运行后,即可组合过滤器以满足用例要求。

实现用例1

首先回顾一下用例要求:

过滤器逻辑

返回False

返回True

DistanceToPlayer AND HasTag

滤入Actor

滤出Actor

执行以下步骤即可满足此要求:

  1. HasTag 过滤器添加到过滤器区域(Filter Area)。

  2. 将Actor标签命名变量设为`Standing`。

  3. 在过滤器区域中,将 HashTag 拖到 DistanceToPlayer 旁。

    拖动HasTag

  4. 距离(Distance) 变量默认值从300改为400。

    修改距离变量

    组成过滤器集时,可使用AND、OR和NOT逻辑运算符。右键点击逻辑运算符即可选择其他逻辑运算符。

    HT_DistanceToPlayerNativeFilter_4.png

  5. 运行PIE会话即可验证过滤器逻辑。

当玩家Pawn和标有站立Actor标签的Actor相聚在400cm内时,追踪源过滤系统将滤入该Actor。

观察玩家Pawn位于范围内时,Animation Insights(左下方面板)仅追踪Equip_Pistol_Standing - 混合权重(和图表)数据的方式。

用例2

我们假定需要在场景中移动时实现被玩家Pawn光线投射命中(或碰撞)的已标记骨骼网格体Actor的过滤器。根据此用例,我们将实现以下过滤器:

实现类型

过滤器命名

用法

蓝图

IsOfClass

滤入属于指定类的Actor。将默认类定义为骨骼网格体Actor。

原生

光线投射

滤入被玩家Pawn的光线投射命中的已标记Actor。将默认光线长度定义为400cm。

实现过滤器后,我们将组合它们,以便在已标记骨骼网格体Actor被玩家Pawn的光线投射命中时滤入Actor,Animation Insights可以记录其的追踪数据。在本章最后,还应确保过滤器满足用例要求,将过滤器逻辑如下设置:

过滤器逻辑

返回True

返回False

RaycastActor AND IsOfClass

滤入Actor

滤出Actor

IsOfClass蓝图过滤器

  1. 追踪源过滤(Trace Source Filtering) 对话框中,选择 添加过滤器(Add Filter) > 新建过滤器蓝图(Create new Filter Blueprint)

  2. /Game/FilterBP/ 下将资产另存为IsOfClass。

  3. 在IsOfClass蓝图(HasTag Blueprint)编辑器中,选择 函数(Functions)>(函数)重载((Function) Override)>Actor通过过滤器(Does Actor Pass Filter)

  4. 添加包含以下细节的新变量:

    • 变量命名 :**ActorClassRef

    • 变量类型: Actor类参考

    • 可编辑实例: 启用

    • 提示文本: Actor类参考

  5. 编译蓝图即可定义默认值。

  6. 将默认值定义为 SkeletalMeshActor

    HT_IsOfClassBP_1.png

  7. 使用以下蓝图定义Actor通过过滤器函数:

  8. 在"我的蓝图"面板中的"追踪源过滤"(Trace Source Filtering)分类中,右键点击 获取工具提示文本(Get Tool Tip Text) 函数,然后选择 实现函数(Implement Function)

  9. 使用以下蓝图定义 获取工具提示文本(Get Tool Tip Text) 函数。

  10. 使用以下蓝图定义 获取显示文本(Get Display Text) 函数。

  11. 编译、保存并关闭HashTag蓝图编辑器,以在过滤器区域查看IsOfClass蓝图过滤器。

  12. 运行PIE会话即可验证IsOfClass过滤器。

    Skeletal Mesh Actors filter in during PIE Session.

验证IsOfClass蓝图过滤器预期工作后,即可实现RaycastActor原生过滤器。

RaycastActor原生过滤器

  1. 将空C++类添加到项目,并命名为`RaycastActor`。

  2. 在`RaycastActor.h`中,添加以下代码:

    //在项目设置的描述页面中填写版权声明。
    
    #pragma once
    
    #include "DataSourceFilter.h"
    #include "RaycastActor.generated.h"
    
    UCLASS(NotBlueprintable)
    class URaycastActor : public UDataSourceFilter
    {
        GENERATED_BODY()
            URaycastActor();
    
    private:
        UPROPERTY(Category = Filtering, EditAnywhere)
            FName ActorTagName;
    
        UPROPERTY(Category = Filtering, EditAnywhere)
            float RayLength;
    
    protected:
        virtual bool DoesActorPassFilter_Internal(const AActor* InActor) const override;
        virtual void GetDisplayText_Internal(FText& OutDisplayText) const override;
    };
  3. 在`RaycastActor.cpp`中,添加以下代码:

    //在项目设置的描述页面中填写版权声明。
    
    #include "RaycastActor.h"
    #include "GameFramework/PlayerController.h"
    #include "GameFramework/Pawn.h"
    #include "Engine/World.h"
    #include "DrawDebugHelpers.h"
    
    #define LOCTEXT_NAMESPACE "URaycastActor"
    
    /**
    将初始距离设置为400虚幻单位(cm)。|
    */
    URaycastActor::URaycastActor() :ActorTagName("ADD ACTOR TAG"), RayLength(400.0f)
    {
    }
    
    /**
    从玩家Pawn处光线投射以命中已标记Actor。
    */
    bool URaycastActor::DoesActorPassFilter_Internal(const AActor* InActor) const
    {
        if (InActor)
        {
            UWorld* World = InActor->GetWorld();
            if (World)
            {
                if (APlayerController* Controller = World->GetFirstPlayerController())
                {
                    if (APawn* Pawn = Controller->GetPawn())
                    {
                        FHitResult* HitResult = new FHitResult();
                        FVector StartTrace = Pawn->GetActorLocation();
                        FVector ForwardVector = Pawn->GetActorForwardVector();
                        FVector EndTrace = (ForwardVector * RayLength) + StartTrace;
                        FCollisionQueryParams* CollisionQuery = new FCollisionQueryParams();
                        World->LineTraceSingleByChannel(*HitResult, StartTrace, EndTrace, ECC_Visibility, *CollisionQuery);
                        DrawDebugLine(World, StartTrace, EndTrace, FColor(0, 255, 0), false, 0.0f);
    
                        /**如玩家Pawn的光线命中已标记Actor,则返回true。*/
                        if (HitResult->GetActor() != NULL && HitResult->GetActor()->ActorHasTag(ActorTagName))
                        {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    
    /**
    玩家可自定义以下内容:
    * - 要查找的Actor标签命名
    * - 光线长度
    */
    void URaycastActor::GetDisplayText_Internal(FText& OutDisplayText) const
    {
        OutDisplayText = FText::Format(LOCTEXT("TraceSourceText", "Hit {0} Actor with Ray Length {1}"), FText::FromName(ActorTagName), RayLength);
    }
    #define LOCTEXT_NAMESPACE // "URaycastActor"
  4. 添加过滤器(Add Filter) 下拉菜单中,编译代码以查看RaycastActor过滤器。

    HT_RaycastActor_1.png

  5. 右键点击"为SkeletalMeshActor过滤器",然后选择 移除过滤器(Remove Filter) ,将过滤器区域中的IsOfClass蓝图过滤器移除。

  6. 选择 RaycastActor 即可将新原生过滤器(Native Filter)添加到过滤器区域(Filter Area)。

  7. 点击光线过滤器(Rayfilter),然后将 ADD ACTOR TAG 更改为 Standing 即可定义Actor标签命名。

    RaycastActor过滤器

  8. 运行PIE会话即可验证RaycastActor过滤器。

    站立Actor被玩家Pawn的光线投射命中时,所有Actor将滤入。

验证RaycastActor原生过滤器预期工作后,即可组合过滤器以满足用例要求。

实现用例2

首先回顾一下用例要求:

过滤器逻辑

返回True

返回False

RaycastActor AND IsOfClass

滤入Actor

滤出Actor

  1. 将IsOfClass过滤器添加至过滤器区域(Filter Area)。

  2. 在过滤器区域中,将IsOfClass拖到RaycastActor旁。

    拖动IsOfClass过滤器

  3. 运行PIE会话即可验证过滤器逻辑。

当玩家Pawn的光线投射命中标有站立Actor标签的Actor时,追踪源过滤系统将滤入骨骼网格体Actor。

观察玩家Pawn的光线投射命中站立Actor时,Animation Insights(左下方面板)仅追踪Equip_Pistol_Standing - 混合权重和Crouch_Idle_Rifle_Ironsights - 混合权重(和图表)数据的方式。

自行尝试!

通过对两个范例用例进行实现,你已学习了如何使用追踪源过滤。可思考利用其他哪些过滤器可便于Animation Insights仅追踪自己需要的Actor数据。

部分过滤器理念可能包括:

  • 发射物碰撞

  • 自动导向发射物碰撞

  • 按钮触发器

在实现过滤器时,请思考对过滤器进行逻辑组合的方式,以便过滤器滤入有助于优化和调试动画的Actor数据。虽然我们只使用了AND逻辑运算符,但不妨思考利用OR和NOT运算符来组合逻辑的方法。

欢迎帮助改进虚幻引擎文档!请告诉我们该如何更好地为您服务。
填写问卷调查
取消