[Unreal]#25_Collision Data
Unreal Engine의 Collision Data에 대해 알아보겠습니다.
Overview
- 개요
- Collision Setting
- Collision Query
- FCollisionResponseParams
- 예제
#1. 개요
1. Unreal Engine의 Collision Setting
Details
- 위 영상을 참조해 Unreal Engine의 Collision Setting에 대해 알아보고, 이를 관리하는 방법에 대해 리뷰합니다.
#2. 콜리전 세팅
1. Collision Data
Details
- Unreal Engine에서 Collision Data(충돌 정보)는 Collision Geometry와 객체의 충돌 속성 등을 의미합니다. 이러한 Collision Data는 객체가 월드 내 행동 방식을 결정하며, 우리는 해당 객체의 충돌 결과를 Collision Query를 통해 얻을 수 있습니다.
2. Collision Geometry
Details
- [개념] : Collision Geometry는 물체와 협력해 사용자에게 해당 물체의 충돌 정보를 전달하기 위한 간소화된 물리적인 모양입니다. 예를 들면, 간단한 박스 모양의 Collision Geometry가 Static Mesh를 둘러싸며, 해당 Static Mesh와 다른 어떠한 객체와 충돌하면, 그 충돌 정보를 사용자에게 전달합니다. 또, Primitive Shape 그 자체로 Level에 배치되어 Trigger Box 역할을 수행하거나, 캡슐 형태로 캐릭터에 부착되어 캐릭터의 충돌을 관리하기도 합니다.
3. Collision Channels
/**
* Enum indicating different type of objects for rigid-body collision purposes.
*/
UENUM(BlueprintType)
enum ECollisionChannel
{
ECC_WorldStatic UMETA(DisplayName="WorldStatic"),
ECC_WorldDynamic UMETA(DisplayName="WorldDynamic"),
ECC_Pawn UMETA(DisplayName="Pawn"),
ECC_Visibility UMETA(DisplayName="Visibility" , TraceQuery="1"),
ECC_Camera UMETA(DisplayName="Camera" , TraceQuery="1"),
ECC_PhysicsBody UMETA(DisplayName="PhysicsBody"),
ECC_Vehicle UMETA(DisplayName="Vehicle"),
ECC_Destructible UMETA(DisplayName="Destructible"),
/** Reserved for gizmo collision */
ECC_EngineTraceChannel1 UMETA(Hidden),
ECC_EngineTraceChannel2 UMETA(Hidden),
ECC_EngineTraceChannel3 UMETA(Hidden),
ECC_EngineTraceChannel4 UMETA(Hidden),
ECC_EngineTraceChannel5 UMETA(Hidden),
ECC_EngineTraceChannel6 UMETA(Hidden),
ECC_GameTraceChannel1 UMETA(Hidden),
ECC_GameTraceChannel2 UMETA(Hidden),
ECC_GameTraceChannel3 UMETA(Hidden),
ECC_GameTraceChannel4 UMETA(Hidden),
ECC_GameTraceChannel5 UMETA(Hidden),
ECC_GameTraceChannel6 UMETA(Hidden),
ECC_GameTraceChannel7 UMETA(Hidden),
ECC_GameTraceChannel8 UMETA(Hidden),
ECC_GameTraceChannel9 UMETA(Hidden),
ECC_GameTraceChannel10 UMETA(Hidden),
ECC_GameTraceChannel11 UMETA(Hidden),
ECC_GameTraceChannel12 UMETA(Hidden),
ECC_GameTraceChannel13 UMETA(Hidden),
ECC_GameTraceChannel14 UMETA(Hidden),
ECC_GameTraceChannel15 UMETA(Hidden),
ECC_GameTraceChannel16 UMETA(Hidden),
ECC_GameTraceChannel17 UMETA(Hidden),
ECC_GameTraceChannel18 UMETA(Hidden),
/** Add new serializeable channels above here (i.e. entries that exist in FCollisionResponseContainer) */
/** Add only nonserialized/transient flags below */
// NOTE!!!! THESE ARE BEING DEPRECATED BUT STILL THERE FOR BLUEPRINT. PLEASE DO NOT USE THEM IN CODE
ECC_OverlapAll_Deprecated UMETA(Hidden),
ECC_MAX,
};
Details
- [개념] : Collsion Channel은 충돌 컴포넌트가 충돌 가능한 혹은 충돌을 통한 상호작용을 허용하는 다른 충돌 컴포넌트를 지정하는 데 사용됩니다. 예를 들어, 캐릭터의 캡슐형 콜리전 컴포넌트의 콜리전 채널 설정을 통해 또 다른 캐릭터 객체의 캡슐형 컴포넌트 혹은 Static Mesh의 박스형 컴포넌트와 충돌할 때 어떤 동작을 수행할지 정의할 수 있습니다. 정리하면, Collision 채널은 Collision Component가 어떠한 Collision Component와 "충돌" 동작을 통해 상호작용 할 것인지, 아니면 "충돌" 동작을 무시할 것인지 결정하는 매개입니다.
- [종류] : Collision Channel은 두 종류입니다 - Trace Channel, Object Channel
4. Collision Profile
Details
- [개념] : Collision Profile은 Collision을 갖는 모든 컴포넌트 내 Collision 관련 속성들의 목록입니다. 'Object Type'은 Collision Channel을 설정하는 항목이고, Collision Response(콜리전 반응)은 해당 객체가 모든 Collision Channel에 대해 어떻게 반응할 것인지 설정하는 항목입니다.
5. Collision Filtering
Details
- [개념] : Collision Filtering은 두 객체의 Collision Profile을 통해 충돌에 의한 상호작용을 수행할 것인지 결정합니다. 예를 들면, 사용자 캐릭터와 Static Mesh의 충돌 시, 사용자 캐릭터는 Static Mesh의 Collision Profile 항목 중 'Pawn' 유형에 대한 Collision Response를 살펴보고, Static Mesh는 캐릭터의 Collision Profile 항목 중 'WorldStatic' 유형에 대한 Collision Response를 살펴봅니다. 결과적으로, 두 객체의 '충돌' 관련 상호작용은 가장 영향력이 적은 충돌 반응(Collision Response)을 선택하는데, 위 예제를 살펴보면 가장 영향력이 충돌 반응은 사용자 캐릭터의 Collsiion Profile 항목 중 'WolrdStatic' 유형에 대한 Collision Response = Overlap입니다.
6. 충돌 이벤트의 콜백 함수
void ATestCharacter::BeginPlay()
{
Super::BeginPlay();
// 콜백 함수 등록
GetCapsuleComponent()->OnComponentBeginOverlap.AddDynamic(this, "CapsuleBeginOverlap");
}
// 콜백 함수
void ATestCharacter::CapsuleBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
PrintLine();
// 충돌 이벤트 처리
}
Details
- [충돌 이벤트 콜백 함수] : Unreal은 충돌 컴포넌트의 충돌 이벤트 발생 시 호출되는 콜백 함수를 제공합니다.
- [동작 방식] : 충돌 컴포넌트에서 'Overlap' 혹은 'Block' 등의 최종 Collision Response가 발생하면, 이에 해당하는 콜백 함수를 호출합니다. 'Overlap' Collision Response가 발생하면, OnComponentBeginOverlap 콜백 함수가 호출되며, 'Block' Collision Response가 발생하면, OnComponentHit 콜백 함수가 호출됩니다.
- [주의할 점] : 동적 바인딩을 수행할 함수는 UFUNCTION()과 함께 선언해야 합니다.
#3. Collision Query
1. Collision Query
Details
- [개념] : Collision Query는 두 물체의 충돌 발생 시 두 물체의 ObjectType 혹은 Collision Response에 근거한 Collion Filtering의 결과를 반환합니다.
2. Collision Query 함수
Details
- Collision Query 함수는 그 종류가 다양하며, 상황에 맞는 적절한 Query 함수를 활용하는 것이 중요합니다.
3. LineTraceSingleByChannel
#include "Engine/World.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/Actor.h"
#include "DrawDebugHelpers.h"
void AMyActor::PerformLineTrace()
{
APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
if (!PlayerController) return;
FVector StartLocation;
FVector EndLocation;
FRotator PlayerViewRotation;
PlayerController->GetPlayerViewPoint(StartLocation, PlayerViewRotation);
EndLocation = StartLocation + (PlayerViewRotation.Vector() * 1000.0f);
FHitResult HitResult;
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(this);
if (GetWorld()->LineTraceSingleByChannel(HitResult, StartLocation, EndLocation, ECC_Visibility, CollisionParams))
{
UE_LOG(LogTemp, Warning, TEXT("Hit: %s"), *HitResult.GetActor()->GetName());
}
DrawDebugLine(GetWorld(), StartLocation, EndLocation, FColor::Red, false, 1, 0, 1);
}
Details
- [개념] : 'LineTraceSingleByChannel'은 Collision Channel 중 Trace Channel을 활용하는 Query 함수입니다. 따라서, 가상 환경에서 한 지점에서 다른 지점을 향해 '레이'라고 하는 가상의 선을 발사하고, 그 경로에서 첫 번째 'Block'이 발생하면 Raycast를 멈추고 충돌 결과를 반환합니다.
- [특징] : 'LineTraceSingleByChannel'은 "FCollisionResponseParams"을 인자로 전달받아 Collision Response를 결정하며, FHitResult 형식의 객체에 충돌 정보를 저장합니다.
- [예제] : 위 예제는 ObjectType이 Visibility인 Collision Channel을 통해 시작 지점과 도착 지점까지 충돌 검사를 진행합니다. 이때, 캐릭터 객체의 Collision Profile은 Object Type이 'Pawn'으로 설정되었으며, ObjectType이 Visibility인 Collision Channel에 대한 충돌 반응으로 'Overlap'을 수행하도록 설정되어 있습니다. 따라서, Raycast는 해당 객체를 통과해 계속 진행되며, 끝내 ObjectType이 WorldStatic이고, ObjectType이 Visibility인 Collision Channel에 대해 'Block' 충돌 반응을 수행토록 설정된 벽 객체를 만나서 FHitResult에 그 결과 값을 저장하고 Raycast를 멈춥니다.
4. LineTraceByProfile
#include "Engine/World.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/Actor.h"
#include "DrawDebugHelpers.h"
void AMyActor::PerformLineTrace()
{
APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
if (!PlayerController) return;
FVector StartLocation;
FVector EndLocation;
FRotator PlayerViewRotation;
PlayerController->GetPlayerViewPoint(StartLocation, PlayerViewRotation);
EndLocation = StartLocation + (PlayerViewRotation.Vector() * 1000.0f);
FHitResult HitResult;
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(this);
if (GetWorld()->LineTraceSingleByProfile(HitResult, StartLocation, EndLocation, TEXT("Custom_PlayerOnly), CollisionParams))
{
UE_LOG(LogTemp, Warning, TEXT("Hit: %s"), *HitResult.GetActor()->GetName());
}
DrawDebugLine(GetWorld(), StartLocation, EndLocation, FColor::Red, false, 1, 0, 1);
}
Details
- [개념] : 'LineTraceSingleByProfile '은 미리 설정한 "Collision Profile"을 활용하는 Query 함수입니다. 따라서, 가상 환경에서 한 지점에서 다른 지점을 향해 '레이'라고 하는 가상의 선을 발사하고, 그 경로에서 첫 번째 'Block'이 발생하면 Raycast를 멈추고 충돌 결과를 반환합니다.
5. LineTraceSingleByChannel vs LineTraceByProfile
- [차이점] : 'LineTraceSingleByChannel'과 'LineTraceByProfile'은 동일한 동작을 수행합니다. 하지만, LineTraceSingleByChannel은 Collision Channel을 활용하며, LineTraceByProfile은 Collision Profile을 활용합니다. 쉽게 말해, LineTraceSingleByChannel은 특정 Collision Channel을 기준으로 LineTrace를 수행하며, Ray가 감지하는 객체의 유형(ObjectType)을 결정합니다. 반면, LineTraceByProfile은 충돌 프로필을 기준으로 LineTrace를 수행하며, Ray가 감지하는 여러 충돌 채널의 조합을 미리 설정하고, 다양한 ObjectType에 대한 충돌 여부를 관리할 수 있습니다.
6. LineTraceSingleByObjectType
#include "Engine/World.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/Actor.h"
#include "DrawDebugHelpers.h"
void AMyActor::PerformLineTrace()
{
APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
if (!PlayerController) return;
FVector StartLocation;
FVector EndLocation;
FRotator PlayerViewRotation;
PlayerController->GetPlayerViewPoint(StartLocation, PlayerViewRotation);
EndLocation = StartLocation + (PlayerViewRotation.Vector() * 1000.0f);
FHitResult HitResult;
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(this);
FCollisionObjectQueryParams ObjectParams(ECollisionChannel::ECC_Pawn);
if (GetWorld()->LineTraceSingleByObjectType(HitResult, StartLocation, EndLocation, ObjectParams, CollisionParams))
{
UE_LOG(LogTemp, Warning, TEXT("Hit: %s"), *HitResult.GetActor()->GetName());
}
DrawDebugLine(GetWorld(), StartLocation, EndLocation, FColor::Red, false, 1, 0, 1);
}
Details
- [개념] : 'LineTraceSingleByObjectType'은 미리 설정한 Collision Profile을 활용하는 Query 함수입니다. 오직 ObjectType을 기준으로 Raycast를 수행하며, 해당 ObjectType을 가진 객체를 만나면 Raycast를 멈추고 충돌 결과를 반환합니다.
- [특징] : ' LineTraceSingleByObjectType '은 Raycast 경로에 있는 피 충돌 객체의 Collision Profile을 살펴보고 Collision Response를 통한 Filtering 과정이 생략됩니다.
- [예제] : ObjectType을 'Pawn'으로 설정한 Raycast가 ObjectType이 'Pawn'인 캐릭터 객체를 만나면 Raycast를 중단하고, 충돌 결과를 반환합니다.
7. LineTraceMultiByChannel
#include "Engine/World.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/Actor.h"
#include "DrawDebugHelpers.h"
void AMyActor::PerformMultiLineTrace()
{
APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
if (!PlayerController) return;
FVector StartLocation;
FVector EndLocation;
FRotator PlayerViewRotation;
PlayerController->GetPlayerViewPoint(StartLocation, PlayerViewRotation);
EndLocation = StartLocation + (PlayerViewRotation.Vector() * 1000.0f);
TArray<FHitResult> HitResults;
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(this);
if (GetWorld()->LineTraceMultiByChannel(HitResults, StartLocation, EndLocation, ECollisionChannel::ECC_Visibility, CollisionParams))
{
for (auto& Hit : HitResults)
{
UE_LOG(LogTemp, Warning, TEXT("Hit: %s"), *Hit.GetActor()->GetName());
}
}
DrawDebugLine(GetWorld(), StartLocation, EndLocation, FColor::Red, false, 1, 0, 1);
}
Details
- [개념] : 'LineTraceMultiByChannel'은 Collision Channel 중 Trace Channel을 활용하는 쿼리 함수입니다. 따라서, 가상 환경에서 한 지점에서 다른 지점을 향해 '레이'라고 하는 가상의 선을 발사하고, 그 경로에서 첫 번째 'Block'이 발생하면 Raycast를 멈추고 경로 상에서 발생한 'Overlap' 충돌 반응을 보여준 객체들에 대한 정보를 반환합니다.
- [특징] : ' LineTraceMultiByChannel'은 첫 번째 'Block'이 발생하면, 이전의 Raycast 경로 상에 존재하는 객체들 중 'Overlap' 충돌 반응을 보여준 두 개 이상의 객체들에 대한 정보를 반환합니다.
8. LineTraceTestByChannel/ObjectType/Profile
- [개념] : 'LineTraceTestBy...'는 선언한 내용에 따라서 그 동작 방식은 동일하지만, 결과 값을 True/False로만 반환합니다.
9. SweepSingleByChannel
#include "Engine/World.h"
#include "GameFramework/PlayerController.h"
#include "GameFramework/Actor.h"
#include "DrawDebugHelpers.h"
void AMyActor::PerformSweep()
{
APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
if (!PlayerController) return;
FVector StartLocation;
FVector EndLocation;
FRotator PlayerViewRotation;
PlayerController->GetPlayerViewPoint(StartLocation, PlayerViewRotation);
EndLocation = StartLocation + (PlayerViewRotation.Vector() * 1000.0f);
FHitResult HitResult;
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(this);
FCollisionShape MyCollShape = FCollisionShape::MakeSphere(50.0f);
if (GetWorld()->SweepSingleByChannel(HitResult, StartLocation, EndLocation, FQuat::Identity, ECollisionChannel::ECC_WorldDynamic, MyCollShape, CollisionParams))
{
UE_LOG(LogTemp, Warning, TEXT("Hit: %s"), *HitResult.GetActor()->GetName());
}
DrawDebugLine(GetWorld(), StartLocation, EndLocation, FColor::Red, false, 1, 0, 1);
}
Details
- [개념] : 'SweepSingleBy...'는 Ray 대신 Box, Capsule, 그리고 Sphere 등의 Shape을 활용하는 방법입니다.
#4. FCollisionResponseParams
1. FCollisionResponseParams
struct ENGINE_API FCollisionResponseParams
{
public:
enum EResponseType
{
ResponseFile, // 응답은 FCollisionResponseContainer에서 정의됩니다.
ResponseCustom // 응답은 사용자 정의입니다.
};
EResponseType ResponseType;
const struct FCollisionResponseContainer* ResponseToChannels;
// 생성자
FCollisionResponseParams(EResponseType InResponseType = ResponseFile)
: ResponseType(InResponseType)
, ResponseToChannels(NULL)
{
}
FCollisionResponseParams(const struct FCollisionResponseContainer& InResponseToChannels)
: ResponseType(ResponseCustom)
, ResponseToChannels(&InResponseToChannels)
{
}
};
Details
- [개념] : 'FCollisionResponseParams'는 충돌 응답을 설정하는 데 사용되는 구조체입니다.
2. 예제-1, IK를 위한 Trace 과정에서 해당 Character를 무시하는 방법
- [설명] : IK를 위한 Line Trace 과정에서 Ray와 해당 캐릭터 객체의 충돌은 무시해야 합니다. 따라서, FCollisionResponseParam의 Collision Response의 SetResponse() 메서드를 통해 ObjectType이 'Pawn'으로 설정된 객체는 무시하는 것으로 설정합니다.
3. 예제-2, Weapon과 Enemy 객체의 충돌
Details
- [설명] : 만약, Enemy 객체의 Collision Profile 내 Weapon Channel에 대한 Collision Response를 'Block'으로 설정했다면, 별도의 Collision Channel을 추가하는 대신 간단히 FCollisionResponseParams를 통해 ObjectType이 'Pawn'인 객체에 대한 충돌 반응을 'Overlap'으로 설정하여 Line Trace를 수행하면 됩니다!
#4. 예제
1. Custom Collision Channel
Details
- [예제-1] : 만약, 레벨 내 보이지 않는 벽이 사용자 캐릭터에 대해서 'Block' 충돌 반응을 설정한다면, 우리는 'PlayerOnly'라는 사용자 정의 Collision Channel을 활용할 수 있습니다. 이를 통해, 사용자 캐릭터와 같이 ObjectType이 'Pawn'인 적들은 이 벽을 통과할 수 있지만, 사용자 캐릭터는 통과할 수 없게 됩니다.
- [동작 방식]
- Custom Collision Channel을 생성하고, 이름은 'PlayerOnly' 그리고, Default Response(기본 충돌 반응)은 'Ignore'로 설정합니다.
- 벽 객체의 Collision Profile 내 ObjectType을 'PlayerOnly'로 설정하고, Preset 설정에서 'Pawn' ObjectType에 대한 충돌 반응을 'Block'으로 설정합니다. 그리고, 사용자 캐릭터의 캡슐 컴포넌트의 Collision Profile 내 ObjectType은 'Pawn'으로 설정하고, Preset 설정에서 'PlayerOnly' ObjectType에 대한 충돌 반응을 'Block'으로 설정합니다.
- ObjectType이 'Pawn'인 여타 다른 객체들은 Preset 설정 내 'PlayerOnly' ObjectType에 대한 충돌 반응을 'Overlap'으로 설정함으로써, 사용자 캐릭터만 통과할 수 없는 벽의 충돌 설정이 완료됩니다.
2. 카메라의 충돌 반응
Details
- [예제-2] : 몇몇 Geometry 객체들의 ObjectType이 'Camera'에 대한 충돌 반응을 'Overlap'으로 설정하여, 클리핑이 발생하는 것을 방지할 수 있습니다.
'게임개발 > Unreal C++' 카테고리의 다른 글
[Unreal]#27_Enhanced Input (2) | 2024.03.01 |
---|---|
[Unreal]#26_Game Ability System(GAS) (0) | 2024.02.23 |
[Unreal]#24_Deactivate와 DeactivateImmediate함수 (0) | 2023.04.16 |
[Unreal]#23_FString, FText, FName 변환 (0) | 2023.02.05 |
[Unreal]#22_TTuple (0) | 2023.02.05 |