How to Implement Trace Source Filtering

Learn how to implement trace source filtering to optimize Animation Insights tracing.

Choose your operating system:

Windows

macOS

Linux

Prerequisite Topics

In order to understand and use the content on this page, make sure you are familiar with the following topics:

In this guide, you will implement two example use cases to learn how to use Trace Source Filtering for your own projects. For example, after implementing the second use case, the Trace Source Filtering system will filter in Actors when your Player Pawn's raycast hits the standing Actor in the following video.

Notice how Actors filter in

Required Setup

For this How-to, we use the Games > Third Person Template project, with C++ and No Starter Content enabled, and the Animation Starter Pack (available in the Epic Games Marketplace ).

  1. Add one standing and one crouching Skeletal Mesh Actor to the Scene.

    We use Equip_Rifle_Standing on the right and Crouch_Idle_Rifle_Ironsights on the left.

  2. Select and tag the standing Skeletal Mesh Actor with the Standing Actor Tag.

  3. Repeat the last step and tag the crouching Skeletal Mesh Actor.

    HT_ReqSetup_2.png

Trace Source Filtering

overview

When working with Animation Insights on a large project, it is vital to limit the application's overhead and disk space usage. In the following example, Animation Insights outputs trace data for all Actors in the Scene.

Identifying performance issues will be difficult if this project grows to include thousands of objects.

To reduce the amount of Animation Insights trace data, use Trace Source Filtering to choose which gameplay objects can output trace data. To enable Trace Source Filtering, follow these steps:

  1. In Animation Insights , select Menu > (Filtering) Trace Source Filtering .

    HT_TraceSourceFiltering_1.png

  2. In Trace Source Filtering , enable Options > Visualize > Actor Filtering .

    HT_TraceSourceFiltering_2.png

  3. To verify that Trace Source Filtering runs in the editor, play the level in the active level editor viewport (PIE Session). You should see the following:

    Trace Source Filtering renders boxes around all Actors in this scene.

  4. To implement Trace Source Filters, enable Options > Visualize > Only Actor(s) passing Filtering .

    HT_TraceSourceFiltering_3.png

If you play the level in PIE Session and enable both Actor Filtering and Only Actor(s) passing Filtering, the Trace Source Filtering feature visualizes every actor in the scene because you haven't implemented Filters yet.

HT_TraceSourceFiltering_EndResult.png

Animation Insights with Trace Source Filtering enabled

Now that you've enabled Trace Source Filtering, you can implement some filters to limit the amount of trace data that Animation Insights will output. The rest of this guide shows some use cases, including Blueprint and C++ (Native) Filter implementations for each use case.

Use Case 1

Let's say that we want to implement Filters for tagged Actors located within a specified distance of our Player Pawn's position. With this use case in mind, we will implement the following filters:

Implementation Type

Filter Name

Usage

Blueprint

HasTag

To filter in Actors that have a defined Actor tag.

Native

DistanceToPlayer

To filter in Actors that are located within a specified distance of our Player Pawn's position. Define the default distance to be 300 Unreal Units (cm).

After implementing the filters, we will combine them so that if a tagged Actor is within a specific distance of our Player Pawn, to filter in the Actor so that Animation Insights can record its trace data. At the end of this section, our filters should meet the use case requirement with filter logic that looks like the following:

Filter Logic

Returns True

Returns False

DistanceToPlayer AND HasTag

Filter in Actors

Filter out Actors

When defining Filter logic, it's helpful to write requirements as complete sentences because it helps to identify potential flaws in the logic prior to implementation.

HasTag Blueprint Filter

  1. In the Trace Source Filtering dialog box, select Add Filter > Create new Filter Blueprint .

    HT_HasTagBPFilter_1.png

  2. When the Save Asset As menu appears, create a new FilterBP folder under /Game/ .

    HT_HasTagBPFilter_2.png

  3. Save the Asset As HasTag under /Game/FilterBP/ .

  4. In the HasTag Blueprint editor, select Functions > (Function) Override > Does Actor Pass Filter .

    HT_HasTagBPFilter_3.png

  5. Add a new Variable with the following details:

    • Variable Name: ActorTag

    • Variable Type: String

    • Instance Editable: Enabled

    • Tooltip: Actor Tag Name

  6. To define the default value, compile the Blueprint.

  7. In the Details panel, define the default value as ACTOR TAG .

    HT_HasTagBPFilter_4.png

  8. Define the Does Actor Pass Filter function with the following Blueprint.

    Click for full image.

  9. In the My Blueprint panel's Trace Source Filtering category, right-click the Get Tool Tip Text function and select Implement Function .

    HT_HasTagBPFilter_6.png

  10. Define the Get Tool Tip Text function with the following Blueprint:

    Click for full image.

    {0} format placeholder. To learn more about text formatting, read about Text Localization

  11. Define the Get Display Text function with the following Blueprint.

    Click for full image.

  12. Compile, save, and close the HasTag Blueprint Editor to view the HasTag Blueprint Filter in the Filter Area.

    Click for full image.

    Add Filter

  13. To define the Actor Tag name, click the HasTag filter, and change ACTOR TAG to Crouching .

    HasTag Filter

  14. To verify that you tagged the Actors correctly in the Required Setup section, run a PIE Session.

    The Actor we tagged Crouching (on the left) filters in during the PIE Session.

    After verifying the HasTag Blueprint Filter works as expected, you're ready to implement the DistanceToPlayer Native Filter.

    If HasTag isn't filtering in the Actor, verify that the Actor Tag name is the same as the name assigned to the Actor Tag Name variable. If the names are the same, inspect the Blueprint for bugs.

DistanceToPlayer Native Filter

  1. Add an empty C++ Class to the project, and name it DistanceToPlayer .

  2. In your project's *.Build.cs file, add the "SourceFilteringTrace", "SourceFilteringCore", and "SourceFilteringEditor" Public Dependency Module Names:

    // Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
    
    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. In DistanceToPlayer.h , add the following code:

    // Fill out your copyright notice in the Description page of Project Settings.
    
    #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. In DistanceToPlayer.cpp , add the following code:

    // Fill out your copyright notice in the Description page of Project Settings.
    
    #include "DistanceToPlayer.h"
    #include "GameFramework/PlayerController.h"
    #include "GameFramework/Pawn.h"
    #include "Engine/World.h"
    
    #define LOCTEXT_NAMESPACE "UDistanceToPlayer"
    
    /**
    Set initial distance to 300 Unreal Units (cm).
    */
    UDistanceToPlayer::UDistanceToPlayer() : Distance(300.0f)
    {
    }
    
    /**
    Check the Actor's distance to our Player 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())
                    {
                        /**Return true if Actor is less than the distance threshold to our Player Pawn.*/
                        return Pawn->GetDistanceTo(InActor) < Distance;
                    }
                }
            }
        }
        return false;
    }
    
    /**
    The player can customize the distance value.
    */
    void UDistanceToPlayer::GetDisplayText_Internal(FText& OutDisplayText) const
    {
        OutDisplayText = FText::Format(LOCTEXT("DisplayText", "Distance to Player Pawn < {0}"), { Distance });
    }
    #undef LOCTEXT_NAMESPACE // "UDistanceToPlayer"
  5. In the Add Filter dropdown, compile the code to view the DistanceToPlayer Filter.

    HT_DistanceToPlayerNativeFilter_1.png

  6. To add the new Native Filter to the Filter Area, select DistanceToPlayer .

  7. Right-click the Crouching tag and select Remove Filter to remove the HasTag Blueprint Filter from the Filter Area.

    DistanceToPlayer Filter

  8. To verify the DistanceToPlayer Filter, run a PIE Session.

    Actors within 300 Unreal Units (cm) of our Player Pawn filter in.

After verifying the DistanceToPlayer Native Filter works as expected, you're ready to combine the filters to meet the use case requirement.

Implementing Use Case 1

Let's revisit the use case requirement:

Filter Logic

Returns False

Returns True

DistanceToPlayer AND HasTag

Filter in Actors

Filter out Actor(s)

To meet this requirement, follow these steps:

  1. Add a HasTag Filter to the Filter Area.

  2. Set the Actor Tag name variable to Standing .

  3. In the Filter Area, drag HasTag next to DistanceToPlayer .

    Dragging HasTag

  4. Change the Distance variable default value from 300 to 400.

    Changing Distance Variable

    When composing a Filter Set, the AND, OR, and NOT logical operators are available. Right-click the logic operator to select a different one.

    HT_DistanceToPlayerNativeFilter_4.png

  5. To verify the filter logic, run a PIE Session.

When our Player Pawn gets within 400 cm of the Actor tagged with the Standing Actor Tag, the Trace Source Filtering system filters in the Actor.

Notice how Animation Insights (lower left panel) only traces Equip_Pistol_Standing - Blend Weight (and Graph) data when our Player Pawn is in range.

Use Case 2

Let's say that we want to implement Filters for tagged Skeletal Mesh Actors that are hit by (or collide with) our Player Pawn's Raycast as we move around the scene. With this use case in mind, we will implement the following filters:

Implementation Type

Filter Name

Usage

Blueprint

IsOfClass

To filter in Actors that belong to a specified Class. Define the default class to be Skeletal Mesh Actor.

Native

Raycast

To filter in tagged Actors that are hit by our Player Pawn's Raycast. Define the default ray length to be 400 cm.

After implementing the filters, we will combine them so that if a tagged Skeletal Mesh Actor is hit by Player Pawn's Raycast, to filter in the Actor so that Animation Insights can record its trace data. At the end of this section, our filters should meet the use case requirement with filter logic that looks like the following:

