【UE4】加載資源的方式(二)使用StaticLoadClass和StaticLoadObject來加載


【UE4】加載資源的方式(二)使用StaticLoadClass和StaticLoadObject來加載

參考資料&原文鏈接

UE4筆記---C++加載BP藍圖及C++BP藍圖文件並創建UUserWidget對象

UE4中資源加載資源的方式

UE4資源加載方式

[UE4]C++實現動態加載的問題:LoadClass和LoadObject

[UE4]C++實現動態加載UObject:StaticLoadObject,以Texture和Material為例

Dynamic Asset Loading with C++

Dynamic Load Object

靜態加載和動態加載

這里說的靜態加載指的是必須在構造函數中完成的加載方式(主要使用ConstructorHelpers,后面的文章會講述)動態加載值得是可以在Runtime期間加載的方式

同步加載和異步加載

注意:LoadObject<T>()LoadClass<T>() 這兩者的加載方式都是同步加載。

為了防止某些情況下引發的巨大延遲,必要的時候我們需要使用異步資源載入系統。

若想用異步加載則可以使用FStreamableManager,它同時提供了同步加載和異步加載兩種方式。后面的文章會講述。

動態加載的核心函數及參數

核心函數是StaticLoadObject和StaticLoadClass函數,它們分別加載繼承於UObject的資源和加載繼承於UClass的C++類,當然加載它們的Native Class也是可以的。

它們的參數都是一樣的,如下:

/**
 * Find or load an object by string name with optional outer and filename specifications.
 * These are optional because the InName can contain all of the necessary information.
 *
 * @param ObjectClass	The class (or a superclass) of the object to be loaded.
 * @param InOuter		An optional object to narrow where to find/load the object from
 * @param Name			String name of the object. If it's not fully qualified, InOuter and/or Filename will be needed
 * @param Filename		An optional file to load from (or find in the file's package object)
 * @param LoadFlags		Flags controlling how to handle loading from disk, from the ELoadFlags enum
 * @param Sandbox		A list of packages to restrict the search for the object
 * @param bAllowObjectReconciliation	Whether to allow the object to be found via FindObject in the case of seek free loading
 * @param InstancingContext				InstancingContext used to remap imports when loading a packager under a new name
 *
 * @return The object that was loaded or found. nullptr for a failure.
 */
  • ObjectClass要加載的對象的類(或超類)。
  • InOuter一個可選對象,用於縮小查找/加載對象的位置。
  • Name對象的字符串名稱。如果它不是完全限定的,則需要 InOuter 和/或 Filename。
  • Filename要從中加載(或在文件的包對象中查找)的可選文件。
  • LoadFlags控制如何處理從磁盤加載的標志,來自 ELoadFlags 枚舉。
  • Sandbox用於限制對象搜索的包列表。
  • bAllowObjectReconciliation是否允許在seek free加載的情況下通過FindObject找到對象。
  • InstancingContext在序列化期間調用時的附加上下文。

這個函數乍一看很嚇人,這么多參數。其實如果只是動態加載資源的話我們只需要關注幾個中要的參數就可以了,下文會一一講到。

LoadClass與StaticLoadClass、LoadObject與StaticLoadObject

動態加載UObject和動態加載UClass分別用LoadObject<T>()LoadClass<T>() ,兩者均在在UObjectGlobals.h中。

關系

其中LoadClass是將StaticLoadClass封裝成了模板函數,省略了一些參數,只需要傳您關心的參數即可,使用更為方便。

同樣LoadObject是將StaticLoadObject封裝成了模板函數。

區別

LoadObject<T>()用來加載非藍圖資源,比如動畫、貼圖、音效等資源;

LoadClass<T>()用來加載藍圖並獲取藍圖Class,比如角色藍圖。如果要用藍圖創建對象,必須先通過LoadClass獲取class,然后再通過SpawnActor生成對象。

加載UObject和UClass

加載UObject

COREUOBJECT_API UObject* StaticLoadObject( UClass* Class, UObject* InOuter, const TCHAR* Name, const TCHAR* Filename = nullptr, uint32 LoadFlags = LOAD_None, UPackageMap* Sandbox = nullptr, bool bAllowObjectReconciliation = true, const FLinkerInstancingContext* InstancingContext = nullptr);

例子:

void UWC_TestUI::OnBtnClickCommonBtn_StaticLoadObject()
{
	UE_LOG(LogTemp,Warning,TEXT("UWC_TestUI:OnBtnClickCommonBtn_StaticLoadObject!"));
	if (!InterestingUE4Path.IsEmpty())
	{
		if (InterestingUE4 == nullptr)
		{
			InterestingUE4 = Cast<UTexture2D>(StaticLoadObject(UTexture2D::StaticClass(),nullptr,*InterestingUE4Path,nullptr,LOAD_None,nullptr));
			if (InterestingUE4 != nullptr)
			{
				Img_StaticLoadObject->SetBrushFromTexture(InterestingUE4);
			}
		}
	}
}

這里只用了兩個參數:

ObjectClass要加載的對象的類(或超類),告訴UE我要加載的資源的是什么類型的。

Name對象的字符串名稱,可以簡單理解為它在UE的Content中的路徑,可以直接右鍵然后復制下來:

