Components 란?

컴포넌트는 액터(Actor) 내에서 서브 오브젝트(Sub Object)로 사용되도록 만들어진 특수한 유형의 UObject 이다.
보통 쉽게 교체할 수 있는 부품의 형태로써, 컴포넌트를 갖고있는 액터의 특정 함수성이나 행위를 바꾸고자 할 때 사용된다.
예를들면 자동차의 이동방식은 비행기나 배와 다르지만, 셋 모두 운송 수단이라는 것에서는 변함이 없는 공통성을 갖고있다. 자동차는 핸들, 비행기는 플라이트 스틱, 배는 조타를 돌리듯이 컴포넌트를 사용하여 그 이동 제어 방식의 특수성을 부여하는 것으로 이해하면 편하다.
일반적인 서브 오브젝트의 기본적인 행위와는 반대로, 컴포넌트는 액터 안에 서브-오브젝트로 생성되는 컴포넌트가 인스턴싱될 때, 특정 클래스의 각 액터 인스턴스는 자체적으로 컴포넌트의 고유 인스턴스를 갖는다.
예를 들어 비행기의 엔진들의 종류를 생각해보면 팬으로 돌아가는 엔진과 제트 엔진이 있을 것이다.
만약 우리가 팬으로 돌아가는 엔진을 가진 비행기를 10대 소환했다고 가정하고 컴포넌트들이 각 액터마다 고유 인스턴스를 갖지 않는다면, 하나의 비행기의 엔진만 가동하더라도, 10대의 비행기가 팬으로 돌아가는 앤진을 돌리고 있을 것이다.
이렇게 기본적인 컴포넌트 인스턴싱 덕분에 액터에 고유한 서브 오브젝트를 빠르게 추가하는 프로세스가 단순화 될 수 있어 아주 편하다.
액터 컴포넌트(Actor Components)
액터 컴포넌트는 다양한 유형의 엑터에 추가시킬 수 있으며, 재사용가능한 기능을 정의하는 컴포넌트에 대한 베이스 클래스이다.
이들은 일반적으로 지오메트리에 액터를 연관시키는데 사용되는데, 예를들면 충돌이나 화면상에 렌더링된 메시 의 형태나, 액터의 월드 이동 방식을 제어하거나, 액터에서의 소리재생, 빛과 그림자를 드리우는 기능 등등 다양한 기능을 지원한다.
사실 플레이어가 게임을 플레이할 때, 월드에서 보고 듣고 상호작용하는 모든 것들은 결국 한가지 이상의 액터 컴포넌트들의 조합으로 만들어진 결과물들이다.
언리얼 엔진에서는 트랜스폼을 가진 액터 컴포넌트를 씬 컴포넌트(Scene Component) 라고 하며, 렌더링 가능한 것은 (Primitive Component) 라고 한다.
액터 컴포넌트 등록 ( Register Actor Components)
액터 컴포넌드가 매 프레임마다 틱(Tick)을 돌며 업데이트해서 씬(Scene)에 영향을 끼치도록 하려면, 씬에 등록시켜야 한다.
액터 컴포넌트의 등록은 아래의 함수를 호출하여 이루어진다.
void UActorComponent::RegisterComponent()
이 함수는 UActorComponent::RegisterComponentWithScene()를 호출해서 소유중인 액터의 Components[] 배열에 액터 컴포넌트가 들어있는지 확인한다. 배열에 대한 확인이 끝나면 씬에 연관시킨 다음, 액터 컴포넌트에 대한 렌더 프록시 (Render Proxy)와 피직스 스테이트 (Physics State)를 만든다.
액터 컴포넌트는 서브 오브젝트로 생성되고 액터의 default properties 안에 있는 Components[] 배열에 추가되면, 붙어있는 액터가 스폰될 때 자동으로 등록된다.
런타임에 UActorComponent::RegisterComponent()를 호출해 언제든 등록시킬 수 있지만, 수동 컴포넌트 등록은 조금 무거운 작업이라 필요할 때에만 사용해야한다.
컴포넌트가 등록될 때, 세 가지의 이벤트가 발동된다.
UActorComponent::OnRegister() | 컴포넌트 등록시 필요에 따라 추가적인 초기화를 가능하게 함 |
UActorComponent::CreateRenderState() | 컴포넌트에 대한 렌더 스테이트를 초기화 |
UActorComponent::OnCreatePhysicsState() | 컴포넌트에 대한 피직스 스테이트를 초기화 |
컴포넌트 등록해제 (UnRegister Actor Components)
컴포넌트가 등록해제될 때 또한 세 가지의 이벤트가 발동된다.
UActorComponent::OnUnRegister() | 컴포넌트 등록해제시 필요에 따라 추가적인 작업을 가능하게 함 |
UActorComponent::DestroyRenderState() | 컴포넌트에 대한 렌더 스테이트를 소멸 |
UActorComponent::OnDestroyPhysicsState() | 컴포넌트에 대한 피직스 스테이트를 소멸 |
컴포넌트 업데이트 (Updating Actor Components)
액터 컴포넌트에는 TickComponent() 함수를 통해 매 프레임마다 컴포넌트를 업데이트할 수 있는 기능이 있다.
이를 통해서 컴포넌트가 프레임별 계산을 할 수 있게 된다.
예를 들어 SkeletalMeshComponent는 애니메이션과 스켈레탈 컨트롤러를 업데이트하는데 TickComponent()를 사용하는 반면, ParticleSystemComponent는 시스템의 이미터를 업데이트하고 처리할 파티클 이벤트 검사에 사용한다.
컴포넌트가 업데이트되려면, 컴포넌트가 등록되어있어야 하고, 틱이 돌 수 있도록 PrimaryComponentTick.bCanEverTick=true로 설정해야한다. 마지막으로 틱 함수인 TickComponent를 셋업해주어야 한다.
액터 컴포넌트에 대한 틱 함수 예제는 아래와 같다.
void UMyActorComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// ...
}
렌더 스테이트 (Render State)
액터 컴포넌트가 렌더링되도록 하려면 렌더 스테이트가 생성되어 있어야 한다.
액터 컴포넌트의 렌더 스테이트는 컴포넌트의 렌더 데이터 업데이트가 필요할 만큼 변화가 있었는지 엔진에 알려주기도 한다. 만약 변화가 생기면 렌더 스테이트에 더티 마킹(Dirty Marking)이 되어 프레임이 끝날 때, 모든 더티 컴포넌트의 렌더 데이터를 업데이트시킨다.
피직스 스테이트 (Physics State)
액터 컴포넌트가 물리 엔진을 사용하여 시뮬레이션 되도록 하려면, 피직스 스테이트가 생성되어 있어야 한다. 렌더 스테이트와는 다르게 피직스 스테이트는 변화가 발생하는 즉시 업데이트되기 때문에 더티 마킹될일이 없다.
씬 컴포넌트 (Scene Components)
씬 컴포넌트는 액터 컴포넌트에 트렌스폼 (Transform) 정보를 추가시켜 확장한 컴포넌트이다. 트렌스폼이 추가되었기 때문에 씬 컴포넌트는 씬에 배치하거나 서로 붙이거나(Attach) 할 수 있다.
어태치먼트 (Attachment)
어태치먼트는 컴포넌트 수준에서 처리되며, 오직 씬 컴포넌트들 끼리만 붙일 수 있다. 씬 컴포넌트에는 AttachParent 프로퍼티가 있어서, 어느 컴포넌트에 붙었는지도 알 수 있다.
븥이려는 액터의 루트 컴포넌트가 SceneComponent를 베이스로 해야만 붙일 수 있는데 그 이유는 각 컴포넌트의 부모는 딱 하나뿐이라 붙은 컴포넌트가 붙이려는 액터의 루트 컴포넌트가 아닐 경우, 해당 컴포넌트와 자손 컴포넌트는 붙게될 유일한 컴포넌트가 되어버린다. 루트 컴포넌트는 전체적으로 액터처럼 붙지도 영향받지도 않은채 남아있게 되는데, 액터가 루트 컴포넌트와 그 트렌스폼에 의존하기 때문이다.
컴포넌트 트렌스폼(Component Transform)
FTransform 구조체에는 Translation 벡터, Rotation 쿼터니언, Scale3D 벡터가 들어있다.
각 씬 컴포넌트 자체에는 보통 내부용으로 쓰이는 FTransform이 있어서 월드 기준 위치와 방향 그리고 크기를 저장한다.
기본적으로 RelativeLocation, RelativeRotation, RelativeScale3D 처럼 상대적인 값들은 그 AttachParent를 기준으로 한다.
bAbsoluteLocation, bAbsoluteRotation, bAbsoluteScale 프로퍼티를 사용하면 이 값의 기준을 월드로 강제시킬 수 있다. 이 옵션들을 참으로 설정하면 그 프로퍼티는 월드를 기준으로 하게된다.
부모를 기준으로 해서 트렌스폼 값을 사용할 때 절대 월드값을 사용해서 Translation과 Rotation을 설정할수도 있다.
SceneComponent::SetWorldLocation() | 이 컴포넌트를 월드 스페이스 내 지정된 위치에 놓도록 상대 트랜슬레이션을 설정 |
SceneComponent::SetWorldRotation() | 이 컴포넌트를 월드 스페이스 내 지정된 방향으로 놓도록 상대 로테이션을 설정 |
프리미티브 컴포넌트 (Primitive Components)
프리미티브 컴포넌트는 보통 콜리전 데이터로 사용되거나 렌더링되는 지오메트리 유형을 생성하거나 담는 씬 컴포넌트 (Scene Component)이다.
씬 프록시 (Scene Proxy)
프리미티브 컴포넌트의 씬 프록시는 FPrimitiveSceneProxy 인스턴스로, 프리미티브 렌더링을 게임 스레드와 병행시키기 위해 미러링되는 씬 데이터를 캡슐화 한 것이다.
각 프리미티브 유형마다 FPrimitiveSceneProxy의 서브 크래스를 생성하며, 해당되는 프리미티브 유형을 렌더링하는데 필요한 렌더 데이터를 담는다.
좋은 글 진심으로 감사합니다! 언리얼 엔진을 공부 중인데 개념이 너무 복잡하고 많아서 헤매던 차였어요. 덕분에 컴포넌트에 대해 좀 더 이해할 수 있었습니다 ^_^