애셋 참조

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;
}
Select Skin
Light
Dark

Welcome to the new Unreal Engine 4 Documentation site!

We're working on lots of new features including a feedback system so you can tell us how we are doing. It's not quite ready for use in the wild yet, so head over to the Documentation Feedback forum to tell us about this page or call out any issues you are encountering in the meantime.

We'll be sure to let you know when the new system is up and running.

Post Feedback