1. 언리얼 엔진에서 Object vs Actor 이해하기

  1. Object(UObject)의 개념
  • UObject는 언리얼 엔진에서 모든 클래스의 최상위 부모이다.
  • 스스로 월드(레벨)에 배치될 수 없다. 주로 데이터나 로직만 담당
    • 예: 플레이어 능력치(HP, 경험치), AI정보, 게임 설정 값 등
  • 화면에 보이지 않는 추상적인 부분을 처리하는 역할

  1. Actor(AActor)의 개념
  • AActor는 UObject를 확장(상속)한 클래스로, 월드에 배치 할 수 있다.
  • 위치(트랜스폼), 회전, 크기 등 공간적 정보를 가지고 있고, 여러 컴포넌트(메시, 파티클, 사운드 등)를 추가로 붙일 수 있다.
  • 실제 게임 세계에서 보이고 상호작용하는 캐릭터, 적 몬스터, 무기, 조명, 파티클 효과 등은 주로 AActor를 기반으로 제작한다.

2. 새로운 Actor 클래스 생성

언리얼 에디터에서 Actor 클래스를 public 으로 생성하게 되면 .h가 public 폴더에, .cpp가 private 폴더에 생긴다.

반대로 Actor클래스를 private으로 생성하게 되면 .h, .cpp 가 private 폴더에 생긴다.

Actor를 생성하고 에디터에서 월드에 배치하게 되면 3D 모델이 눈에 보이지 않는다. 그 이유는 3D 메시를 설정하지 않았기 때문이다. 3D 메시를 할당해주기 위해서는 Actor에 추가적인 Component를 붙여줘야 한다.


3. Actor 클래스에 컴포넌트 멤버 변수 추가

컴포넌트는 언리얼 엔진에서 Actor가 어떤 역할을 하거나 특정 속성을 갖도록 만들어주는 부품(파츠) 개념이다.

루트 컴포넌트와 Scene Component

  • 모든 Actor는 최상위 컴포넌트인 루트 컴포넌트(Root Component)를 가져야 한다.
  • Root Component는 액터의 트랜스폼 (위치, 회전, 크기)를 정의하며, 모든 하위 컴포넌트가 이를 기준으로 동작한다.
  • 일반적으로, Scene Component를 루트로 설정하여 액터의 트랜스폼을 관리하고, 그 아래에 다양한 컴포넌트를 계층적으로 붙인다.
    • Scene Component는 모든 트랜스폼 속성을 가지는 기본 컴포넌트이다.
    • Scene Component는 직접적인 시각적 출력(3D 모델, 빛 등)을 가지지 않지만, 다른 컴포넌트들의 계층적 트랜스폼을 정의하는 기준점 역할을 한다.
    • Scene Component를 루트로 설정하면, 다른 시각적 컴포넌트를 아래에 Attach하여 관리할 수 있다.

Static Mesh Component

  • 애니메이션 없이 움직임이 없거나 단순 이동, 회전만 하는 고정된(static) 3D 모델을 표시하는 컴포넌트이다.
    • 건물, 바위, 아이템, 환경 오브젝트 등 움직임이 없거나 단순한 오브젝트에 주로 사용
    • 3D 모델을 표현하고, 물리 충돌과 관련된 기능 제공

Static Mesh Component와 Scene Component 연결

  • Item.h 파일에서 다음과 같이 포인터 멤버 변수 추가
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"

UCLASS()
class SPARTAPROJECT_API AItem : public AActor
{
	GENERATED_BODY()
    
public:
	AItem();
    
protected:
	// 루트 컴포넌트를 나타내는 Scene Component 포인터
    USceneComponent* SceneRoot;
    // Static Mesh Component 포인터
    UStaticMeshComponent* StaticMeshComp;
};
  • Item.cpp
#include "Item.h"

AItem::AItem()
{
	// Scene Component를 생성하고 루트로 설정
    SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
    SetRootComponent(SceneRoot);
    
    // Static Mesh Component를 생성하고 Scene Component에 Attach
    StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
    StaticMeshComp->SetupAttachment(SceneRoot);
}

