https://dev.epicgames.com/documentation/ko-kr/unreal-engine/sparse-class-data-in-unreal-engine?application_version=5.3
- 자주 사용되는 Actor Type의 주복 데이터를 제거하여 Memory를 절약
- 제공하는 기능
- Memory에 Property의 사본을 단 하나만 존재하도록 유지
- Designer가 BP Graph에서 Property 값에 Access하고 Class Default에서 편집 가능
- 사용을 권장하는 경우
- In-Game에서 동시에 여러 개의 Instance를 가지는 Actor Class의 Property
- 상당한 Memory가 중복된 사본에 사용되고 있음을 의미한다.
- 배치된 Actor Instance를 변경하지 않는 Property
- Actor Instance가 값을 override하지 않아 EditInstanceOnly나 EditAnywhere 지정자가 필요하지 않는 경우
- C++ 코드로 수정되지 않는 Property
- 직접 Access하는 모든 C++ 코드는 접근자 함수에 대한 호출로 대체 되어야 한다.
- Sparse Class Data를 사용하기 위해서는 Native C++ 코드가 필요하다.
예제
-
더보기
USTRUCT(BlueprintType)
struct FMySparseClassData
{
GENERATED_BODY()
FMySparseClassData()
: MyFloatProperty(0.f)
, MyIntProperty(0)
, MyNameProperty(NAME_None)
{ }
// 에디터에서 이 프로퍼티의 디폴트값을 세팅할 수 있습니다.
// 블루프린트 그래프에서는 액세스할 수 없습니다.
UPROPERTY(EditDefaultsOnly)
float MyFloatProperty;
// 이 프로퍼티의 값은 C++ 코드로 설정됩니다.
// 블루프린트 그래프에서 액세스할 수 있습니다(변경은 불가능함).
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
int32 MyIntProperty;
// 에디터에서 이 프로퍼티의 디폴트값을 세팅할 수 있습니다.
// 블루프린트 그래프에서 액세스할 수 있습니다(변경은 불가능함).
// 'GetByRef'는 블루프린트 그래프가 사본 대신 const 참조에 액세스함을 의미합니다.
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(GetByRef))
FName MyNameProperty;
};
- EditAnywhere, EditInstanceOnly, BlueprintReadWrite가 Tag된 Property 대상으로는 작업할 수 없다
- Sparse Class Data를 포함하는 Struct는 USTRUCT(BlueprintType) 지정자가 선언되어 있어야 한다.
- 각 Property는 반드시 EditDefaultsOnly 지정자를 포함해야 한다.
- 별도의 Category가 없는 경우, Default인 'My Sparse Class Data'를 받게 된다.
-
더보기
UCLASS(BlueprintType, SparseClassDataTypes = MySparseClassData)
class AMyActor : public AActor
{
GENERATED_BODY()
#if WITH_EDITOR
public:
// ~ 이 함수는 기존 데이터를 FMySparseClassData로 전송합니다.
virtual void MoveDataToSparseClassDataStruct() const override;
#endif // WITH_EDITOR
#if WITH_EDITORONLY_DATA
//~ 이 프로퍼티는 FMySparseClassData 구조체로 이동합니다.
private:
// 이 프로퍼티는 에디터에서 변경할 수 있지만, 클래스별로만 변경됩니다.
// 블루프린트 그래프에서는 액세스하거나 변경할 수 없습니다.
// 희소 클래스 데이터의 잠재적 후보입니다.
UPROPERTY()
float MyFloatProperty_DEPRECATED;
// 이 프로퍼티는 에디터에서 변경할 수 없습니다.
// 블루프린트 그래프에서 액세스할 수 있지만, 변경할 수는 없습니다.
// 희소 클래스 데이터의 잠재적 후보입니다.
UPROPERTY()
int32 MyIntProperty_DEPRECATED;
// 이 프로퍼티는 에디터에서 클래스별로 편집할 수 있습니다.
// 블루프린트 그래프에서 액세스할 수 있지만, 변경할 수는 없습니다.
// 희소 클래스 데이터의 잠재적 후보입니다.
UPROPERTY()
FName MyNameProperty_DEPRECATED;
#endif // WITH_EDITORONLY_DATA
//~ 나머지 프로퍼티는 인스턴스별로 변경할 수 있습니다.
//~ 따라서 나머지 프로퍼티는 희소 클래스 데이터 구현에서 제외됩니다.
public:
// 이 프로퍼티는 배치된 MyActor 인스턴스에서 편집할 수 있습니다.
// 희소 클래스 데이터의 잠재적 후보가 아닙니다.
UPROPERTY(EditAnywhere)
FVector MyVectorProperty;
// 이 프로퍼티는 블루프린트 그래프에서 변경할 수 있습니다.
// 희소 클래스 데이터의 잠재적 후보가 아닙니다.
UPROPERTY(BlueprintReadWrite)
FVector2D MyVector2DProperty;
};
- UCLASS(SparseClassDataTypes = [SPARSE_CLASS_DATA_TYPE])
- 이 선언을 통해 이 Class에서 어느 Sparse Class Data를 사용할지 연결한다.
- Class당 1개의 Sparse Class Data만 지정할 수 있다.
- 여러개가 필요한 경우 이를 하나로 묶은 Wrapper를 Sparse Class Data로 지정해야 한다.
- Sparse Class Data를 지정하면 UBT가 자동으로 Get[SPARSE_CLASS_DATA_TYPE] 함수를 생성해준다.
- 다음은 기존 변수를 무난하게 Sparse Class Data로 변환하며 값을 설정하기 위한 세팅이다.
- Sparce Class Data로 이동하는 Property 주변을 #if WITH_EDITORONLY_DATA Precomiler 처리
- 원본 Class의 property의 변수명에 _DEPRECATED 접미사 추가
- _DEPRECATED 접미사가 붙은 변수는 Unreal에서 인지하고 사용 시 warning을 발생시켜준다.
- 원본 Class의 UPROPERTY에 모든 지정자를 제거하고 접근자를 private로 세팅
- Editor Build(#if WITH_EDITOR) 환경에서 MoveDataToSparseClassDataStruct 함수 override
- 원본 Class에서 Sparse Class Data로 1회성 복사를 수행해 기존 값을 보존
-
더보기
#include "Engine/BlueprintGeneratedClass.h"
#if WITH_EDITOR
void AMyActor::MoveDataToSparseClassDataStruct() const
{
// 이미 저장된 희소 데이터를 덮어쓰지 않도록 하세요.
UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(GetClass());
if (BPClass == nullptr || BPClass->bIsSparseClassDataSerializable == true)
{
return;
}
Super::MoveDataToSparseClassDataStruct();
#if WITH_EDITORONLY_DATA
// 언리얼 헤더 툴(Unreal Header Tool, UHT)은 GetMySparseClassData를 자동 생성합니다.
FMySparseClassData* SparseClassData = GetMySparseClassData();
// 이 줄을 수정하여 모든 희소 클래스 데이터 프로퍼티를 포함합니다.
SparseClassData->MyFloatProperty = MyFloatProperty_DEPRECATED;
SparseClassData->MyIntProperty = MyIntProperty_DEPRECATED;
SparseClassData->MyNameProperty = MyNameProperty_DEPRECATED;
#endif // WITH_EDITORONLY_DATA
}
#endif // WITH_EDITOR
- Sparse Class Data의 영향을 받은 Property를 Editor에서 편집/Access 하는 사용자는 차이를 느끼지 못한다.
- Memory 사용량은 줄어든다.
- Property가 C++에서 Reference되는 경우, Getter 함수 호출로 모두 대체 되어야 한다.
- 예를 들어 SparceClassData::MyFloatPropertyData에 접근하려면 GetMyFloatProperty를 대신 호출해야 한다.
- 다행히도 이러한 함수는 UHT가 자동으로 생성한다.
- 해당 PROPERTY에 NoGetter MetaData 지정자를 선언하면 Getter 함수 생성을 방지할 수 있다.
- 해당 PROPERTY에 값 대신 상수 참조로 Access 하고 싶은 경우 GetByRef MetaData 지정자를 사용해야 한다.