Filter Logic

Returns True

Returns False

RaycastActor AND IsOfClass

Filter in Actors

Filter out Actors

IsOfClass Blueprint Filter

  1. In the Trace Source Filtering dialog box, select Add Filter > Create new Filter Blueprint .

  2. Save the Asset As IsOfClass under /Game/FilterBP/ .

  3. In the IsOfClass Blueprint editor, select Functions > (Function) Override > Does Actor Pass Filter .

  4. Add a new Variable with the following details:

    • Variable Name: ActorClassRef

    • Variable Type: Actor Class Reference

    • Instance Editable: Enabled

    • Tooltip: Actor Class Reference

  5. To define the default value, compile the Blueprint.

  6. Define the default value as SkeletalMeshActor .

    HT_IsOfClassBP_1.png

  7. Define the Does Actor Pass Filter function with the following Blueprint:

  8. In the My Blueprint panel's Trace Source Filtering category, right-click the Get Tool Tip Text function and select Implement Function .

  9. Define the Get Tool Tip Text function with the following Blueprint.

  10. Define the Get Display Text function with the following Blueprint.

  11. Compile, save, and close the HasTag Blueprint Editor to view the IsOfClass Blueprint Filter in the Filter Area.

  12. To verify the IsOfClass filter, run a PIE Session.

    Skeletal Mesh Actors filter in during the PIE Session.

After verifying the IsOfClass Blueprint Filter works as expected, you're ready to implement the RaycastActor Native Filter.

RaycastActor Native Filter

  1. Add an empty C++ Class to the project, and name it RaycastActor .

  2. In RaycastActor.h , add the following code:

    // Fill out your copyright notice in the Description page of Project Settings.
    
    #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. In RaycastActor.cpp , add the following code:

    // Fill out your copyright notice in the Description page of Project Settings.
    
    #include "RaycastActor.h"
    #include "GameFramework/PlayerController.h"
    #include "GameFramework/Pawn.h"
    #include "Engine/World.h"
    #include "DrawDebugHelpers.h"
    
    #define LOCTEXT_NAMESPACE "URaycastActor"
    
    /**
    Set initial distance to 400 Unreal Units (cm).
    */
    URaycastActor::URaycastActor() : ActorTagName("ADD ACTOR TAG"), RayLength(400.0f)
    {
    }
    
    /**
    Raycast from Player Pawn to hit a tagged 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);
    
                        /**Return true if Player Pawn's Ray hits a tagged Actor.*/
                        if (HitResult->GetActor() != NULL && HitResult->GetActor()->ActorHasTag(ActorTagName))
                        {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    
    /**
    The player can customize the following:
    * - The Actor Tag Name to look for
    * - The Ray Length
    */
    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. In the Add Filter dropdown, compile the code to view the RaycastActor Filter.

    HT_RaycastActor_1.png

  5. Right-click the "is a SkeletalMeshActor filter" and select Remove Filter to remove the IsOfClass Blueprint Filter from the Filter Area.

  6. To add the new Native Filter to the Filter Area, select RaycastActor .

  7. To define the Actor Tag name, click the Rayfilter, and change ADD ACTOR TAG to Standing .

    RaycastActor Filter

  8. To verify the RaycastActor Filter, run a PIE Session.

    All Actors filter in when the Standing Actor is hit by our Player Pawn's raycast.

After verifying the RaycastActor Native Filter works as expected, you're ready to combine the filters to meet the use case requirement.

Implementing Use Case 2

Let's revisit the use case requirement:

Filter Logic

Returns True

Returns False

RaycastActor AND IsOfClass

Filter in Actors

Filter out Actors

  1. Add an IsOfClass Filter to the Filter Area.

  2. In the Filter Area, drag IsOfClass next to RaycastActor.

    Dragging IsOfClass Filter

  3. To verify the filter logic, run a PIE Session.

When our Player Pawn's raycast hits the Actor tagged with the Standing Actor Tag, the Trace Source Filtering system filters in Skeletal Mesh Actors.

Notice how Animation Insights (lower left panel) only traces Equip_Pistol_Standing - Blend Weight and Crouch_Idle_Rifle_Ironsights - Blend Weight (and Graph) data when our Player Pawn's raycast hits the Standing Actor.

On Your Own!

Now that you've gotten some practice implementing two example use cases to learn how to use Trace Source Filtering, think of other filters so that Animation Insights only traces the Actor data you're interested in.

Some filter ideas might include:

  • Projectile Collision

  • Homing Projectile Collision

  • Button Trigger

While implementing your filters, think of how you can logically combine them so that they filter in the Actor data that will help you optimize and debug your Animations. Although we only used the AND logical operator, think of ways to combine your logic with OR and NOT operators as well.

Help shape the future of Unreal Engine documentation! Tell us how we're doing so we can serve you better.
Take our survey
Dismiss