나중에도 쓸일이 있을 것 같아서 남겨둠
- UPrimitiveComponent 의 delegate인 OnBeingOverlap, OnEndOverlap 과 같은 Dynamic Delegate에는 AddDynamic 으로 함수를 바인딩 할 수 있다.
바인딩 되는 함수가 UFUNCTION() 이어야 하며, 블루프린트에서 노출할 수도 있다.
// Volume에서 Overlap Event 가 발생하면, OnVolumeOverlap을 호출한다. AMyPostProcessVolume::AMyPostProcessVolume(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { GetBrushComponent()->OnComponentBeginOverlap.AddDynamic(this, &AMyPostProcessVolume::OnVolumeOverlap); }
Game Delegate 에 바인딩 하고 싶을 때는 AddDynamic 대신 AddRaw, AddUObject, AddStatic 등을 사용해서 바인딩 할 수 있다.
- AddStatic : 멤버 함수 아닌 정적 함수를 바인딩 할 때 사용
- AddRaw : UObject 파생 클래스가 아닌 C++ 클래스에 사용.
사용하고자 하는 Delegate와 같은 시그니처를 가진 함수를 정의한 후, 이 함수를 바인딩한다. - AddLambda : 괄호 안의 람다를 바인딩 해 준다.
OnViewTargetChanged
특정 카메라가 뷰 타겟으로 플레이어 카메라에 적용되었을 때만 수행하고 싶은 동작이 있다고 하자.
View Target 이 바뀌는 타이밍을 알 수 있다면, 이 카메라를 사용할 때만 월드에서 특정 동작을 수행하고, 뷰타겟에서 빠져나갈 때는 이전 상태로 복구할 수 있다.
UE5 엔진 코드 중 NiagaraWorldManager.cpp 에는 다음과 같은 코드가 있다.
ViewTargetChangedHandle = FGameDelegates::Get().GetViewTargetChangedDelegate().AddLambda(
[](APlayerController* PC, AActor* OldTarget, AActor* NewTarget)
{
OnRefreshOwnerAllowsScalability();
}
);
}
그 헤더 파일에서는 ViewTargetChangedHandle을 아래와 같이 선언하였다.
static FDelegateHandle ViewTargetChangedHandle;
위 코드를 참고했을 때, ViewTarget이 변경되면 AddLambda() 안의 람다식을 실행하도록 하려면 아래와 같이 작성하면 된다는 것을 알 수 있었다.
FGameDelegates::Get().GetViewTargetChangedDelegate().AddLambda( /^...^/ );
게임 내에서 카메라 등이 뷰 타겟으로 활성회되었을 때만 수행하고 싶은 동작이 있을 때 유용하다.
(Delegate를 통해 OldViewTarget, NewViewTarget을 모두 Actor 형태로 전달받을 수 있다)
// in PlayerCameraManager.cpp
FGameDelegates::Get().GetViewTargetChangedDelegate().Broadcast(PCOwner, OldViewTarget, NewTarget);
그런데 CineCameraActor에서는 OnBecomeViewTarget, OnEndViewTarget 함수를 블루프린트에서 확장해서 사용할 수 있도록 제공하고 있다.
CineCameraActor 클래스를 상속받은 BP에서 아래 이벤트를 꺼낼 수 있다.
이 부분들은 블루프린트에서 접근할 용도로 만들어 진 것으로 보이기 때문에, 위에서 본 Delegate를 사용하는 방법은 수행하려는 동작을 반드시 C++ 로 구현해야 하는 경우에 사용할 수 있을 듯 하다.
OnFeatureLevelChanged
엔진 코드 중 SCascadePreviewViewport.cpp 에서는 아래와 같은 코드를 볼 수 있다.
UEditorEngine* Editor = (UEditorEngine*)GEngine;
PreviewFeatureLevelChangedHandle = Editor->OnPreviewFeatureLevelChanged().AddLambda([this](ERHIFeatureLevel::Type NewFeatureLevel)
{
if(ViewportClient.IsValid())
{
UWorld* World = ViewportClient->GetPreviewScene().GetWorld();
if (World != nullptr)
{
World->ChangeFeatureLevel(NewFeatureLevel);
}
}
});
에디터에서 FeatureLevel이 바뀌었을 때 (내 경우에는 주로 SM6 ↔ ES3.1)를 알고, 바뀐 FeatureLevel을 넘겨받을 수 있다.
넘겨받은 FRHIFeatureLevel 목록은 아래 RHIFeatureLevel.h 에서 확인할 수 있다.
enum Type : int
{
/** Feature level defined by the core capabilities of OpenGL ES2. Deprecated */
ES2_REMOVED,
/** Feature level defined by the core capabilities of OpenGL ES3.1 & Metal/Vulkan. */
ES3_1,
/**
* Feature level defined by the capabilities of DX10 Shader Model 4.
* SUPPORT FOR THIS FEATURE LEVEL HAS BEEN ENTIRELY REMOVED.
*/
SM4_REMOVED,
/**
* Feature level defined by the capabilities of DX11 Shader Model 5.
* Compute shaders with shared memory, group sync, UAV writes, integer atomics
* Indirect drawing
* Pixel shaders with UAV writes
* Cubemap arrays
* Read-only depth or stencil views (eg read depth buffer as SRV while depth test and stencil write)
* Tessellation is not considered part of Feature Level SM5 and has a separate capability flag.
*/
SM5,
/**
* Feature level defined by the capabilities of DirectX 12 hardware feature level 12_2 with Shader Model 6.5
* Raytracing Tier 1.1
* Mesh and Amplification shaders
* Variable rate shading
* Sampler feedback
* Resource binding tier 3
*/
SM6,
Num
};
Delegate 와 상관없이 현재 월드의 FeatureLevel을 얻고 싶으면 World 에서 FeatureLevel을 읽어오면 된다.
에디터 상태이거나 아직 에디터가 켜지기 전, Construction 단계에서 에디터의 FeatureLevel 상태를 얻고 싶으면
Editor 참조에서 DefautlWorldFeatureLevel 을 받아올 수 있다.
(이 부분은 에디터에서만 사용되는 코드이기 때문에 #if WITH_EDITOR 로 감싸주었다)
// 현재 월드의 FeatureLevel을 얻는다.
GetWorld()→GetFeatureLevel();
// 월드가 없을 때 (인게임 상황이 아닐 때), 에디터에서 활성화된 FeatureLevel을 얻는다.
// 생성자에서 GetWorld()로 월드를 참조하려고 시도하면 에러가 발생한다.
int CurrentFeatureLevel = Editor->DefaultWorldFeatureLevel;
이 Delegate를 이용하면, 모바일, PC 각 플랫폼마다 다르게 동작해야 하는 요소들 (포스트 프로세스 볼륨, 각 플랫폼별 별도 라이트 셋팅 등)을 각 상태를 에디터 상태에서 전환하도록 할 수 있다.
덧붙임
위에서 사용한 Editor 는 UEditorEngine 클래스 인스턴스를 참조한다. 이 클래스는 Editor/EditorEngine.h 에 포함되어 있다.
위 경우에는 cpp 파일에서만 사용하고 있기 때문에, 헤더 파일이 아닌 cpp 파일에서 include 해 준다.
그렇게 해야 이 클래스의 헤더 파일을 include 하고 있는 다른 클래스에 영향을 주지 않고, 컴파일 시간이 늘어나는 일도 피할 수 있다.
만약 헤더 파일에서 변수 선언할 때 이것을 사용해야 한다면, 컴파일 에러 방지를 위해 전방선언으로 클래스 이름만 명시해 준다.
https://lykanstudio.tistory.com/16
'Unreal Engine' 카테고리의 다른 글
3dsMax Spline -> Unreal Engine Spline 으로 Export (0) | 2024.11.30 |
---|---|
Iridescent Material in UE5 (0) | 2024.08.26 |
Two-Sided Foliage Shading Model in Unreal Engine (1) | 2024.07.01 |
Subsurface Shading Model in Unreal Engine (0) | 2024.06.30 |
Subsurface Profile Shading Model in Unreal Engine (1) | 2024.05.12 |