Code Less, Create More!

Simple but useful code snippets for 3D Graphic Developers

Unreal Engine

Unreal Engine(C++)에서 Material을 로드하는 방법

데브엑스 2023. 3. 15. 06:53
반응형

머티리얼(Material: 재질)은 언리얼 엔진에서 장면을 렌더링할 때 필수적인 요소입니다. 머티리얼은 객체가 어떻게 Shading(음영 처리)되고 텍스처 매핑되어야 하는지를 정의하는, 언리얼 엔진 렌더링 파이프라인의 핵심 구성 요소입니다.

머티리얼은 보통 언리얼 엔진의 머티리얼 에디터를 사용하여 생성합니다. 머티리얼 에디터에서는 머티리얼의 속성을 정의하는 노드 네트워크를 시각적으로 구성하고 편집할 수 있습니다. 머티리얼이 생성되면 3D 장면을 구성하는 객체들의 메시 컴포넌트에 적용하여 사용할 수 있습니다.

언리얼 엔진에서는 C++을 사용해 프로그래밍으로 머티리얼을 불러오고 조작할 수 있습니다. 이를 통해 이벤트나 사용자 상호 작용에 따라 변경되는 동적인 머티리얼을 생성할 수 있습니다. 또한 객체 간에 머티리얼을 공유하여 메모리 사용량을 줄이고 성능을 향상시킬 수 있습니다.

그러나 언리얼 엔진에서 머티리얼을 불러올 때 객체 생성자에서 불러오는 것과 코드의 다른 부분에서 불러오는 것은 명확히 구분하되어야 합니다.

1. 객체 생성자에서 로드하기

ConstructorHelpers 클래스는 일반적으로 생성자 내에서 사용되며 객체의 생성 과정에서 컨텐츠 디렉터리에 저장된 Asset들을 메모리에 로드하는 기능을 제공합니다. 생성자 내에서 ConstructorHelpers를 사용하면, 객체가 생성될 때 Asset이나 객체가 메모리에 로드되어 바로 사용할 수 있게 됩니다.

아래는 객체 생성자 내부에서 머티리얼을 타입별로 구분해 로드하는 방법의 예시 코드입니다.

Material:

static FString Path = TEXT("/Game/Materials/M_overlay"); 
static ConstructorHelpers::FObjectFinder<UMaterial> Material(*Path); 
 
if (Material.Object == nullptr) 
{
    UE_LOG(LogTemp, Error, TEXT("Failed to load material at path: %s"), *Path);
}
UMaterial* MyMaterial = Material.Object;

Material Instance:

static FString Path = TEXT("/Game/Materials/M_overlay_inst");
static ConstructorHelpers::FObjectFinder<UMaterialInstance> MaterialInstance(*Path);

if (MaterialInstance.Object == nullptr)
{
    UE_LOG(LogTemp, Error, TEXT("Failed to load material at path: %s"), *Path);
}
UMaterialInstance* MyMaterialInstance = MaterialInstance.Object;

ConstructorHelpers::FObjectFinder를 생성자 내에서 사용하는 이유는 프로그램 실행중에 Asset이나 객체를 로드함으로써 발생하는 성능 문제를 피하기 위함입니다. 게임 플레이 도중에 Asset이나 객체를 로드하게 되면 눈에 띄는 지연이 발생할 수 있고, 게임 전체의 성능에 영향을 미칠 수도 있습니다. 이 때문에 객체 생성 과정에서 Asset이나 객체를 로드함으로써 이러한 성능 문제를 피하고 프로그램이 원활하게 실행되게 할 수 있습니다.

 

주의할 점:
ConstructorHelpers는 생성자에서 호출되면 메모리 및 객체 관리가 자동으로 처리되지만, 생성자가 아닌 곳에서 사용되면 에러를 발생시킵니다. 또한 Asset의 경로나 타입이 맞지 않을 경우 로딩이 실패하게 되므로 항상 결과값을 확인해 오류에 대비해야 합니다.

 

참고 링크:

https://docs.unrealengine.com/4.27/en-US/API/Runtime/CoreUObject/UObject/ConstructorHelpers/

 

ConstructorHelpers

 

docs.unrealengine.com

2. 실행중에 로드하기

StaticLoadObject는 프로젝트의 콘텐츠 디렉토리 내에서 특정 경로나 이름을 통해 객체를 로드할 수 있는 함수입니다. FObjectFinder와 달리 StaticLoadObject는 객체가 생성된 후에 프로그램의 실행 중에 객체를 로드하는 데 사용합니다.

Material classes in Unreal Engine

Material Instance:  

// Load the material asset during gameplay
FString Path = "/Game/Materials/M_overlay_inst";
UMaterialInstance* MyMaterialInstance = Cast<UMaterialInstance>(StaticLoadObject(UMaterialInterface::StaticClass(), this, *Path));

if (MyMaterialInstance == nullptr)
{
    UE_LOG(LogTemp, Error, TEXT("Failed to load material at path: %s"), *Path);
}

StaticLoadObject 함수의 주요 매개변수들로는 객체의 유형, 프로젝트 콘텐츠 디렉토리 내의 경로, 그리고 객체를 비동기로 로드할지 여부를 나타내는 플래그 등이 있습니다.

 

