3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

UE5 トレース系の処理についてのメモ

Last updated at Posted at 2024-03-07

概要

UnrealEngine5 のトレースについてのメモ。
似たようなものでオーバーラップ(UWorld::OverlapMultiByObjectTypeなど)がありますが、こちらはオーバーラップするとコリジョンイベントが発生します。

更新履歴

日付 内容
2024/03/07 初版
2024/11/05 サンプルコード修正

参考

以下の記事を参考にいたしました、ありがとうございます。
UE5公式:トレースの概要
UE4レイキャスト(ライントレース)を使う
Sweep Multi Line Trace
非同期シーンを利用したRaycast
UE5公式:UWorld
UE5公式:UKismetSystemLibrary
UE5公式:FRraceHandle
【UE5】コリジョン管理・処理に関する講演メモ・補足 : Collision Data in UE5: Practical Tips for Managing Collision Settings & Queries | Unreal Fest 2023
コリジョンについて

環境

Windows10
Visual Studio 2022
UnrealEngine 5.3.2

関連ソース

"Engine\Source\Runtime\Engine\Classes\Engine\World.h"
"Engine\Source\Runtime\Engine\Private\World.cpp"
"Engine\Source\Runtime\Engine\Classes\Kismet\KismetSystemLibrary.h"
"Engine\Source\Runtime\Engine\Public\CollisionQueryParams.h"

KismetSystemLibrary

トレース系メソッドはUWorldクラスにありますが、BPで扱えるように KismetSystemLibraryクラスにてラップされています。

ライントレース

ライントレースはブロックヒットまでに返すヒット数が1つか複数かでSingleMulti が用意されています。

KismetSystemLibrary.h
// 指定されたラインに沿って衝突トレースを実行し、最初に発生したブロックヒットを返します。
// このトレースは、指定された TraceChannel に応答するオブジェクトを検索します。
UFUNCTION(BlueprintCallable, Category="Collision", meta=(bIgnoreSelf="true", WorldContext="WorldContextObject", AutoCreateRefTerm="ActorsToIgnore", DisplayName="Line Trace By Channel", AdvancedDisplay="TraceColor,TraceHitColor,DrawTime", Keywords="raycast"))
static ENGINE_API bool LineTraceSingle(const UObject* WorldContextObject, const FVector Start, const FVector End, ETraceTypeQuery TraceChannel, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTrace::Type DrawDebugType, FHitResult& OutHit, bool bIgnoreSelf, FLinearColor TraceColor = FLinearColor::Red, FLinearColor TraceHitColor = FLinearColor::Green, float DrawTime = 5.0f);

// 指定されたラインに沿って衝突トレースを実行し、最初のブロックヒットまでに発生したすべてのヒットを返します。
// このトレースは、指定された TraceChannel に応答するオブジェクトを見つけます。
UFUNCTION(BlueprintCallable, Category="Collision", meta=(bIgnoreSelf="true", WorldContext="WorldContextObject", AutoCreateRefTerm="ActorsToIgnore", DisplayName = "Multi Line Trace By Channel", AdvancedDisplay="TraceColor,TraceHitColor,DrawTime", Keywords="raycast"))
static ENGINE_API bool LineTraceMulti(const UObject* WorldContextObject, const FVector Start, const FVector End, ETraceTypeQuery TraceChannel, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTrace::Type DrawDebugType, TArray<FHitResult>& OutHits, bool bIgnoreSelf, FLinearColor TraceColor = FLinearColor::Red, FLinearColor TraceHitColor = FLinearColor::Green, float DrawTime = 5.0f);

このほか、???ForObjects, ???ByProfile のような引数違いのメソッドが用意されています。???ByProfile での引数 FName ProfileNameBlockAllOverlapAllなどのプロジェクト設定の[コリジョン]で定義されている名前です。通常はゲーム独自の追加プロファイルで使うと思います。

KismetSystemLibrary.h
// 指定されたラインに沿って衝突トレースを実行し、最初に発生したヒットを返します。
// これは、ObjectTypes で指定されたタイプのオブジェクトのみを検索します。
UFUNCTION(BlueprintCallable, Category="Collision", meta=(bIgnoreSelf="true", WorldContext="WorldContextObject", AutoCreateRefTerm="ActorsToIgnore", DisplayName = "Line Trace For Objects", AdvancedDisplay="TraceColor,TraceHitColor,DrawTime", Keywords="raycast"))
static ENGINE_API bool LineTraceSingleForObjects(const UObject* WorldContextObject, const FVector Start, const FVector End, const TArray<TEnumAsByte<EObjectTypeQuery> > & ObjectTypes, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTrace::Type DrawDebugType, FHitResult& OutHit, bool bIgnoreSelf, FLinearColor TraceColor = FLinearColor::Red, FLinearColor TraceHitColor = FLinearColor::Green, float DrawTime = 5.0f );

