1. 程式人生 > >[UE4]C++讀取/儲存檔案(如Texture2D)

[UE4]C++讀取/儲存檔案(如Texture2D)

//指定檔案路徑
    FString PathToLoad = "Texture2D'/Game/timg.timg'";

//通過路徑Load進來,並轉換成Texture2D
    UTexture2D* tmpTexture =  Cast<UTexture2D>(StaticLoadObject(UTexture2D::StaticClass(), NULL, *(PathToLoad ))); 

//改變Texture2D的屬性
    tmpTexture->LODGroup = TextureGroup::TEXTUREGROUP_Pixels2D;

//得到儲存的路徑
    FString FileName = tmpTexture->GetFName().ToString();
    FString pathPackage = FString("/Game/") + FileName;

//根據路徑建立Package
    UPackage * Package = CreatePackage(nullptr, *pathPackage);

//設定改變並儲存
    Package->SetDirtyFlag(true);
    UEditorLoadingAndSavingUtils::SaveDirtyPackages(false, true);

-----------------------------------------------------------

其他資料:

Rama的外掛:

https://github.com/EverNewJoy/VictoryPlugin

將讀取方法暴露給藍圖了,但是目前版本沒有儲存

-----------------------------------------------------------------------

動態建立package資源並且匯出資源

void UTestShaderBlueprintLibrary::ExportTexture(UTexture2D* TextureToBeExpot)
{
    //TextureToBeExpot->CompressionSettings = TextureCompressionSettings::TC_VectorDisplacementmap;
    //TextureToBeExpot->SRGB = 0;
    //TextureToBeExpot->UpdateResource();
    //TextureToBeExpot->Source.BulkData
 
    FTexture2DMipMap& mipmap = TextureToBeExpot->PlatformData->Mips[4];
    void* Data = mipmap.BulkData.Lock(LOCK_READ_WRITE);
    uint32* PixelPointer = (uint32*)Data;
    if (PixelPointer == nullptr)
    {
        mipmap.BulkData.Unlock();
        return;
    }
 
    int32 texturex = TextureToBeExpot->PlatformData->SizeX;
    int32 texturey = TextureToBeExpot->PlatformData->SizeY;
    TArray<uint8>colors;
    colors.AddUninitialized(texturex * texturey * 4);
 
    for (int32 x = 0; x < texturex * texturey; x++)
    {
        uint32 EncodedPixel = *PixelPointer;
        //B
        colors[4 * x] = (EncodedPixel & 0x000000FF);
 
        //G
        colors[4 * x + 1] = (EncodedPixel & 0x0000FF00) >> 8;
 
        //R
        colors[4 * x + 2] = (EncodedPixel & 0x00FF0000) >> 16;
 
        //A
        colors[4 * x + 3] = (EncodedPixel & 0xFF000000) >> 24;
 
        PixelPointer++;
    }
    mipmap.BulkData.Unlock();
 
    //----------------------------------------------------------//
    // Texture Information
    int width = texturex;
    int height = texturey;
 
    FString FileName = TextureToBeExpot->GetFName().ToString();
    
    // Create Package
    FString pathPackage = FString("/Game/MyTextures/") + FileName;
    //FString absolutePathPackage = FPaths::ProjectContentDir() + "/MyTextures/";
 
    //FPackageName::RegisterMountPoint(*pathPackage, *absolutePathPackage);
 
    UPackage * Package = CreatePackage(nullptr, *pathPackage);
 
    // Create the Texture
    //FName TextureName = MakeUniqueObjectName(Package, UTexture2D::StaticClass(), FName(*FileName));
    //FName TextureName = FPaths::GetBaseFilename(absolutePathPackage);
    UObject* TexObj = NewObject<UTexture2D>(Package, TextureToBeExpot->GetFName(), RF_Public | RF_Standalone);
    UTexture2D* Texture = Cast<UTexture2D>(TexObj);
 
    Texture->Source.Init(width, height, /*NumSlices=*/ 1, /*NumMips=*/ 1, TSF_BGRA8, colors.GetData());
    Texture->PlatformData = new FTexturePlatformData();
    Texture->PlatformData->SizeX = width;
    Texture->PlatformData->SizeY = height;
    Texture->PlatformData->PixelFormat = PF_B8G8R8A8;
    
    //Texture->Source.Format = 
 
    // Passing the pixels information to the texture
    FTexture2DMipMap* Mip = new(Texture->PlatformData->Mips) FTexture2DMipMap();
    Mip->SizeX = width;
    Mip->SizeY = height;
    Mip->BulkData.Lock(LOCK_READ_WRITE);
    uint8* TextureData = (uint8 *)Mip->BulkData.Realloc(height * width * sizeof(uint8) * 4);
    FMemory::Memcpy(TextureData, colors.GetData(), sizeof(uint8) * height * width * 4);
    Mip->BulkData.Unlock();
 
    // Updating Texture & mark it as unsaved
    Texture->AddToRoot();
    FAssetRegistryModule::AssetCreated(Texture);
    Texture->UpdateResource();
    Package->SetDirtyFlag(true);
    
    //Texture->PostEditChange();
 
    UE_LOG(LogTemp, Log, TEXT("Texture created: %s"), &FileName);
 
    //---------------------------------------------------------//
 
    //TextureToBeExpot->
    //FEditorFileUtils::PromptForCheckoutAndSave(PackagesToSave, false, /*bPromptToSave=*/ false);
 
    FAssetToolsModule& AssetToolModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
    IAssetTools& AssetTool = AssetToolModule.Get();
 
    TArray<UObject*>Textures;
    Textures.Add(Texture);
    AssetTool.ExportAssetsWithDialog(Textures, true);
 
 
}
注意package的路徑,如果路徑不對資源將建立失敗。

 

 

