애셋 참조

Choose your operating system:

Windows

macOS

Linux

언리얼 엔진 4 에는 애셋 참조 방식과 메모리에 로드되는 익스텐션을 통해 제어할 수 있는 메커니즘이 다수 제공됩니다. 레퍼런스는 두 가지 방식으로 생각해 볼 수 있는데, 하나는 오브젝트 A 가 오브젝트 B 를 참조하여 오브젝트 A 로드시 오브젝트 B 가 로드되게 만드는 강 참조, 오브젝트 경로같은 문자열 형태의 간접 메커니즘을 통해 오브젝트 A 가 오브젝트 B 를 참조하게 만드는 약 참조이 있습니다. 먼저 강 참조에 대해 다룬 뒤 나머지 부분에서 약 참조을 알아보도록 하겠습니다.

직접 프로퍼티 참조

애셋 참조의 가장 흔한 경우로, UPROPERTY 매크로를 통해 노출됩니다. 게임플레이 클래스에는 UPROPERTY 를 노출시키면 디자이너가 특정 애셋에 블루프린트 상속을 통해서 또는 월드에 배치한 인스턴스를 통해서 아키타입을 지정합니다. 예를 들어 아래 코드는 StrategyGame 샘플에 들어있는 AStrategyBuilding 에서 따온 것으로, 디자이너가 한 유형 건물을 지을 때 재생할 소리를 선택할 수 있습니다.

/** construction start sound stinger */

UPROPERTY(EditDefaultsOnly, Category=Building)

USoundCue* ConstructionStartStinger;

이 프로퍼티는 한 오브젝트의 디폴트 프로퍼티 일부로서만 설정 가능합니다 (EditDefaultsOnly 키워드로 제어합니다). 디자이너는 AStrategyBuilding 에서 확장되는 블루프린트 클래스를 새로 만듭니다. 그런 다음 디자이너가 원하는 사운드를 그 블루프린트용으로 저장 가능합니다. 디자이너가 만든 블루프린트가 로드될 때마다, UPROPERTY 의 일부로 참조되는 사운드 역시 자동으로 로드됩니다.

생성 시간 참조

강 참조의 두 번째 유형은, 주어진 프로퍼티에 대해 로드해야 하는 애셋을 프로그래머가 정확히 알고 있어, 그 프로퍼티를 오브젝트의 생성시 일부분으로 설정하는 경우입니다. 여기에는 ConstructorHelpers 라는 특수 클래스가 사용되는데, 생성 단계 도중 오브젝트와 오브젝트의 클래스를 찾는 것입니다. StrategyGame 샘플에서 다시 한 번, HUD 렌더링시 같이 포함시킬 애셋을 할당하는 스니펫입니다.

/** gray health bar texture */

UPROPERTY()

class UTexture2D* BarFillTexture;

AStrategyHUD::AStrategyHUD(const FObjectInitializer& ObjectInitializer) :
    Super(ObjectInitializer)
{
    static ConstructorHelpers::FObjectFinder<UTexture2D> BarFillObj(TEXT("/Game/UI/HUD/BarFill"));

    ...

    BarFillTexture = BarFillObj.Object;

    ...

}

위 생성자에서 ConstructorHelpers 클래스는 메모리에서 애셋을 찾아본 다음, 없으면 로드합니다. 로드할 것을 지정하는 데 애셋에 대한 전체 경로가 쓰인 것이 보입니다. 애셋이 존재하지 않거나 오류로 인해 로드할 수 없는 경우, 프로퍼티는 nullptr 로 설정됩니다. 그런 일이 발생하면, 텍스처를 접근하려는 코드는 크래시가 납니다. 어서트를 통해 애셋을 제대로 로드시켜 나중의 코드에서 레퍼런스가 유효하다 간주할 수 있도록 합니다.

UPROPERTY 선언은 이전의 강 레퍼런스 예제에서도 똑같이 나타납니다. 초기 설정 부분만 빼면 동일한 방식으로 작동합니다. 강 참조에 대해 한 가지 고려할 점은, 오브젝트가 로드 및 초기화되면 강 참조된 애셋도 로드된다는 점입니다. 세심히 주의를 기울이지 않으면 다수의 애셋이 한꺼번에 로드되어 메모리가 눈덩이처럼 불어날 것입니다. 그 로딩을 유예시키고 실행시간에 로드할 부분을 결정하고자 한다면, 다음 부분이 도움이 될 것입니다.

