• UE4中资源的引用


    强引用(hard reference)

    如果A强引用B,那么在加载A时会把B也加载进内存

    c++强引用资源

    AMyTest1GameMode的构造函数中加载Blueprint UClass,并赋值给DefaultPawnClass成员变量

    那么AMyTest1GameMode类型就强引用着/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter的Blueprint UClass

    AMyTest1GameMode::AMyTest1GameMode()
    {
        // set default pawn class to our Blueprinted character
        static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
        if (PlayerPawnBPClass.Class != NULL)
        {
            DefaultPawnClass = PlayerPawnBPClass.Class;
        }
    }

    注1:由于使用的是字符串,因此在构建版本时,并不会cook并将/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter的Blueprint UClass打进安装包

    注2:为了让该资源打进安装包,需要让被cook的地图直接或间接引用该Blueprint UClass;或者在DefaultGame.ini文件的/Script/UnrealEd.ProjectPackagingSettings标签的DirectoriesToAlwaysCook数组中配置包含该资源的目录

    [/Script/UnrealEd.ProjectPackagingSettings]
    +DirectoriesToAlwaysCook=(Path="/Game/ThirdPersonCPP/Blueprints")

    资源强引用资源

    下图中从MyTest1Character派生的Blueprint中的USkeletalMeshComponent* Mesh组件的USkeletalMesh* SkeletalMesh变量就强引用着SK_Mannequin的Skeletal Mesh资源

    UCLASS(hidecategories=Object, config=Engine, editinlinenew, abstract)
    class ENGINE_API USkinnedMeshComponent : public UMeshComponent
    {
        GENERATED_UCLASS_BODY()
    
        // ... ...
        
        /** The skeletal mesh used by this component. */
        UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Mesh")
        class USkeletalMesh* SkeletalMesh;
        
        // ... ...
    };

    注1:由于USkeletalMesh* SkeletalMesh被标为EditAnywhere,因此ThirdPersonCharacter的Blueprint放置到游戏关卡中后,还可以对该Blueprint实例的USkeletalMeshComponent* Mesh组件的USkeletalMesh* SkeletalMesh指向的资源进行再次修改

    注2:若被修饰为UPROPERTY(EditDefaultsOnly),就只能在Blueprint中进行修改

     

    软引用(soft reference)

    为了控制何时加载资源,可使用TSoftObjectPtr(或TSoftClassPtr)模板类型来软引用资源(或UClass类型)。

    软引用的工作方式与硬引用一样,可直接关联对应的资源(或UClass类型),在编辑器中界面表现是一样,可通过拖拽、下拉框或箭头选择要关联的资源。

    在编辑器中,仅仅可通过弹出的Tips来区分

    另外,被软引用到的资源会被编辑器中的Reference Viewer引用查看器)工具识别,也会自动cook进安装包

    与指定字符串路径相比,当在编辑器中对被软引用到的资源进行移动、改名等操作时,ue4会进行自动调整。

    UCLASS(config=Game)
    class AMyTest1Character : public ACharacter
    {
        GENERATED_BODY()
        
        // ... ...
        
    public:
        UPROPERTY(Category = MyTest1, EditAnywhere) TSoftObjectPtr<UTexture2D> SourceTexture1; // 软引用
        UPROPERTY(Category = MyTest1, EditAnywhere) UTexture2D* SourceTexture2; // 硬引用
    };

    在Referece Viewer中,粉色的线为弱引用,白色的线为强引用

    UTexture2D* AMyTest1Character::GetLazyTexture2D()
    {
        if (!SourceTexture1.IsPending()) // 检查资源是否已准备好
        {
            return SourceTexture1.Get();
        }
        return SourceTexture1.LoadSynchronous(); // 手动来同步加载贴图资源   注:同步加载可能会导致游戏线程卡顿,开发者需要评估该行为是否合理
    }
    
    
    UTexture2D* AMyTest1Character::GetLazyTexture2D_2()
    {
        if (!SourceTexture1.IsPending()) // 检查资源是否已准备好
        {
            return SourceTexture1.Get();
        }
        
        const FSoftObjectPath& SourceTextureRef = SourceTexture1.ToSoftObjectPath();
        
        return Cast<UTexture2D>(UAssetManager::GetStreamableManager().LoadSynchronous(SourceTextureRef));  // 手动来同步加载贴图资源   注:同步加载可能会导致游戏线程卡顿,开发者需要评估该行为是否合理
    }
    
    UTexture2D* AMyTest1Character::GetLazyTexture2D_3()
    {
        if (!SourceTexture1.IsPending()) // 检查资源是否已准备好
        {
            return SourceTexture1.Get();
        }
        
        const FSoftObjectPath& SourceTextureRef = SourceTexture1.ToSoftObjectPath();
    
        UAssetManager::GetStreamableManager().RequestSyncLoad(SourceTextureRef); // 手动来同步加载贴图资源   注:同步加载可能会导致游戏线程卡顿,开发者需要评估该行为是否合理
        return FindObject<UTexture2D>(nullptr, *SourceTexture1.ToString());  
    }

    如果希望延迟加载UClass,可使用TSoftClassPtr模版类来引用对应的UClass

    UCLASS(config=Game)
    class AMyTest1Character : public ACharacter
    {
        GENERATED_BODY()
        
        // ... ...
        
    public:
        UPROPERTY(Category = MyTest1, EditAnywhere) TSoftClassPtr<UMyBPObject> MyObjectClass; // 软引用
    };

    UClass* AMyTest1Character::GetLazyBPObjectClass()
    {
        if (MyObjectClass.IsValid()) // 检查类型是否已准备好
        {
            return MyObjectClass.Get();
        }
    
        return MyObjectClass.LoadSynchronous();  // 手动来同步加载蓝图Class   注:同步加载可能会导致游戏线程卡顿,开发者需要评估该行为是否合理
    }
    
    
    UClass* AMyTest1Character::GetLazyBPObjectClass_2()
    {
        if (MyObjectClass.IsValid()) // 检查类型是否已准备好
        {
            return MyObjectClass.Get();
        }
    
        const FSoftObjectPath& AssetRef = MyObjectClass.ToSoftObjectPath();
    
        return Cast<UClass>(UAssetManager::GetStreamableManager().LoadSynchronous(AssetRef));  // 手动来同步加载蓝图Class   注:同步加载可能会导致游戏线程卡顿,开发者需要评估该行为是否合理
    }
    
    UClass* AMyTest1Character::GetLazyBPObjectClass_3()
    {
        if (MyObjectClass.IsValid()) // 检查类型是否已准备好
        {
            return MyObjectClass.Get();
        }
    
        const FSoftObjectPath& AssetRef = MyObjectClass.ToSoftObjectPath();
    
        UAssetManager::GetStreamableManager().RequestSyncLoad(AssetRef); // 手动来同步加载蓝图Class   注:同步加载可能会导致游戏线程卡顿,开发者需要评估该行为是否合理
        return FindObject<UClass>(nullptr, *MyObjectClass.ToString());
    }

    使用FSoftClassPathFSoftObjectPath来软引用UClass和资源

    UCLASS(config=Game)
    class AMyTest1Character : public ACharacter
    {
        GENERATED_BODY()
        
        // ... ...
        
    public:
        UPROPERTY(Category = MyTest1, EditAnywhere) FSoftClassPath SourceClass1;
        UPROPERTY(Category = MyTest1, EditAnywhere) FSoftObjectPath SourceObject1;
    };

    注1:FSoftClassPath只能软引用Class、DynamicClass、BlueprintGeneratedClass、WidgetBlueprintGeneratedClass、AnimBluprintGeneratedClass和LinkerPlaceholderClass六大类。这些类的继承关系如下:

    Class (632)
      DynamicClass (760)
      LinkerPlaceholderClass (1072)
      BlueprintGeneratedClass (1512)
        WidgetBlueprintGeneratedClass (1640)
        AnimBlueprintGeneratedClass (2632)

    注2:FSoftObjectPath可以软引用任何资源和UClass

    注1:黄色的TPersistentObjectPtrTSoftObjectPtrTSoftClassPtr为模板类

    注2:FSoftObjectPath类中FThreadSafeCounter CurrentTag、TSet<FName> PIEPackageNames(黄色)是static

    它们之间相互转换关系如下:

    // === 定义FSoftObjectPath对象 ===
    FSoftObjectPath ObjectPath1(TEXT("Material'/Engine/EngineDebugMaterials/VertexColorMaterial.VertexColorMaterial'"));
    FSoftObjectPath ObjectPath2;
    ObjectPath2.SetPath(TEXT("/Engine/EngineMaterials/DefaultDiffuse_TC_Masks.DefaultDiffuse_TC_Masks"));
    
    FSoftObjectPath ObjectPath3(UMyObject::StaticClass()->GetDefaultObject()); // ObjectPath3为:/Script/MyTest1.Default__MyObject
    
    // FSoftObjectPtr对象与FSoftObjectPath对象相互转换
    FSoftObjectPtr FObjectPtr1(ObjectPath2);
    const FSoftObjectPath& ObjectPath4 = FObjectPtr1.ToSoftObjectPath();
    
    FSoftObjectPtr FObjectPtr2(UMyObject::StaticClass()->GetDefaultObject()); // FObjectPtr2为:/Script/MyTest1.Default__MyObject
    const FSoftObjectPath& ObjectPath5 = FObjectPtr2.ToSoftObjectPath();
    
    // === 定义TSoftObjectPtr<T>对象 ===
    TSoftObjectPtr<UMyObject> TObjectPtr1(UMyObject::StaticClass()->GetDefaultObject()); // TObjectPtr1为:/Script/MyTest1.Default__MyObject
    
    // TSoftObjectPtr<T>对象与FSoftObjectPath对象相互转换
    FSoftObjectPath ObjectPath6 = FSoftObjectPath("/Game/ThirdPerson/Meshes/Bump_StaticMesh.Bump_StaticMesh");
    TSoftObjectPtr<UStaticMesh> TObjectPtr2(ObjectPath6);
    
    const FSoftObjectPath& ObjectPath7 = TObjectPtr2.ToSoftObjectPath();
    
    // === 定义FSoftClassPath对象 ===
    FSoftClassPath ClassPath1 = FSoftClassPath(TEXT("/Script/MyTest1.MyObject"));
    FSoftClassPath ClassPath2 = FSoftClassPath(UMyObject::StaticClass()); // ClassPath2为:/Script/MyTest1.MyObject
    
    FSoftClassPath ClassPath3;
    ClassPath3.SetPath(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter.ThirdPersonCharacter_C"));
    
    // === 定义TSoftClassPtr<T>对象 ===
    TSoftClassPtr<UMyObject> TClassPtr1(UMyObject::StaticClass()); // TClassPtr1为:/Script/MyTest1.MyObject
    
    // TSoftClassPtr<T>对象与FSoftObjectPath对象相互转换
    FSoftObjectPath ObjectPath8(TEXT("/Game/ThirdPersonCPP/Blueprints/MyBPObject.MyBPObject_C"));
    TSoftClassPtr<UMyBPObject> TClassPtr2(ObjectPath8);
    const FSoftObjectPath& ObjectPath9 = TClassPtr2.ToSoftObjectPath();

    字符串路径

    资源(或UClass)通过字符串路径来指定,通过LoadObjectLoadClass)来加载。

    该方式不能被Reference Viewer工具识别,资源进行移动、改名等操作时,不会自动调整。也不能自动cook进安装包。

    加载资源

    // 加载UI蓝图资源   注:不是UI蓝图Class
    FString MyWidgetBPPath = TEXT("/Game/ThirdPerson/UMG/MyWidgetBlueprint");
    UObject* MyWidgetBPObject = LoadObject<UObject>(nullptr, *MyWidgetBPPath);  // MyWidgetBPObject的类型为UWidgetBlueprint*
    
    // 加载Texture2D资源
    FString TexturePath1 = TEXT("/Engine/EngineMaterials/DefaultDiffuse_TC_Masks");
    UTexture2D* TextureObj1 = FindObject<UTexture2D>(nullptr, *TexturePath1);  // 若之前没有加载,TextureObj1则返回为空
    TextureObj1 = LoadObject<UTexture2D>(nullptr, *TexturePath1);  // 在LoadObject内部在加载前也会调用FindObject先进行查找,如果不存在,才会从硬盘加载它
    
    // 加载材质资源
    FString MaterialPath1 = TEXT("/AnimationSharing/AnimSharingRed.AnimSharingRed");
    UMaterialInterface* MaterialObj1 = LoadObject<UMaterialInterface>(nullptr, *MaterialPath1);
    
    // 加载StaticMesh资源
    FString StaticMeshPath1 = TEXT("/Game/ThirdPerson/Meshes/Bump_StaticMesh.Bump_StaticMesh");
    UStaticMesh* MyStaticMesh = Cast<UStaticMesh>(StaticLoadObject(UStaticMesh::StaticClass(), nullptr, *StaticMeshPath1));

    如果在UObject类型的构造函数中,可以使用ConstructorHelpers::FObjectFinder来加载资源

    static ConstructorHelpers::FObjectFinder<UStaticMesh> MyStaticMeshClass(TEXT("/Game/ThirdPerson/Meshes/Bump_StaticMesh"));
    UStaticMesh* MyStaticMesh = MyStaticMeshClass.Object;

    加载UClass(类型)

    // Native UClass  
    FString MyObjectPath = TEXT("/Script/MyTest1.MyObject");
    UClass* MyObjectHit = FindObject<UClass>(ANY_PACKAGE, *MyObjectPath); // 在游戏启动初始化时就已创建,因此可以直接Find到
    UClass* MyObjectClass = LoadClass<UMyObject>(nullptr, *MyObjectPath); // MyObjectClass为UClass*类型  与MyObjectHit相等
    //UClass* MyObjectClass = StaticLoadClass(UMyObject::StaticClass(), nullptr, *MyObjectClassPath); // 与上面语句等价
    
    // UObjcet Blueprint UClass
    FString MyBPObjectPath = TEXT("/Game/ThirdPersonCPP/Blueprints/MyBlueprintObject.MyBlueprintObject_C");
    UClass* MyBPObjectHit = FindObject<UClass>(ANY_PACKAGE, *MyBPObjectPath);
    UClass* MyBPObjectClass = LoadClass<UObject>(nullptr, *MyBPObjectPath); // MyBPObjectClass为UBlueprintGeneratedClass*类型
    //UClass* MyBPObjectClass = StaticLoadClass(UObject::StaticClass(), nullptr, *MyBPObjectPath); // 与上面语句等价
    
    // AActor Blueprint UClass
    FString PlayerPawnBPPath = TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter.ThirdPersonCharacter_C");
    UClass* PlayerPawnBPClass = StaticLoadClass(APawn::StaticClass(), nullptr, *PlayerPawnBPPath); // PlayerPawnBPClass为UBlueprintGeneratedClass*类型
    // 也可使用LoadClass来加载  如:UClass* PlayerPawnBPClass = LoadClass<APawn>(nullptr, *PlayerPawnBPPath);
    // 也可使用LoadObject来加载  如:UClass* PlayerPawnBPClass = LoadObject<UClass>(nullptr, *PlayerPawnBPPath);
    
    // 可以通过FindObject<UClass>函数来查找PlayerPawnBPPath对应的蓝图Class是否已经加载
    // 另外,StaticLoadClass、LoadClass、LoadObject函数在加载前也会调用FindObject<UClass>来查找,如果不存在,才会从硬盘加载它
    // UClass* PlayerPawnBPClass = FindObject<UClass>(nullptr, *PlayerPawnBPPath);
    
    // UUserWidget Blueprint UClass
    FString MyWidgetBPPath = TEXT("/Game/ThirdPerson/UMG/MyWidgetBlueprint.MyWidgetBlueprint_C");
    UClass* MyWidgetBPClass = StaticLoadClass(UObject::StaticClass(), nullptr, *MyWidgetBPPath); // MyWidgetBPClass为UWidgetBlueprintGeneratedClass*类型
    // 也可使用LoadClass来加载  如:UClass* MyWidgetBPClass = LoadClass<UObject>(nullptr, *MyWidgetBPPath);
    // 也可使用LoadObject来加载  如:UClass* MyWidgetBPClass = LoadObject<UClass>(nullptr, *MyWidgetBPPath);
    
    UUserWidget* DefaultMyWidgetBPObject = MyWidgetBPClass->GetDefaultObject<UUserWidget>();
    
    UUserWidget* MyWidget = UWidgetBlueprintLibrary::Create(this, MyWidgetBPClass, nullptr); // 基于MyWidgetBPClass类型创建一个UserWidget实例

    注1:Native UClass的字符串路径为/Script/【模块名】.【类型名】]      // 类型名要去掉U、A等前缀

    注2:Blueprint UClass的字符串路径为/【Engine | Game | 插件名】/<XXX>/[名称].[名称] _C

    如果在UObject类型的构造函数中,可以使用ConstructorHelpers::FClassFinder来加载UClass(类型)

    static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
    UClass* PawnClass = PlayerPawnBPClass.Class;
    
    static ConstructorHelpers::FClassFinder<UObject> MyBPObjectClass(TEXT("/Game/ThirdPersonCPP/Blueprints/MyBlueprintObject"));
    UClass* MyClass = MyBPObjectClass.Class;
    
    static ConstructorHelpers::FClassFinder<UObject> MyWidgetBPClass(TEXT("/Game/ThirdPerson/UMG/MyWidgetBlueprint.MyWidgetBlueprint_C"));
    UClass* MyWidgetClass = MyWidgetBPClass.Class;

    注:传给ConstructorHelpers::FClassFinder的Blueprint UClass的字符串路径不为[名称].[名称] _C时,其内部会进行补齐

    参考

    引用资源Referencing Assets

  • 相关阅读:
    HDU 5444 Elven Postman 二叉排序树
    HDU 5438 Ponds dfs模拟
    Gym
    markdown test
    Gym
    集训回顾
    UVALive
    UVALive
    UVALive
    codeforcres 589 J
  • 原文地址:https://www.cnblogs.com/kekec/p/13357937.html
Copyright © 2020-2023  润新知