------------------------------------------------------------------------------------------------------------------

 

老外的分享

https://answers.unrealengine.com/questions/500286/saveload-package.html

 

--------------------------------------------------------------------------------------------------------

 

[UE4]C++實現動態載入的問題:LoadClass<T>()和LoadObject<T>()

 

 

C++靜態載入問題:ConstructorHelpers::FClassFinder()和FObjectFinder() 

http://aigo.iteye.com/blog/2281373

C++實現動態載入UObject:StaticLoadObject();以Texture和Material為例

http://aigo.iteye.com/blog/2268056

 

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

 

區別:

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

LoadClass<T>()用來載入藍圖並獲取藍圖Class,比如角色藍圖。如果要用藍圖建立物件,必須先通過LoadClass獲取class,然後再通過SpawnActor生成物件。

 

LoadClass引數注意事項:

另外注意:LoadClass<T>的模版名稱,不能直接寫UBlueprint,例如:LoadClass<UBlueprint>是錯誤的,建立藍圖時選擇的是什麼父類,則寫對應的父類名,假如是Actor,那麼要寫成:LoadClass<AActor>,否則無法載入成功。

路徑名也必須帶_C字尾(LoadObject不需要帶_C字尾),例如,藍圖路徑是:Blueprint'/Game/Blueprints/MyBP.MyBP'

加字尾以後,則是:Blueprint'/Game/Blueprints/MyBP.MyBP_C',

例子:

 

Cpp程式碼 

 收藏程式碼

  1. UClass* Test = LoadClass<AActor>(NULL, TEXT("Blueprint'/Game/Blueprints/MapPathBrush_BP.MapPathBrush_BP_C'"));  

 

 

官方還沒出文件,只能先看程式碼註釋:
 

Cpp程式碼 

 收藏程式碼

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

 

Cpp程式碼 

 收藏程式碼

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

 