간접 프로퍼티 참조

애셋 로드 시점을 쉽게 제어할 수 있는 방법은 TSoftObjectPtr 을 사용하는 것입니다. 디자이너의 경우, 직접 프로퍼티 레퍼런스인 것처럼 작업할 수 있습니다. 하지만 직접 포인터 레퍼런스 대신, 애셋의 로드 여부에 대한 안전 검사가 가능한 템플릿 코드와 함께 프로퍼티가 스트링으로 저장됩니다. 참고로 TSoftObjectPtr 을 사용하려면 애셋을 수동으로 로드해야 합니다. 템플릿으로 된 LoadObject<>() 메서드나 StaticLoadObject() 나 FStreamingManager 를 사용하여 오브젝트를 로드할 수 있습니다 (상세 정보는 비동기 애셋 로딩 문서를 참고하세요). 처음 두 메서드는 애셋을 동기식으로 로드하여 프레임 속도가 출렁일 수 있으니, 게임플레이에 영향을 끼치지 않을 것이 확실한 것에만 사용해야 합니다.

UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category=Building)
TSoftObjectPtr<UStaticMesh> BaseMesh;

UStaticMesh* GetLazyLoadedMesh()
{
    if (BaseMesh.IsPending())
    {
        const FSoftObjectPath& AssetRef = BaseMesh.ToStringReference();
        BaseMesh = Cast< UStaticMesh>(Streamable.SynchronousLoad(AssetRef));
    }
    return BaseMesh.Get();
}

위 코드는 UStaticMesh 의 TSoftObjectPtr 을 사용하여 실행시간에 메시를 지연시켜 로드하고 있습니다. 애셋은 오브젝트의 로드 여부를 검사합니다. 로드되지 않은 경우, FStreamingManager 를 사용한 동기성 로드가 일어납니다. 아니면 TSoftObjectPtr 안의 UStaticMesh 포인터가 호출자에게 반환됩니다.

UClass 를 유예식으로 로드하려는 경우, TAssetSubclassOf 템플릿 유형 클래스 전용 버전을 대체하여 TSoftClassPtr 과 같은 접근법을 사용할 수 있습니다. 이 함수는 지정된 애셋을 참조하는 것과 같은 역할을 하지만, 인스턴스 대신 애셋에 대한 UClass 를 참조합니다.

오브젝트 검색/로드

지금까지의 예제는 모두 UPROPERTY 기반이었습니다. 하지만 실행시간에 스트링을 만들어 그 오브젝트로의 레퍼런스를 구하려면 어떻게 해야 할까요? 두 가지 방법이 있습니다. 이미 생성 또는 로드된 UObject 만 사용하려는 경우, FindObject<>() 가 맞습니다. 이미 로드되어 있지 않은 오브젝트를 로드하려면, LoadObject<>() 가 맞습니다. 참고로 LoadObject<>() 는 내부적으로 FindObject 와 동일한 역할을 하므로, 오브젝트를 먼저 검색한 다음 로드할 필요가 없습니다. 각 함수의 사용 예는 다음과 같습니다.

AFunctionalTest* TestToRun = FindObject<AFunctionalTest>(TestsOuter, *TestName);
GridTexture = LoadObject<UTexture2D>(NULL, TEXT("/Engine/EngineMaterials/DefaultWhiteGrid.DefaultWhiteGrid"), NULL, LOAD_None, NULL);

UClass 로드시 사용할 수 있는 전문 LoadObject 가 있습니다. 클래스를 로드와 그 유형을 자동 검증을 더욱 쉽게 할 수 있는 방법입니다. 아래 코드 스니펫으로 확인해 볼 수 있습니다.

DefaultPreviewPawnClass = LoadClass<APawn>(NULL, *PreviewPawnName, NULL, LOAD_None, NULL);

위는 다음과 같습니다.

DefaultPreviewPawnClass = LoadObject<UClass>(NULL, *PreviewPawnName, NULL, LOAD_None, NULL);

if (!DefaultPreviewPawnClass->IsChildOf(APawn::StaticClass()))
{
    DefaultPreviewPawnClass = nullptr;
}
언리얼 엔진 문서의 미래를 함께 만들어주세요! 더 나은 서비스를 제공할 수 있도록 문서 사용에 대한 피드백을 주세요.
설문조사에 참여해 주세요
건너뛰기