オンメモリでテクスチャをPNG形式にしてアップロードしたかったのでUTextureをPNGのTArray形式に変換してみました。
UE4.27.2、UE5.1.1で確認しています。
以下のコードを参照しています(ほぼそのままです)。
- Engine/Source/Runtime/ImageWriteQueue/Private/ImageWriteBlueprintLibrary.cpp
- c++ - How to export FTexture2DRHIRef to png? - Stack Overflow
ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETERを使うとENQUEUE_RENDER_COMMANDを使えと怒られたので以下のページを参照して対応しました。
#include "ImageUtils.h"
#include "GenericPlatform/GenericPlatformProcess.h"
void HogeHoge::Convert(UTexture* Img, TArray<uint8>& ImgData)
{
if (!Img || !Img->Resource || !Img->Resource->TextureRHI)
{
UE_LOG(LogTemp, Warning, TEXT("Upload Texture is invalid"));
return;
}
FTexture2DRHIRef Texture2D = Img->Resource->TextureRHI->GetTexture2D();
if (!Texture2D)
{
UE_LOG(LogTemp, Warning, TEXT("Upload Texture2D is invalid"));
return;
}
TArray<FColor> OutPixels;
struct FReadSurfaceContext
{
FTexture2DRHIRef Texture;
TArray<FColor>* OutData;
FIntRect Rect;
FReadSurfaceDataFlags Flags;
};
FReadSurfaceContext ReadSurfaceContext =
{
Texture2D,
&OutPixels,
FIntRect(0, 0, Texture2D->GetSizeXY().X, Texture2D->GetSizeXY().Y),
FReadSurfaceDataFlags(RCM_UNorm, CubeFace_MAX)
};
FReadSurfaceContext Context = ReadSurfaceContext;
ENQUEUE_RENDER_COMMAND(ReadSurfaceCommand)(
[Context](FRHICommandListImmediate& RHICmdList)
{
RHICmdList.ReadSurfaceData(
Context.Texture,
Context.Rect,
*Context.OutData,
Context.Flags
);
});
FlushRenderingCommands();
#if ENGINE_MAJOR_VERSION >= 5
TArray64<uint8> ImgData64;
FImageUtils::PNGCompressImageArray(Context.Rect.Width(), Context.Rect.Height(), OutPixels, ImgData64);
ImgData.AddUninitialized(ImgData64.Num());
FMemory::Memcpy(ImgData.GetData(), ImgData64.GetData(), ImgData64.Num() * sizeof(uint8));
#else
FImageUtils::CompressImageArray(Context.Rect.Width(), Context.Rect.Height(), OutPixels, ImgData);
#endif