Cpp程式碼 

 收藏程式碼

  1. /** 
  2.  * Find or load an object by string name with optional outer and filename specifications. 
  3.  * These are optional because the InName can contain all of the necessary information. 
  4.  * 
  5.  * @param ObjectClass   The class (or a superclass) of the object to be loaded. 
  6.  * @param InOuter       An optional object to narrow where to find/load the object from 
  7.  * @param InName        String name of the object. If it's not fully qualified, InOuter and/or Filename will be needed 
  8.  * @param Filename      An optional file to load from (or find in the file's package object) 
  9.  * @param LoadFlags     Flags controlling how to handle loading from disk 
  10.  * @param Sandbox       A list of packages to restrict the search for the object 
  11.  * @param bAllowObjectReconciliation    Whether to allow the object to be found via FindObject in the case of seek free loading 
  12.  * 
  13.  * @return The object that was loaded or found. NULL for a failure. 
  14.  */  
  15. COREUOBJECT_API UObject* StaticLoadObject( UClass* Class, UObject* InOuter, const TCHAR* Name, const TCHAR* Filename = NULL, uint32 LoadFlags = LOAD_None, UPackageMap* Sandbox = NULL, bool bAllowObjectReconciliation = true );  
  16. COREUOBJECT_API UClass* StaticLoadClass(UClass* BaseClass, UObject* InOuter, const TCHAR* Name, const TCHAR* Filename = NULL, uint32 LoadFlags = LOAD_None, UPackageMap* Sandbox = NULL);  

 

 LoadObject引數注意事項:

 LoadObject載入例子,不需要新增字尾:

Cpp程式碼 

 收藏程式碼

  1. UTexture2D* Tex = LoadObject<UTexture2D>(NULL, TEXT("Texture2D'/Game/Textures/UI/tex_test001.tex_test001'"));  

 
 

可以用LoadObject載入的檔案包括:

Texture、Material、SoundWave、SoundCue、ParticlesSystem、AnimMontage、BlendSpace(1D,2D,3D)、AnimSequence、AnimBlueprint、SkeletalMesh等等。這些檔案的父類都是UObject,所以也可以先載入為UObject*然後再強轉為具體的型別,例如:

Cpp程式碼 

 收藏程式碼

  1. UObject* Obj = LoadObject<UObject>(NULL, TEXT("SkeletalMesh'/Game/MyMesh.MyMesh'"));  
  2. USkeletalMesh* MyMesh = Cast<USkeletalMesh*>(Obj);  

 

 

https://aigo.iteye.com/blog/2268056

 

https://aigo.iteye.com/blog/2281558

 

 

 

載入MaterialTexture

Cpp程式碼 

 收藏程式碼

  1. struct FConstructorStatics  
  2.  {  
  3.      ConstructorHelpers::FObjectFinderOptional<UTexture> TextureFinder;  
  4.      ConstructorHelpers::FObjectFinderOptional<UMaterial> MaterialFinder;  
  5.      FConstructorStatics()  
  6.          : TextureFinder(TEXT("Texture2D'/Game/Textures/2DBackground.2DBackground'"))  
  7.          , MaterialFinder(TEXT("Material'/Game/Materials/DynamicTextureMaterial.DynamicTextureMaterial'"))  
  8.      {  
  9.      }  
  10.  };  
  11.  static FConstructorStatics ConstructorStatics;  
  12.    
  13.  Texture = ConstructorStatics.TextureFinder.Get();  
  14.  UMaterial* Material = ConstructorStatics.MaterialFinder.Get();  
  15.  DynamicMaterial = UMaterialInstanceDynamic::Create(Material, this);  

 

設定呼叫載入好的Material和Texture:

Cpp程式碼 

 收藏程式碼

  1. DynamicMaterial->SetTextureParameterValue(FName("DynamicTexture"), Texture);  
  2. Mesh->SetMaterial(0, DynamicMaterial);  

 

 

如果資源永不再使用,想銷燬資源物件,程式碼如下:

Cpp程式碼 

 收藏程式碼

  1. Texture2D* mytex; //這裡假設mytex合法有效  
  2.   
  3. mytex->ConditionalBeginDestroy();  
  4. mytex = NULL;  
  5. GetWorld()->ForceGarbageCollection(true);