UTexture2DArray数据是只有Editer下存有,但是有些时候需要在Runtime动态添加纹理,所以需要重写一下。
Texture2DArrayWrapper.h
// Copyright 2022 Dexter.Wan. All Rights Reserved. // EMail: 45141961@qq.com #pragma once #include "CoreMinimal.h" #include "UObject/Object.h" #include "Texture2DArrayWrapper.generated.h" /** * */ UCLASS() class UTexture2DArrayWrapper : public UObject { GENERATED_BODY() public: UTexture2DArrayWrapper(const FObjectInitializer& ObjectInitializer); public: UPROPERTY(BlueprintReadWrite, EditAnywhere) TArray<UTexture2D*> SourceTextures; UFUNCTION(BlueprintCallable, BlueprintPure) UTexture2DArray* GetTextureArray() const; UFUNCTION(BlueprintCallable) void UpdateTextureArray(int32 TemplateIndex = 0); UFUNCTION(BlueprintCallable, BlueprintPure) const TArray<UTexture2D*>& GetTextures() const; private: UPROPERTY() UTexture2DArray* Texture2DArray; UPROPERTY() TArray<UTexture2D*> Textures; };
Texture2DArrayWrapper.cpp
// Copyright 2022 Dexter.Wan. All Rights Reserved. // EMail: 45141961@qq.com #include "Texture2DArrayWrapper.h" #include "Engine/Texture2D.h" #include "Engine/Texture2DArray.h" PRAGMA_DISABLE_OPTIMIZATION UTexture2DArrayWrapper::UTexture2DArrayWrapper(const FObjectInitializer& ObjectInitializer) { Texture2DArray = CreateDefaultSubobject<UTexture2DArray>(TEXT("Texture2DArray")); Texture2DArray->UpdateResource(); } UTexture2DArray* UTexture2DArrayWrapper::GetTextureArray() const { return Texture2DArray; } void UTexture2DArrayWrapper::UpdateTextureArray(int32 TemplateIndex) { // 重置有效纹理表列 Textures.Reset(); // 获取纹理数组的平台数据 FTexturePlatformData*& PlatformData = *Texture2DArray->GetRunningPlatformData(); // 如果纹理源为空 删除平台数据并更新渲染资源 if (SourceTextures.Num() == 0) { if (PlatformData != nullptr) { delete PlatformData; PlatformData = nullptr; } Texture2DArray->UpdateResource(); return; } // 如果模板索引无效 默认使用第0个纹理做模板 TemplateIndex = SourceTextures.IsValidIndex(TemplateIndex) ? TemplateIndex : 0; // 获取模板纹理 UTexture2D* TemplateTexture = SourceTextures[TemplateIndex]; // 得到模板纹理的平台数据 const FTexturePlatformData* TemplatePlatformData = *((UTexture*)TemplateTexture)->GetRunningPlatformData(); // 取得模板纹理的长宽 const int64 SizeX = TemplatePlatformData->SizeX; const int64 SizeY = TemplatePlatformData->SizeY; // 取得模板纹理的像素格式 const EPixelFormat PixelFormat = TemplatePlatformData->PixelFormat; // 筛选有效的纹理 for (UTexture2D* Texture : SourceTextures) { const FTexturePlatformData* SourcePlatformData = *((UTexture*)Texture)->GetRunningPlatformData(); bool bIsInvalid = false; // 只有长宽与纹理格式都符号模板才有效 bIsInvalid |= SourcePlatformData->SizeX != SizeX; bIsInvalid |= SourcePlatformData->SizeY != SizeY; bIsInvalid |= SourcePlatformData->PixelFormat != PixelFormat; if (!bIsInvalid) { Textures.AddUnique(Texture); } } // 获取纹理数组元素数与Mip层数 const int64 NumSlices = Textures.Num(); const int64 NumMips = TemplatePlatformData->Mips.Num(); // 设置一般属性 Texture2DArray->AddressX = TemplateTexture->AddressX; Texture2DArray->AddressY = TemplateTexture->AddressY; Texture2DArray->AddressZ = TextureAddress::TA_Wrap; Texture2DArray->SRGB = TemplateTexture->SRGB; Texture2DArray->Filter = TemplateTexture->Filter; Texture2DArray->MipLoadOptions = TemplateTexture->MipLoadOptions; // 如果平台数据不存在则创建 if (PlatformData == nullptr) { PlatformData = new FTexturePlatformData(); } // 设置纹理长宽元素数与像素格式 PlatformData->SizeX = SizeX; PlatformData->SizeY = SizeY; PlatformData->PackedData = NumSlices; PlatformData->PixelFormat = PixelFormat; // 删除多余的Mip层 if (PlatformData->Mips.Num() > NumMips) { PlatformData->Mips.RemoveAt(NumMips, PlatformData->Mips.Num() - NumMips); } // 遍历每个Mip层 for (int32 MipIndex = 0; MipIndex < NumMips; ++MipIndex) { // 获取模板上对应的Mip层 const FTexture2DMipMap& TemplateMip = TemplatePlatformData->Mips[MipIndex]; // 获取此Mip层的元素字节数与总字节数 const int64 ElementBytesCount = TemplateMip.BulkData.GetElementCount(); const int64 MipBytesCount = ElementBytesCount * NumSlices; // 确保当前Mip层对象存在 if (!PlatformData->Mips.IsValidIndex(MipIndex)) { check(PlatformData->Mips.Num() == MipIndex); PlatformData->Mips.Add(new FTexture2DMipMap()); } // 取得纹理数组中的Mip层对象 FTexture2DMipMap& Mip = PlatformData->Mips[MipIndex]; // 设置当前Mip层长宽及元素数 Mip.SizeX = TemplateMip.SizeX; Mip.SizeY = TemplateMip.SizeY; Mip.SizeZ = NumSlices; // 以读写方式锁定当前Mip层 Mip.BulkData.Lock(LOCK_READ_WRITE); // 重置Mip层到所需大小 void* BulkData = (uint8*)Mip.BulkData.Realloc(MipBytesCount); // 遍历每个纹理元素 for (int32 SliceIndex = 0; SliceIndex < NumSlices; ++SliceIndex) { // 获取源纹理平台数据 FTexturePlatformData*& SourcePlatformData = *((UTexture*)Textures[SliceIndex])->GetRunningPlatformData(); // 获取源纹理对应Mip层 FTexture2DMipMap& SourceMip = SourcePlatformData->Mips[MipIndex]; // 以只读方式锁定源纹理Mip层 const void* SourceBulkData = SourceMip.BulkData.Lock(LOCK_READ_ONLY); // 从源纹理复制数据到纹理数组中 FMemory::Memcpy((uint8*)BulkData + ElementBytesCount * SliceIndex, SourceBulkData, ElementBytesCount); // 解锁源纹理Mip层 SourceMip.BulkData.Unlock(); } // 解锁当前Mip层 Mip.BulkData.Unlock(); } // 更新纹理数组渲染资源 Texture2DArray->UpdateResource(); } const TArray<UTexture2D*>& UTexture2DArrayWrapper::GetTextures() const { return Textures; } PRAGMA_ENABLE_OPTIMIZATION