创建并保存Asset通过C++

ue4-create-texture-editor-plugin This example was created for Unreal Engine 4.16. It might not work if the versions are too different.
 void CreateTexture() {
 	// Texture Information
 	FString FileName = FString("MyTexture");
 	int width = 1024;
 	int height = 1024;
 	uint8 * pixels = (uint8 *)malloc(height * width * 4); // x4 because it's RGBA. 4 integers, one for Red, one for Green, one for Blue, one for Alpha
 	// filling the pixels with dummy data (4 boxes: red, green, blue and white)
 	for (int y = 0; y < height; y++)
 	{
 		for (int x = 0; x < width; x++)
 		{
 			if (x < width / 2) {
 				if (y < height / 2) {
 					pixels[y * 4 * width + x * 4 + 0] = 255; // R
 					pixels[y * 4 * width + x * 4 + 1] = 0;   // G
 					pixels[y * 4 * width + x * 4 + 2] = 0;   // B
 					pixels[y * 4 * width + x * 4 + 3] = 255; // A
 				}
 				else {
 					pixels[y * 4 * width + x * 4 + 0] = 0;   // R
 					pixels[y * 4 * width + x * 4 + 1] = 255; // G
 					pixels[y * 4 * width + x * 4 + 2] = 0;   // B
 					pixels[y * 4 * width + x * 4 + 3] = 255; // A
 				}
 			}
 			else {
 				if (y < height / 2) {
 					pixels[y * 4 * width + x * 4 + 0] = 0;   // R
 					pixels[y * 4 * width + x * 4 + 1] = 0;   // G
 					pixels[y * 4 * width + x * 4 + 2] = 255; // B
 					pixels[y * 4 * width + x * 4 + 3] = 255; // A
 				}
 				else {
 					pixels[y * 4 * width + x * 4 + 0] = 255; // R
 					pixels[y * 4 * width + x * 4 + 1] = 255; // G
 					pixels[y * 4 * width + x * 4 + 2] = 255; // B
 					pixels[y * 4 * width + x * 4 + 3] = 255; // A
 				}
 			}
 		}
 	}
 	// Create Package
 	FString pathPackage = FString("/Game/MyTextures/");
 	FString absolutePathPackage = FPaths::GameContentDir() + "/MyTextures/";
 	FPackageName::RegisterMountPoint(*pathPackage, *absolutePathPackage);
 	UPackage * Package = CreatePackage(nullptr, *pathPackage);
 	// Create the Texture
 	FName TextureName = MakeUniqueObjectName(Package, UTexture2D::StaticClass(), FName(*FileName));
 	UTexture2D* Texture = NewObject(Package, TextureName, RF_Public | RF_Standalone);
 	// Texture Settings
 	Texture->PlatformData = new FTexturePlatformData();
 	Texture->PlatformData->SizeX = width;
 	Texture->PlatformData->SizeY = height;
 	Texture->PlatformData->PixelFormat = PF_R8G8B8A8;
 	// 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, pixels, sizeof(uint8) * height * width * 4);
 	Mip->BulkData.Unlock();
 	// Updating Texture & mark it as unsaved
 	Texture->AddToRoot();
 	Texture->UpdateResource(); // 这行代码必须调用,否则贴图数据为空。
 	Package->MarkPackageDirty();
 	UE_LOG(LogTemp, Log, TEXT( "Texture created: %s" ), &FileName);
 	free(pixels);
 	pixels = NULL;
 }
save-a-procedurally-generated-texture-as-a-new-asset
本文的代码是通过拷贝到gVim中,执行 {:%s/^/ /g}命令来批量在每行行首插入空格,然后gg到最开头,大V进入visual模式,G选中到最末尾,确定选中全文后,执行{"+y}拷贝全文到系统粘贴板,最后粘贴到这里。

Asset and Asset File

阅读Assets and Packages一节,我觉得有2个概念需要区分一下:Asset、Asset File。
UE4里Asset是资产的意思,可以理解为一种逻辑资产、思维资产。而这个资产要落地,就写入文件里形成一个资产文件(.uasset)。
通常,一个asset file里存储一个asset

ENQUEUE压指令到渲染线程获取贴图数据

 void GetTexturePixels(FTexture2DRHIRef Texture, TArray<FColor>& OutPixels)
 {
     struct FReadSurfaceContext
     {
         FTexture2DRHIRef Texture;
         TArray<FColor>* OutData;
         FIntRect Rect;
         FReadSurfaceDataFlags Flags;
     };
     OutPixels.Reset();
     FReadSurfaceContext ReadSurfaceContext =
     {
         Texture,
         &OutPixels,
         FIntRect(0, 0, Texture->GetSizeXY().X, Texture->GetSizeXY().Y),
         FReadSurfaceDataFlags(RCM_UNorm, CubeFace_MAX)
     };
     ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(
         ReadSurfaceCommand,
         FReadSurfaceContext, Context, ReadSurfaceContext,
         {
             RHICmdList.ReadSurfaceData(
                 Context.Texture,
                 Context.Rect,
                 *Context.OutData,
                 Context.Flags
             );
         });
     FlushRenderingCommands();
 }