// 指定されたラインに沿って衝突トレースを実行し、発生したすべてのヒットを返します。
// これは、ObjectTypes で指定されたタイプのオブジェクトのみを検索します。
UFUNCTION(BlueprintCallable, Category="Collision", meta=(bIgnoreSelf="true", WorldContext="WorldContextObject", AutoCreateRefTerm="ActorsToIgnore", DisplayName = "Multi Line Trace For Objects", AdvancedDisplay="TraceColor,TraceHitColor,DrawTime", Keywords="raycast"))
static ENGINE_API bool LineTraceMultiForObjects(const UObject* WorldContextObject, const FVector Start, const FVector End, const TArray<TEnumAsByte<EObjectTypeQuery> > & ObjectTypes, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTrace::Type DrawDebugType, TArray<FHitResult>& OutHits, bool bIgnoreSelf, FLinearColor TraceColor = FLinearColor::Red, FLinearColor TraceHitColor = FLinearColor::Green, float DrawTime = 5.0f);

// 特定のプロファイルを使用してワールドに対してレイをトレースし、最初のブロック ヒットを返します。
UFUNCTION(BlueprintCallable, Category = "Collision", meta = (bIgnoreSelf = "true", WorldContext = "WorldContextObject", AutoCreateRefTerm = "ActorsToIgnore", DisplayName = "Line Trace By Profile", AdvancedDisplay = "TraceColor,TraceHitColor,DrawTime", Keywords = "raycast"))
static ENGINE_API bool LineTraceSingleByProfile(const UObject* WorldContextObject, const FVector Start, const FVector End, FName ProfileName, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTrace::Type DrawDebugType, FHitResult& OutHit, bool bIgnoreSelf, FLinearColor TraceColor = FLinearColor::Red, FLinearColor TraceHitColor = FLinearColor::Green, float DrawTime = 5.0f);

トレースは床の高さを調べる等で使うケースが多いと思います。
以下コード例。

床の高さを調べる
	// 元の位置
	FVector _Loc = GetActorLocation();

	// 床を調べる
	FVector _St = _Loc + GetActorUpVector() * +500.0f;
	FVector _Ed = _Loc + GetActorUpVector() * -500.0f;
	FHitResult _HitResult;
	TArray<AActor*> ActorsToIgnore;

	UKismetSystemLibrary::LineTraceSingle(this, _St, _Ed,
			UEngineTypes::ConvertToTraceType(ECollisionChannel::ECC_WorldStatic),
			false, ActorsToIgnore, EDrawDebugTrace::None, _HitResult, true);

	if (_HitResult.bBlockingHit) {
		// 床の高さに補正
		_Loc = _HitResult.ImpactPoint;
	}
	else {
		// 床が見当たらない?
	}

LineTraceByChannel

BPでのノードは以下のようになっています。
LineTraceByChannel.png

LineTraceForObjects

引数が少し違います。ForObjects では調べるオブジェクトタイプを直接指定する必要があります。
LineTraceByObjects.png

LineTraceByProfile

引数にコリジョンプロファイル名を指定する必要があります。
LineTraceByProfileBP.png

ライン以外のトレース

ライン以外にスフィア、ボックス、カプセルがあり、それぞれ Single/Multi、Channel/ForObjects/ByProfile 版の各メソッドが用意されています。

KismetSystemLibrary.h
// スフィア
UFUNCTION(BlueprintCallable, Category="Collision", meta=(bIgnoreSelf="true", WorldContext="WorldContextObject", AutoCreateRefTerm="ActorsToIgnore", DisplayName = "Sphere Trace By Channel", AdvancedDisplay="TraceColor,TraceHitColor,DrawTime", Keywords="sweep"))
static ENGINE_API bool SphereTraceSingle(const UObject* WorldContextObject, const FVector Start, const FVector End, float Radius, ETraceTypeQuery TraceChannel, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTrace::Type DrawDebugType, FHitResult& OutHit, bool bIgnoreSelf, FLinearColor TraceColor = FLinearColor::Red, FLinearColor TraceHitColor = FLinearColor::Green, float DrawTime = 5.0f);

// ボックス
UFUNCTION(BlueprintCallable, Category = "Collision", meta = (bIgnoreSelf = "true", WorldContext="WorldContextObject", AutoCreateRefTerm = "ActorsToIgnore", DisplayName = "Box Trace By Channel", AdvancedDisplay="TraceColor,TraceHitColor,DrawTime", Keywords="sweep"))
static ENGINE_API bool BoxTraceSingle(const UObject* WorldContextObject, const FVector Start, const FVector End, const FVector HalfSize, const FRotator Orientation, ETraceTypeQuery TraceChannel, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTrace::Type DrawDebugType, FHitResult& OutHit, bool bIgnoreSelf, FLinearColor TraceColor = FLinearColor::Red, FLinearColor TraceHitColor = FLinearColor::Green, float DrawTime = 5.0f);

// カプセル
UFUNCTION(BlueprintCallable, Category="Collision", meta=(bIgnoreSelf="true", WorldContext="WorldContextObject", AutoCreateRefTerm="ActorsToIgnore", DisplayName = "Capsule Trace By Channel", AdvancedDisplay="TraceColor,TraceHitColor,DrawTime", Keywords="sweep"))
static ENGINE_API bool CapsuleTraceSingle(const UObject* WorldContextObject, const FVector Start, const FVector End, float Radius, float HalfHeight, ETraceTypeQuery TraceChannel, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, EDrawDebugTrace::Type DrawDebugType, FHitResult& OutHit, bool bIgnoreSelf, FLinearColor TraceColor = FLinearColor::Red, FLinearColor TraceHitColor = FLinearColor::Green, float DrawTime = 5.0f);

BPでは以下のようになっています。
TraceBP.png

UWorld

トレース系メソッドはこちらに実装されています、BPでは呼び出せないのでC++で処理をつくることが必要です。

非同期ライントレース

非同期処理のトレース系メソッドが用意されています。非同期なので即時結果を取得することはできませんが、うまく使うとゲームスレッドの処理負荷軽減にもなります。

World.h
// 非同期用のインターフェース。 パラメータセットはほぼ同じですが、オプションで実行完了時に呼び出されるデリゲートを設定でき、必要に応じて UserData を設定できます。
// デリゲートがない場合は、QueryTraceData または QueryOverlapData を使用してトレース データをクエリできます。データは、リクエストが行われた後の次のフレームでのみ利用可能です。つまり、フレーム X でリクエストが行われた場合、フレーム (X+1) で結果を取得できます。 )
FTraceHandle	AsyncLineTraceByChannel(EAsyncTraceType InTraceType, const FVector& Start,const FVector& End, ECollisionChannel TraceChannel, const FCollisionQueryParams& Params = FCollisionQueryParams::DefaultQueryParam, const FCollisionResponseParams& ResponseParam = FCollisionResponseParams::DefaultResponseParam, const FTraceDelegate* InDelegate = nullptr, uint32 UserData = 0 );

 
同期版トレースとの違いはリクエスト時にトレースハンドル(FTraceHandle) が返ってくることと、完了時のデリゲートに処理を登録する必要があることです。
また複数のトレースを実行する場合はハンドルを保持してデリゲートで判別分岐処理等が必要になると思います。
以下サンプルコード。

TestActor.h
UCLASS()
class SAMPLE_API ATestActor : public AActor
{
	GENERATED_BODY()

// ..省略..

	// トレースデリゲート
	FTraceDelegate	TraceDelegate;
	
	// 完了時イベント
	void OnTraceCompleted(const FTraceHandle& _Handle, FTraceDatum& _Data);
	// トレースリクエスト
	FTraceHandle RequestTrace();

}; 
TestActor.cpp
#include "Engine/World.h"

void ATestActor::BeginPlay()
{
	// トレース完了時処理をバインド
	TraceDelegate.BindUObject(this, &ThisClass::OnTraceCompleted);
 	// トレースリクエスト
	RequestTrace();
}

// トレース完了時処理
void ATestActor::OnTraceCompleted(const FTraceHandle& _Handle, FTraceDatum& _Data)
{ 
	// 結果表示
	for (auto& _It : _Data.OutHits) {
		UE_LOG(LogTemp, Log, TEXT("OutHit : %s"), *_It.GetActor()->GetFName().ToString())
	}
}

