概要
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つか複数かでSingle
とMulti
が用意されています。
// 指定されたラインに沿って衝突トレースを実行し、最初に発生したブロックヒットを返します。
// このトレースは、指定された 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 ProfileName
は BlockAll
やOverlapAll
などのプロジェクト設定の[コリジョン]で定義されている名前です。通常はゲーム独自の追加プロファイルで使うと思います。
// 指定されたラインに沿って衝突トレースを実行し、最初に発生したヒットを返します。
// これは、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
LineTraceForObjects
引数が少し違います。ForObjects
では調べるオブジェクトタイプを直接指定する必要があります。
LineTraceByProfile
ライン以外のトレース
ライン以外にスフィア、ボックス、カプセルがあり、それぞれ Single/Multi、Channel/ForObjects/ByProfile 版の各メソッドが用意されています。
// スフィア
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);
UWorld
トレース系メソッドはこちらに実装されています、BPでは呼び出せないのでC++で処理をつくることが必要です。
非同期ライントレース
非同期処理のトレース系メソッドが用意されています。非同期なので即時結果を取得することはできませんが、うまく使うとゲームスレッドの処理負荷軽減にもなります。
// 非同期用のインターフェース。 パラメータセットはほぼ同じですが、オプションで実行完了時に呼び出されるデリゲートを設定でき、必要に応じて 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
) が返ってくることと、完了時のデリゲートに処理を登録する必要があることです。
また複数のトレースを実行する場合はハンドルを保持してデリゲートで判別分岐処理等が必要になると思います。
以下サンプルコード。
UCLASS()
class SAMPLE_API ATestActor : public AActor
{
GENERATED_BODY()
// ..省略..
// トレースデリゲート
FTraceDelegate TraceDelegate;
// 完了時イベント
void OnTraceCompleted(const FTraceHandle& _Handle, FTraceDatum& _Data);
// トレースリクエスト
FTraceHandle RequestTrace();
};
#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);
コリジョンオーバーラップテスト
特定形状のコリジョンをオーバーラップテストをするメソッドもあります。トレースと違って移動はなしで衝突したコンポーネントでコリジョンイベントが発生します。
// 特定のチャネルを使用して、指定された位置でシェイプの衝突をテストし、ブロックまたは重複するシェイプが見つかった場合は返します。
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;
まとめ
ライントレース以外はあまり使わないのでまとめ。非同期系はゲームスレッドの処理負荷軽減のためにも使っていきたいところです。