코드 분석

  • CreateDefaultSubobject<T>(TEXT(""))
    • Unreal Engine에서 컴포넌트를 생성하고 초기화할 때 사용하는 함수이다.
    • 템플릿 타입 <T> 로 생성할 컴포넌트의 유형을 지정한다.
    • "StaticMesh, "SceneRoot"는 각 컴포넌트의 식별 이름이 된다.
    • TEXT() 매크로는 문자열을 유니코드로 처리하기 위한 것으로, 언리얼 엔진 코드 표준에서 권장한다.
  • SetRootComponent(SceneRoot)
    • 루트 컴포넌트를 SceneRoot로 설정한다.
    • 루트 컴포넌트는 액터의 기본위치, 회전, 크기를 정의하며, 다른 모든 하위 컴포넌트가 이를 기준으로 동작한다.
  • SetupAttachment(SceneRoot)
    • StaticMeshCompSceneRoot에 부착한다.
    • StaticMeshCompSceneRoot의 하위 컴포넌트로 동작하며, SceneRoot의 트랜스폼 변화에 따라 움직인다.

4. Mesh & Material 할당하고 Actor 배치

Static Mesh Component의 주요 구성 요소

  • Static Mesh (스태틱 메시)
    • 3D 모델 (정적 메쉬 데이터)를 정의한다. 이는 모델 파일이며, 언리얼 엔진에서는 .uasset파일로 관리된다.
  • Material(머터리얼)
    • 메쉬의 표면 시각적 속성을 정의한다. 색상, 질감, 반사율, 투명도 등의 속성을 설정할 수 있다.
    • Static Mesh에는 여러 개의 머터리얼 슬롯이 있을 수 있다. 슬롯은 메쉬의 특정 부분에 다른 머터리얼을 적용할 수 있도록 한다.

Static Mesh 및 Material 설정

#include "Item.h"

AItem::AItem()
{
	// Scene Component를 생성하고 루트로 설정
    SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
    SetRootComponent(SceneRoot);
    
    // Static Mesh Component를 생성하고 Scene Component에 Attach
    StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
    StaticMeshComp->SetupAttachment(SceneRoot);
    
    // Static Mesh를 코드에서 설정
    static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Game/Resources/Props/SM_Chair.SM_Chair"));
    if (MeshAsset.Succeeded())
    {
    	StaticMeshComp->SetStaticMesh(MeshAsset.Object);
    }
    
    // Material을 코드에서 설정
    static ConstructorHelpers::FObjectFinder<UMaterial> MaterialAsset(TEXT("/Game/Resources/Materials/M_Metal_Gold.M_Metal_Gold"));
    if (MaterialAsset.Succeeded())
    {
    	StaticMeshComp->SetMaterial(0, MaterialAsset.Object);
    }
}

코드 분석

  • ConstructorHelpers::FObjectFinder<T>

    • Unreal Engine에서 특정 리소스를 경로 기반으로 로드하는 클래스이다.
  • TEXT("/Game/Resources/Props/SM_Chair.SM_Chair")

    • 리소스의 경로를 나타낸다. 리소스의 경로를 가져오려면 아래와 같이 해당하는 에셋을 우클릭하고 Copy Refernece를 해서 붙여넣기를 한다.

    • /Game 여기서부터만 입력하면 되고, 앞의 경로는 삭제를 해준다.

    • /Game은 Unreal Engine에서 프로젝트의 Content 폴더를 나타낸다.

  • .Succeeded()

    • 지정된 경로에서 리소스를 성공적으로 찾았는지 확인한다.
    • 경로가 잘못되었거나 리소스 파일이 누락된 경우 실패하며, 이후 설정 함수가 호출되지 못한다.
  • SetStaticMesh(), SetMaterial()

    • 성공적으로 로드된 Static Mesh를 StaticMeshComp에 설정한다.
    • 로드된 Material을 StaticMeshComp의 특정 머터리얼 슬롯에 적용한다. 위의 예제에서는 첫번째 슬롯(Index 0)에 Material이 설정되었다.

5. 회고

C++로 액터를 배치하고 실제 3D모델을 화면에 나타낼 수 있도록 배울 수 있어서 좋았다. 실체화를 위해서는 액터에 컴포넌트를 생성하고 root component를 지정해주는것. 그래야만 transform이 가능하다는 것 까지 원리를 이해하고 코드로 구현까지 가능하게 되었다.
하지만 오늘 배운 점에서도 문제점이 있다면 머터리얼과 스태틱메시를 지정하는데 있어 중간에 파일경로가 바뀌면 재사용이 매우 좋지 않다는 점이다. 특히 여러 클래스가 같은 스태틱메시나 머터리얼을 사용하고 있을 때, 파일경로가 바뀐다면 일일이 찾아가서 경로지정한 코드를 수정해주어야만 한다. 그래서 경로를 동적으로 추적하는 Asset Manager나 데이터테이블을 이용해서 경로를 지정하는 방법이 있다는데 이번에 배운걸 제대로 체득하고 나면 자세히 알아보아야 겠다.

profile
Unreal 1기

0개의 댓글

Powered by GraphCDN, the GraphQL CDN