// トレースリクエスト
FTraceHandle ATestActor::RequestTrace()
{
	UWorld* _World = GetWorld();
	if (_World == nullptr){	return(FTraceHandle()); }

	FCollisionObjectQueryParams _ObjectQueryParams;
	_ObjectQueryParams.AddObjectTypesToQuery(ECollisionChannel::ECC_Pawn);

	TArray<AActor*> _ActorsToIgnore;
	FCollisionQueryParams _Params(TEXT("ASyncTest"), false);
	_Params.AddIgnoredActors(_ActorsToIgnore);

	auto _St = GetOwner()->GetActorLocation();
	auto _Ed = _St + (GetOwner()->GetActorForwardVector() * 1000.0f);

	// マルチでライントレース
	auto _Handle = _World->AsyncLineTraceByObjectType(EAsyncTraceType::Multi, _St, _Ed, _ObjectQueryParams, _Params, &TraceDelegate);
	return(_Handle);
}

トレースデリゲートはラムダ式でバインドもできます。
以下サンプルコード。

トレースデリゲートをラムダ式でバインドする
	FVector _St = /* 開始位置 */
	FVector _Ed = /* 終了位置 */

	FCollisionObjectQueryParams _ObjectQueryParams;
	_ObjectQueryParams.AddObjectTypesToQuery(ECC_WorldDynamic);
	FCollisionQueryParams _TraceParams;
	_TraceParams.bTraceComplex = false;

	// トレースデリゲート
	FTraceDelegate _TraceDelegate;
	_TraceDelegate.BindLambda([](const FTraceHandle& _Handle, FTraceDatum& _Data)
	{
		if (_Data.OutHits.Num() > 0){
			// ヒットした場合の処理
			const FHitResult& _Hit = _Data.OutHits[0];
			UE_LOG(LogTemp, Log, TEXT("Hit Actor: %s"), *_Hit.GetActor()->GetName());
		}
	});

	// 非同期トレースを行う
	auto _Trace = GetWorld()->AsyncLineTraceByObjectType(EAsyncTraceType::Single, _St, _Ed, _ObjectQueryParams, _TraceParams, &_TraceDelegate);
	

非同期スフィアトレース

ライン以外のスフィア、ボックス、カプセルのトレースは AsyncSweep???メソッドで行います。形状設定は FCollisionShapeで指定します。

非同期スフィアトレース

FCollisionShape _MySphere = FCollisionShape::MakeSphere(100.0f);
ECollisionChannel _TraceChannel = ECollisionChannel::ECC_Pawn;
FCollisionQueryParams _Params(TEXT("ASyncTest"), false);

auto _Handle = GetWorld()->AsyncSweepByChannel(EAsyncTraceType::Multi, _St, _Ed, FQuat::Identity, _TraceChannel, _MySphere, _Params, FCollisionResponseParams::DefaultResponseParam, &TraceDelegate);

コリジョンオーバーラップテスト

特定形状のコリジョンをオーバーラップテストをするメソッドもあります。トレースと違って移動はなしで衝突したコンポーネントでコリジョンイベントが発生します。

World.h
// 特定のチャネルを使用して、指定された位置でシェイプの衝突をテストし、ブロックまたは重複するシェイプが見つかった場合は返します。
bool OverlapAnyTestByChannel(const FVector& Pos, const FQuat& Rot, ECollisionChannel TraceChannel, const FCollisionShape& CollisionShape, const FCollisionQueryParams& Params = FCollisionQueryParams::DefaultQueryParam, const FCollisionResponseParams& ResponseParam = FCollisionResponseParams::DefaultResponseParam) const;

// 特定のチャネルを使用して、指定された位置でシェイプの衝突をテストし、オーバーラップするコンポーネントのセットを決定します。
bool OverlapMultiByChannel(TArray<struct FOverlapResult>& OutOverlaps, const FVector& Pos, const FQuat& Rot, ECollisionChannel TraceChannel, const FCollisionShape& CollisionShape, const FCollisionQueryParams& Params = FCollisionQueryParams::DefaultQueryParam, const FCollisionResponseParams& ResponseParam = FCollisionResponseParams::DefaultResponseParam) const;

まとめ

ライントレース以外はあまり使わないのでまとめ。非同期系はゲームスレッドの処理負荷軽減のためにも使っていきたいところです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?