image-20211102150734502

其中:

public:
	UPROPERTY(Meta = (BindWidget))
	class UImage * Img_StaticLoadObject;
private:
	UTexture2D * InterestingUE4 = nullptr;
	FString InterestingUE4Path = FString(TEXT("Texture2D'/Game/UI/Images/InterestingUE4.InterestingUE4'"));

還有一個函數是LoadObject,這個函數只是將StaticLoadObject封裝成模板而已,除了Outer和Name以外其余都是空:

/** 
 * Load an object. 
 * @see StaticLoadObject()
 */
template< class T > 
inline T* LoadObject( UObject* Outer, const TCHAR* Name, const TCHAR* Filename=nullptr, uint32 LoadFlags=LOAD_None, UPackageMap* Sandbox=nullptr )
{
	return (T*)StaticLoadObject( T::StaticClass(), Outer, Name, Filename, LoadFlags, Sandbox );
}

你如果也不關心這些參數的話就可以直接用LoadObject,寫起來還快、簡潔,這是例子:

FString InterestingUE4MappingPath = FString(TEXT("Texture2D'/Game/UI/Images/InterestingUE4Mapping.InterestingUE4Mapping'"));
UTexture2D * InterestingUE4Mapping = Cast<UTexture2D>(LoadObject<UTexture2D>(nullptr,*InterestingUE4MappingPath));

支持加載的資源類型

Texture、Material、SoundWave、SoundCue、ParticlesSystem、AnimMontage、BlendSpace(1D,2D,3D)、AnimSequence、AnimBlueprint、SkeletalMesh等等。這些文件的父類都是UObject,所以也可以先加載為UObject*然后再強轉為具體的類型,只要父類是UObject都可以。

加載UClass

/** Version of StaticLoadObject() that will load classes */
COREUOBJECT_API UClass* StaticLoadClass(UClass* BaseClass, UObject* InOuter, const TCHAR* Name, const TCHAR* Filename = nullptr, uint32 LoadFlags = LOAD_None, UPackageMap* Sandbox = nullptr);

例子:

//這個地方有個坑,下面會講,注意這個手動添加的「_C」
FString MyCharacterPath = FString(TEXT("'/Game/Core/BP_MyCharacter.BP_MyCharacter_C'"));
//這里可以填AMyCharacter或AActor,因為AMyCharacter繼承的就是AActor,推薦填AMyCharacter。
UClass *MyCharacterClass = StaticLoadClass(AMyCharacter::StaticClass(),nullptr,*MyCharacterPath,nullptr,LOAD_None,nullptr);
//如果還要從Class生成Actor的話還需要Spawn,生成的時候可以指定位置和旋轉和和你需要的其他參數,具體看源碼。
FVector Location(230.0,0,120);
FRotator Rotation(0.0,0,0);
MyCharacter = Cast<AMyCharacter>(GetWorld()->SpawnActor(MyCharacterClass,&Location,&Rotation));

MyCharacterPath這個地方很坑,如果直接在藍圖上右鍵復制引用的話得到的結果是:'Blueprint /Game/Core/BP_MyCharacter.BP_MyCharacter'

但是啟動游戲,代碼執行到這一行就會報錯,並不能加載成功。

LogUObjectGlobals: Warning: Failed to find object 'Class /Game/Core/BP_MyCharacter.BP_MyCharacter'
LogSpawn: Warning: SpawnActor failed because no class was specified

解決方式:

在路徑的后面加上_C。即:FString MyCharacterPath = FString(TEXT("'Blueprint /Game/Core/BP_MyCharacter.BP_MyCharacter_C'"));

同樣的,加載UClass同樣還有一個函數LoadClass,也只是將StaticLoadClass封裝成模板而已:

/**
 * Load a class object
 * @see StaticLoadClass
 */
template< class T > 
inline UClass* LoadClass( UObject* Outer, const TCHAR* Name, const TCHAR* Filename=nullptr, uint32 LoadFlags=LOAD_None, UPackageMap* Sandbox=nullptr )
{
	return StaticLoadClass( T::StaticClass(), Outer, Name, Filename, LoadFlags, Sandbox );
}

優點也是一樣的,如果你不關心某些參數,寫起來快,這是例子:

UClass *MyCharacterClass = LoadClass<AMyCharacter>(nullptr,*MyCharacterPath);
FVector Location(230.0,0,120);
FRotator Rotation(0.0,0,0);
MyCharacter = Cast<AMyCharacter>(GetWorld()->SpawnActor(MyCharacterClass,&Location,&Rotation));

特點

此加載方式的特點是:

  • 同步加載,注意大資源可能會引起的卡頓和掉幀。
  • 需要路徑不能出錯(后面會用優化),藍圖則需要加上_C
  • 不論加載的是UObject還是UClass,其本質都是使用路徑加載,即必須知道完整路徑。
  • 支持加載的UObject的類型很多。例如Texture、Material、SoundWave、SoundCue、ParticlesSystem、AnimMontage、BlendSpace(1D,2D,3D)、AnimSequence、AnimBlueprint、SkeletalMesh等等。

本文標簽

游戲開發游戲開發基礎Unreal EngineUE資源加載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM