Choose your operating system:
Windows
macOS
Linux
在本指南中,你将通过实现两个范例来学习如何将追踪源过滤用于项目。 例如,在实现第二用例后,追踪源过滤系统可以在你的玩家Pawn的光线投射命中站立的Actor时过滤Actor(如以下视频所示)。
必要的设置
在本指南中,我们将使用 游戏 > 第三人称模板 项目,并启用 C++ 和 无初学者内容包(No Starter Content) 设置,动画初学者包(Animation Starter Pack) (可在Epic Games商城中获取)。
添加一个站立和一个蹲伏骨骼网格体Actor到场景中。
选择并用"Standing"Actor标签标记站立骨骼网格体Actor。
重复上一步骤,并标记蹲伏骨骼网格体Actor。
追踪源过滤
在大型项目上使用Animation Insights时,务必限制应用程序的开销和硬盘空间用量。在以下范例中,Animation Insights将输出场景中所有Actor的追踪数据。
若要减少Animation Insights追踪数据,可使用追踪源过滤来选择哪些gameplay对象可以输出追踪数据。执行以下步骤即可启用追踪源过滤:
在 Animation Insights 中,选择 菜单(Menu)>(过滤)追踪源过滤((Filtering) Trace Source Filtering)。
在 追踪源过滤(Trace Source Filtering) 中,启用选项(Options)> 可视化(Visualize)> Actor过滤(Actor Filtering)。
要验证在编辑器中运行的追踪源过滤,可在激活关卡编辑器视口(PIE会话)中运行关卡。你将看到以下内容:
要实现追踪源过滤器,启用选项(Options)> 可视化(Visualize)> 仅通过过滤的Actor(Only Actor(s) passing Filtering)。
如果在PIE会话中运行关卡,并同时启用Actor过滤(Actor Filtering)和仅通过过滤的Actor(Only Actor(s) passing Filtering),则由于尚未实现过滤器,追踪源过滤功能将显示场景中所有Actor。
启用追踪源过滤后,你可以实现部分过滤器以限制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蓝图过滤器
在 追踪源过滤(Trace Source Filtering) 中,选择 添加过滤器(Add Filter)>新建过滤器蓝图(Create new Filter Blueprint)。
显示"资产另存为(Save Asset As)"菜单时,在"/Game/"中新建FilterBP文件夹。
在
/Game/FilterBP/
下,将资产另存为HasTag。在HasTag蓝图编辑器(HasTag Blueprint)中,选择 函数(Functions)>(函数)重载((Function) Override)> Actor通过过滤器(Does Actor Pass Filter)。
添加包含以下细节的新变量:
变量命名:ActorTag
变量类型:字符串
可编辑实例:已启用
提示文本:Actor标签命名
编译蓝图即可定义默认值。
在细节面板中,将默认值设为`ACTOR TAG`。
使用以下蓝图定义 Actor通过过滤器 功能。
在"我的蓝图"面板上的"追踪源过滤"分类中,右键点击 获取工具提示文本(Get Tool Tip Text) 函数,然后选择 实现函数(Implement Function)。
使用以下蓝图定义 获取工具提示文本(Get Tool Tip Text) 函数:
使用以下蓝图定义 获取显示文本(Get Display Text) 函数。
编译、保存并关闭HashTag蓝图编辑器,以在过滤器区域查看HashTag蓝图过滤器。
添加过滤器(Add Filter)
点击HashTag过滤器,然后将ACTOR标签(ACTOR TAG)改为
Crouching
即可定义Actor TAG
。运行PIE会话即可验证是否已在必要设置(Required Setup)部分正确标记Actor。
验证HashTag蓝图过滤器预期工作后,即可实现DistanceToPlayer原生过滤器。
如HasTag未滤入Actor,则验证Actor标签命名是否与指定到Actor标签命名变量的命名相同。如命名相同,则检查蓝图中的bug。
DistanceToPlayer原生过滤器
将空C++类添加到项目,并命名为"DistanceToPlayer"。
在项目的`*.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" }); } }
在 `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; };
在 `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"
在 添加过滤器(Add Filter) 下拉菜单中,编译代码以查看 DistanceToPlayer 过滤器。
选择 DistanceToPlayer 即可将新原生过滤器添加到过滤器区域。
右键点击"蹲伏(Crouching)"标签,然后选择 移除过滤器(Remove Filter),将过滤器区域中的HashTag蓝图过滤器移除。
运行PIE会话即可验证DistanceToPlayer过滤器。
验证DistanceToPlayer原生过滤器预期运行后,即可组合过滤器以满足用例要求。
实现用例1
首先回顾一下用例要求:
过滤器逻辑 |
返回False |
返回True |
---|---|---|
DistanceToPlayer AND HasTag |
滤入Actor |
滤出Actor |
执行以下步骤即可满足此要求:
将 HasTag 过滤器添加到过滤器区域(Filter Area)。
将Actor标签命名变量设为`Standing`。
在过滤器区域中,将 HashTag 拖到 DistanceToPlayer 旁。
将 距离(Distance) 变量默认值从300改为400。
组成过滤器集时,可使用AND、OR和NOT逻辑运算符。右键点击逻辑运算符即可选择其他逻辑运算符。
运行PIE会话即可验证过滤器逻辑。
当玩家Pawn和标有站立Actor标签的Actor相聚在400cm内时,追踪源过滤系统将滤入该Actor。
用例2
我们假定需要在场景中移动时实现被玩家Pawn光线投射命中(或碰撞)的已标记骨骼网格体Actor的过滤器。根据此用例,我们将实现以下过滤器:
实现类型 |
过滤器命名 |
用法 |
---|---|---|
蓝图 |
IsOfClass |
滤入属于指定类的Actor。将默认类定义为骨骼网格体Actor。 |
原生 |
光线投射 |
滤入被玩家Pawn的光线投射命中的已标记Actor。将默认光线长度定义为400cm。 |
实现过滤器后,我们将组合它们,以便在已标记骨骼网格体Actor被玩家Pawn的光线投射命中时滤入Actor,Animation Insights可以记录其的追踪数据。在本章最后,还应确保过滤器满足用例要求,将过滤器逻辑如下设置:
过滤器逻辑 |
返回True |
返回False |
---|---|---|
RaycastActor AND IsOfClass |
滤入Actor |
滤出Actor |
IsOfClass蓝图过滤器
在 追踪源过滤(Trace Source Filtering) 对话框中,选择 添加过滤器(Add Filter)> 新建过滤器蓝图(Create new Filter Blueprint)。
在
/Game/FilterBP/
下将资产另存为IsOfClass。在IsOfClass蓝图(HasTag Blueprint)编辑器中,选择 函数(Functions)>(函数)重载((Function) Override)>Actor通过过滤器(Does Actor Pass Filter)。
添加包含以下细节的新变量:
变量命名:**ActorClassRef
变量类型:Actor类参考
可编辑实例:启用
提示文本:Actor类参考
编译蓝图即可定义默认值。
将默认值定义为 SkeletalMeshActor。
使用以下蓝图定义Actor通过过滤器函数:
在"我的蓝图"面板中的"追踪源过滤"(Trace Source Filtering)分类中,右键点击 获取工具提示文本(Get Tool Tip Text) 函数,然后选择 实现函数(Implement Function)。
使用以下蓝图定义 获取工具提示文本(Get Tool Tip Text) 函数。
使用以下蓝图定义 获取显示文本(Get Display Text) 函数。
编译、保存并关闭HashTag蓝图编辑器,以在过滤器区域查看IsOfClass蓝图过滤器。
运行PIE会话即可验证IsOfClass过滤器。
验证IsOfClass蓝图过滤器预期工作后,即可实现RaycastActor原生过滤器。
RaycastActor原生过滤器
将空C++类添加到项目,并命名为`RaycastActor`。
在`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; };
在`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"
在 添加过滤器(Add Filter) 下拉菜单中,编译代码以查看RaycastActor过滤器。
右键点击"为SkeletalMeshActor过滤器",然后选择 移除过滤器(Remove Filter),将过滤器区域中的IsOfClass蓝图过滤器移除。
选择 RaycastActor 即可将新原生过滤器(Native Filter)添加到过滤器区域(Filter Area)。
点击光线过滤器(Rayfilter),然后将
ADD ACTOR TAG
更改为Standing
即可定义Actor标签命名。运行PIE会话即可验证RaycastActor过滤器。
验证RaycastActor原生过滤器预期工作后,即可组合过滤器以满足用例要求。
实现用例2
首先回顾一下用例要求:
过滤器逻辑 |
返回True |
返回False |
---|---|---|
RaycastActor AND IsOfClass |
滤入Actor |
滤出Actor |
将IsOfClass过滤器添加至过滤器区域(Filter Area)。
在过滤器区域中,将IsOfClass拖到RaycastActor旁。
运行PIE会话即可验证过滤器逻辑。
当玩家Pawn的光线投射命中标有站立Actor标签的Actor时,追踪源过滤系统将滤入骨骼网格体Actor。
自行尝试!
通过对两个范例用例进行实现,你已学习了如何使用追踪源过滤。可思考利用其他哪些过滤器可便于Animation Insights仅追踪自己需要的Actor数据。
部分过滤器理念可能包括:
发射物碰撞
自动导向发射物碰撞
按钮触发器
在实现过滤器时,请思考对过滤器进行逻辑组合的方式,以便过滤器滤入有助于优化和调试动画的Actor数据。虽然我们只使用了AND逻辑运算符,但不妨思考利用OR和NOT运算符来组合逻辑的方法。