UTexture2DArray Runtime 下添加图片

简介: UTexture2DArray Runtime 下添加图片

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
相关文章
UE插件开发引用包含第三方库头文件问题总结
UE插件开发引用包含第三方库头文件问题总结
508 0
|
存储 开发框架 算法
【串口通信】使用C++和Qt设计和实现串口协议解析器(一)
【串口通信】使用C++和Qt设计和实现串口协议解析器
3275 0
|
6月前
|
XML 前端开发 测试技术
如何使用 Postman 发送 POST XML 请求?
使用 Postman 发送带有 XML 数据的 POST 请求。我们将引导您完成将 XML 数据有效发送到 Web 服务或 API 的步骤,使处理这种常见数据格式变得简单易行。
|
11月前
|
物联网 5G 智能硬件
介绍频段、带宽、频率、调制、解调等基础术语,以及Wi-Fi、蓝牙、ZigBee、UWB、LTE、5G等常见无线通信技术
在无线通信领域,专业术语是理解技术的关键。本文详细介绍了频段、带宽、频率、调制、解调等基础术语,以及Wi-Fi、蓝牙、ZigBee、UWB、LTE、5G等常见无线通信技术,还涵盖了信号传播、信道容量、信噪比等深入概念。通过本文,你将掌握无线技术的核心知识,成为半个无线专家。
1468 4
|
7月前
|
Linux 数据安全/隐私保护 Windows
文件传输告别龟速!1分钟搞定Windows↔CentOS高速通道 小白也能玩转的Xftp秘籍
Xftp 是一款便捷的远程文件传输工具,与 XShell 类似,支持通过 SFTP 协议实现文件上传和下载。首先需下载安装 Xftp,并获取目标 Linux 系统(如 CentOS)的 IP 地址。打开 Xftp 后,按 `Ctrl + N` 新建会话,输入主机 IP、协议(SFTP)、用户名和密码连接服务器。
416 15
文件传输告别龟速!1分钟搞定Windows↔CentOS高速通道 小白也能玩转的Xftp秘籍
|
7月前
|
SQL 分布式计算 数据库
【YashanDB知识库】Hive 命令工具insert崖山数据库报错
【YashanDB知识库】Hive 命令工具insert崖山数据库报错
|
存储 API 图形学
Unity3D学习笔记6——GPU实例化(1)
Unity3D学习笔记6——GPU实例化(1)
201 0
UE DT Load Texture 运行时加载纹理图片 插件说明
UE DT Load Texture 运行时加载纹理图片 插件说明
312 0
|
缓存 图形学 UED
U3D开发技术深度解析:异步场景加载与资源管理优化策略
【7月更文第11天】在Unity3D(简称U3D)游戏开发中,优化场景加载与资源管理是提升用户体验的关键一环。通过实现高效的异步场景加载和智能的资源管理策略,我们能显著缩短玩家的等待时间,提升游戏流畅度。本文将详细介绍这两种技术的应用,并提供实用的代码示例。
1117 0
|
Rust 监控 安全
局域网远程桌面监控软件的性能优化技巧(Rust)
随着远程办公的兴起,局域网远程桌面监控软件的需求与日俱增。为了提高软件的性能和用户体验,我们可以利用Rust语言的特性进行优化。本文将介绍一些优化技巧,并提供一些代码示例,帮助开发者更好地优化远程桌面监控软件。
406 0