(UE4 4.27)UE4的Texture生成和原理浅分析

前言

在网上看到不少有关于UE4 生成Texture的教程,这些教程有些可以成功生成,有些生成失败,有些是创建无法持久保存的Texture或者说是关掉编辑器重启后就变黑的Texture等等,我跟着这些教程算是踩了不少小坑,有点难受,后面我还是决定看源码,最终算是从原理上清楚了Texture生成这个过程的一些原理。

UE4 Texture生成代码

	FString TextureName = "Test";
	FString PackName = FString::Printf(TEXT("/Game/%s"), *TextureName);
	UPackage* Package = CreatePackage(*PackName);
	Package->FullyLoad();
	UTexture2D* Texture = NewObject<UTexture2D>(Package, *TextureName, RF_Public | RF_Standalone | RF_MarkAsRootSet);

	static const int32 TextureWidth = 1024;
	static const int32 TextureHeight = 1024;
	TArray<FColor> SourceColors;
	SourceColors.Init(FColor::Red, TextureWidth * TextureHeight);

	//Source 
	Texture->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
	Texture->Source.Init(TextureWidth, TextureHeight, 1, 1, ETextureSourceFormat::TSF_BGRA8);
	uint8* SourceData = Texture->Source.LockMip(0);
	FMemory::Memcpy(SourceData, SourceColors.GetData(), sizeof(FColor) * SourceColors.Num());
	Texture->Source.UnlockMip(0);

	//PlatformData
	Texture->PlatformData = new FTexturePlatformData();
	Texture->PlatformData->SizeX = TextureWidth;
	Texture->PlatformData->SizeY = TextureHeight;
	Texture->PlatformData->PixelFormat = EPixelFormat::PF_B8G8R8A8;
	FTexture2DMipMap* NewMipMap = new FTexture2DMipMap();
	Texture->PlatformData->Mips.Add(NewMipMap);
	NewMipMap->SizeX = TextureWidth;
	NewMipMap->SizeY = TextureHeight;

	Texture->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
	uint8* MipData = (uint8*)Texture->PlatformData->Mips[0].BulkData.Realloc(sizeof(FColor) * TextureWidth * TextureHeight);
	FMemory::Memcpy(MipData, SourceColors.GetData(), sizeof(FColor) * SourceColors.Num());
	Texture->PlatformData->Mips[0].BulkData.Unlock();

	Texture->UpdateResource();
	Texture->PostEditChange();
	Texture->MarkPackageDirty();
	FAssetRegistryModule::AssetCreated(Texture);

大体的主要三个步骤

(1)填充TextureSource资源

(2)填充PlatformData的Mip资源

(3)UpdateResource

首先反思下,上面的代码有何问题?可以运行下来创建了一张红色无Mip的纹理,大家可能是正常运行的代码,无任何问题。先不说其中的问题,先谈谈Texture几个概念

UTexture的简介

 Texture的FTextureSouce

FTextureSouce存储了纹理的源数据(Color等等),这所谓纹理源数据,可以理解为一份外部导入,不可破坏的数据。或者说是编辑器数据.

 可以看出纹理源数据只存在编辑时,最终Shipping打包出的项目是没这个东西。但是纹理源数据是为了解决什么问题的?从注释上看,是为了创建运行时的纹理数据(给材质Shader等情况使用的纹理数据). 假设不存在TextureSouce,  并且有个情况,我们需要调节纹理的对比度和亮度度等属性,第一次我们调亮度为了0.9,第二次我调亮度回到0.8. 第一次调节,假设原来为FColor(100, 100, 100), 则第一次调节后我们变为了FColor(90, 90, 90), 第二次变为多少?不知道,因为我们原始值已经变了,但是第二次调节亮度为0.8是相对于原始的,没了原始数据我们调节得到的颜色值根本无法知道,因此TextureSouce的作用是作为不可破坏的原始数据存在,Mip的生成都是遵从原始数据来的。TextureSouce不存在Mip或者说存在相当于第0级的Mip.  如下图所示:

Texture2D的FTexturePlatformData

FTexturePlatformData确切来说就是运行时数据,后面UE4 RenderThread的FTexture(对应于DX的SRV)就是靠FTexturePlatformData的各级Mip颜色数据(TArrat<FTexture2DMipMap)来填充创建的。

Texture的PrivateResource

FTextureResource PrivateResource就是我们在RenderThread使用的纹理资源来,GameThread的UTexture2d在RenderThread的代表。 如果我们发现材质,UI等需要用到SRV的情况下纹理上不正常甚至纹理相关的崩溃, PrivateResource是最优先Debug的。

Texture2D的UpdateResource

上面说到TextureFTextureSouceFTexturePlatformData,FTextureResource三个概念。Texture2D给来一个接口把三个概念串联出来来。

 TextureSource->TexturePlatformData

TexturePlatformData->FTextureResource

 

结论

编辑器生成Texture2d

也就是纹理生成,我们只要建立FTextureSource数据,然后UpdateResource就可以得到FTexturePlatformData和FTextureResource,也就是说来为了在编辑器生成纹理资源说不需要手动填充FTexturePlatformData,而且哪怕手动填充FTexturePlatformData也会因为调用UpdateResource(手动在编辑器调节亮度,对比度, Mip生成设定等都会触发UpdateResource, 导致旧的FPlatfromData被新生成的FPlatfromData数据覆盖掉)。

运行时使用Texture2d

有个情况说:使用的Texture2d打包的游戏运行时创建的(不打算保存为编辑器文件),并非DevelopmentEditor或者DebugEditor这些模式下,也就是Texture2D不存在FTextureSource怎么办? 还是得看到上面的UpdateResource, 渲染资源FTextureResource是由FPlatfromData生成的,此时我们直接手动填充FTexturePlatformData的各级Mip数据,然后UpdateResource就行来。顺便说下UTexture2D已经提供来一个创建给完全运行时使用纹理的接口(只有一个Mip等级),但是手动填充FTexturePlatformData​​​​​​​数据后,记住还得手动UpdateResource。

资料参考

Texture2D.h, Texture2D.cpp, Texture.h, Texture.cpp, TextureDerivedData.cpp

猜你喜欢

转载自blog.csdn.net/qq_29523119/article/details/124030787
UE4