需求
数据/数组转成纹理,在材质中进行操作
纹理的导出、读取
纹理创建
最基础的模板
UTexture2D* U类名::方法名(int32 SizeX, int32 SizeY, const TArray<FColor>& Val)
{
if (Val.Num() == 0)return nullptr;
if (Val.Num() != SizeX * SizeY)return nullptr;
UTexture2D* ResTexture2D = UTexture2D::CreateTransient(SizeX, SizeY, PF_B8G8R8A8);
uint8* Pixels = new uint8[SizeX * SizeY * 4];
for (int i = 0; i < SizeX * SizeY; i++)
{
Pixels[4 * i] = Val[i].B;
Pixels[4 * i + 1] = Val[i].G;
Pixels[4 * i + 2] = Val[i].R;
Pixels[4 * i + 3] = Val[i].A;
}
void* TextureData = ResTexture2D->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(TextureData, Pixels, sizeof(uint8) * SizeX * SizeY * 4);
ResTexture2D->GetPlatformData()->Mips[0].BulkData.Unlock();
ResTexture2D->UpdateResource();
return ResTexture2D;
}
返回一张BGRA8的纹理,可以设置成材质参数使用
提高精度
如果对数据精度要求较高,8位可能有较大误差,可以使用其他纹理格式。
需要注意纹理中数据的类型需要对应变化,我列出以下常用的几个
PF_B8G8R8A8使用uint8或FColor
PF_FloatRGBA使用FFloat16
PF_A32B32G32R32F使用FLinearColor
以下为创建一个PF_A32B32G32R32F纹理的代码
UTexture2D* U类名::方法名(int32 SizeX, int32 SizeY, const TArray<FLinearColor>& Val)
{
if (Val.Num() == 0)return nullptr;
if (Val.Num() != SizeX * SizeY)return nullptr;
UTexture2D* ResTexture2D = UTexture2D::CreateTransient(SizeX, SizeY, PF_A32B32G32R32F);
FLinearColor* Pixels = new FLinearColor[SizeX * SizeY];
for (int i = 0; i < SizeX * SizeY; i++) Pixels[i] = Val[i];
void* TextureData = ResTexture2D->GetPlatformData()->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(TextureData, Pixels, sizeof(FLinearColor) * SizeX * SizeY);
ResTexture2D->GetPlatformData()->Mips[0].BulkData.Unlock();
ResTexture2D->UpdateResource();
return ResTexture2D;
}
对纹理的设置
将创建的纹理暴露给外部,双击打开
需要注意的是以下参数
sRGB为色彩矫正,需要数据精确时应关闭,需要纹理导出或读取时应关闭
平铺法默认为包裹,纹理边缘UV0和1的地方会插值,建议设置成限制
过滤器设置为最近,类似像素化,适合作为纹理中的数组使用
过滤器设置为双线性,纹理会平滑插值,效果比顶点的三角插值好很多
其他参数为读取和导出相关参数
如果想要导出或读取纹理,需要以下设置
mip生成格式->无mip贴图
压缩设置->向量置换贴图
sRGB->Fasle
其中mip格式不能在Runtime设置,打包时会报错,需注意
所有设置可在纹理编辑器中更改,也可在代码中设置
//样式相关
ResTexture2D->AddressX = TextureAddress::TA_Clamp;
ResTexture2D->AddressY = TextureAddress::TA_Clamp;
ResTexture2D->Filter=TF_Bilinear;
ResTexture2D->SRGB = false;
//读取和导出相关
ResTexture2D->CompressionSettings = TC_VectorDisplacementmap;
#if WITH_EDITOR
//仅编辑器
ResTexture2D->MipGenSettings = TMGS_NoMipmaps;
#endif
纹理读取
将纹理设置为可读取的格式,结束后修改回来
由于mip无法在打包后设置,且纹理由数组生成,直接读取数组中的值更便利
不建议使用,在编辑器作为测试函数即可
FColor U类名::方法名(UTexture2D* TextureToRead, int I, int J)
{
FColor ResCol;
#if WITH_EDITOR
//Only Read PF_B8G8R8A8
if (TextureToRead->GetPixelFormat() != PF_B8G8R8A8) return ResCol;
//Index Error
if (I >= TextureToRead->GetSizeX() || J >= TextureToRead->GetSizeY())return ResCol;
//Remember Some Settings Then Modify To Prevent LockReadOnly() Return Null
const TextureCompressionSettings OldCompressionSettings = TextureToRead->CompressionSettings;
const TextureMipGenSettings OldMipGenSettings = TextureToRead->MipGenSettings;
const bool OldSRGB = TextureToRead->SRGB;
TextureToRead->CompressionSettings = TC_VectorDisplacementmap;
TextureToRead->MipGenSettings = TMGS_NoMipmaps;
TextureToRead->SRGB = false;
TextureToRead->UpdateResource();
//Get FColor
const FColor* ImageData = (const FColor*)(TextureToRead->GetPlatformData()->Mips[0].BulkData.LockReadOnly());
ResCol = ImageData[I * TextureToRead->GetSizeX() + J];
//Reset Settings
TextureToRead->GetPlatformData()->Mips[0].BulkData.Unlock();
TextureToRead->CompressionSettings = OldCompressionSettings;
TextureToRead->MipGenSettings = OldMipGenSettings;
TextureToRead->SRGB = OldSRGB;
TextureToRead->UpdateResource();
#endif
//Return
return ResCol;
}
}
纹理导出
数据导出为纹理
将颜色数组压缩成缓存,保存为文件
格式为RGBA8,导出时压缩一次,png导入纹理又压缩一次,有一定误差
建议作为预览/测试纹理,需要精度请直接存储数据,运行时用数据生成纹理
bool U类名::方法名(int32 SizeX, int32 SizeY, const TArray<FColor>& Val, const FString Path)
{
//Quantity Mismatch
if (Val.Num() != SizeX * SizeY)return false;
//Compress To Bytes
TArray<uint8> ResFileBytes;
FImageUtils::CompressImageArray(SizeX, SizeY, Val, ResFileBytes);
//Create
return FFileHelper::SaveArrayToFile(ResFileBytes, *Path);
}
kismet中的纹理相关的函数,都对Texture2D->sourse中的参数进行了判断,CreateTransient出的纹理无法通过。
且纹理大小和奇偶有一定限制
暂时没有更好的导出方法
在材质中的使用
将实际数据、范围数组、对应颜色转为纹理
使用custom节点写个映射,制作成热力图
custom中的HLSL代码如下
其他
如果需要精度,所有流程以数据驱动。
对纹理的导出、读取存在限制和误差,仅作为辅助工具使用