주의할 점:
StaticLoadObject는 생성자 내에서 사용되지 않기 때문에, 이 함수를 사용하여 로드한 객체가 적절하게 관리되고 필요하지 않을 때 해제되도록 하는 것이 중요합니다. 이렇게 하면 메모리 누수나 객체 관리가 제대로 이루어지지 않을 경우 발생할 수 있는 성능 문제를 방지할 수 있습니다.
StaticLoadObject의 두 번째 매개변수는 리소스의 소유자로, 객체의 생명주기를 관리하는 소유자를 의미합니다(예: this, GetOwner(), nullptr 등).

 

참고 링크:
https://docs.unrealengine.com/4.27/en-US/API/Runtime/CoreUObject/UObject/StaticLoadObject/

 

StaticLoadObject

Find or load an object by string name with optional outer and filename specifications.

docs.unrealengine.com

Material Instance Dynamic:

머티리얼 Asset에는 미리 정의된 머티리얼의 매개변수를 지정된 상태로 저장되어 있습니다. 프로그램 실행 중에 이를 변경하려면 아래와 같이 UMaterialInstanceDynamic 클래스를 생성해서 매개변수의 값을 변경할 수 있습니다.

// ... Continued.
// Material로 부터 동적 Material Instance를 생성
UMaterialInstanceDynamic* MyMaterialDynamic = UMaterialInstanceDynamic::Create(MyMaterialInstance, this);

// Material 객체의 'Color' 파라미터를 변경
MyMaterialDynamic->SetVectorParameterValue(TEXT("Color"), FLinearColor(0.0f, 1.0f, 0.0f));        
 
// Assign changed material to all mesh components of children.
TArray<USceneComponent*> ChildrenComponents;
RootComponent->GetChildrenComponents(true, ChildrenComponents);
for (auto child : ChildrenComponents)
{
    if (child->IsA(UMeshComponent::StaticClass()))
    {
        UMeshComponent* Mesh = Cast<UMeshComponent>(child);
        
        // UE 4
        Mesh->SetMaterial(0, MyMaterialDynamic);   		
        
        // UE 5 only
        Mesh->SetOverlayMaterial(MyMaterialDynamic);
    }
}

SetOverlayMaterial은 언리얼 엔진 5에서 도입된 메서드로 메시의 기본 머티리얼 위에 오버레이 되는 추가적인 머티리얼을 적용하는 기능입니다.

3. 머티리얼 인스턴스 객체의 유형

언리얼 엔진에서 사용되는 머티리얼 인스턴스의 종류는 다음과 같이 두 가지입니다:

UMaterialInstanceConstant (MIC) => 머티리얼 인스턴스 상수 ( == '머티리얼 인스턴스'로 부름)
UMaterialInstanceDynamic (MID) => 머티리얼 인스턴스 다이나믹

이 두 종류의 머티리얼 인스턴스는 머티리얼의 변형 (variation)을 생성할 수 있도록 해주는 점에서 비슷하지만, 아래와 같은 차이점들이 있습니다:

  • 컴파일: 머티리얼 인스턴스는 디자인 시에 생성되고 미리 컴파일되어 콘텐츠 디렉토리에 정적 에셋으로 저장됩니다. 반면, 머티리얼 인스턴스 다이나믹은 코드를 사용하여 즉시 생성 및 수정되고 런타임에 컴파일됩니다.
  • 커스터마이제이션: 머티리얼 인스턴스와 머티리얼 인스턴스 다이나믹 모두 머티리얼의 변형본으로 생성되고 커스터마이징될 수 있습니다. 그러나 머티리얼 인스턴스 다이나믹은 게임 플레이 중에 프로그래밍으로 수정할 수 있어 더 많은 커스터마이제이션 옵션을 제공합니다. 머티리얼 인스턴스의 경우는 디자인 시에 정의한 매개변수로 제한됩니다.
  • 성능: 머티리얼 인스턴스는 미리 컴파일되어 정적 에셋으로 저장되기 때문에 일반적으로 머티리얼 인스턴스 다이나믹보다 성능 효율이 높습니다. 머티리얼 인스턴스 다이나믹은 런타임에 컴파일되는 데, 특히 실행 중 머티리얼의 파라미터를 자주 변경할 경우 성능에 영향을 줄 수 있습니다.
  • 메모리 사용량: 머티리얼 인스턴스는 정적 에셋으로 저장되고 게임 전체에서 재사용할 수 있기 때문에 일반적으로 머티리얼 인스턴스 다이나믹보다 메모리 효율이 높습니다. 머티리얼 인스턴스 다이나믹은 실행 중에 생성 및 저장되기 때문에 메모리 사용량이 증가할 수 있습니다.
  • 사용 사례: 머티리얼 인스턴스는 색상 변경이나 텍스처 교체와 같이 파라미터를 미리 지정해서 머티리얼의 변형을 생성하는 데 주로 사용됩니다. 머티리얼 인스턴스 다이나믹은 애니메이션 또는 절차적 생성실행 중에 머티리얼의 외형을 변경해야 할 때 사용되는 경우가 많습니다.

보다 상세한 정보는 아래 링크를 참조하세요:
https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/MaterialInstances/

 

Instanced Materials

Hierarchical material relationships that allow modification of properties to alter behavior and appearance of child materials without shader recompilation.

docs.unrealengine.com

 

반응형