本仓库是基于 UnityAsyncImageLoader v0.1.2 在Unity2021.3
版本开发,且原始代码已经包含在仓库中。
本包包含以下主要功能:
-
图像加载、图像解码和Mipmap生成的工作转移到其他线程中,它可以使游戏运行更加流畅,并减少在加载大图像时Unity主线程的卡顿。
-
将加载后的纹理数据进行加工,符合POT纹理的尺寸要求。
-
运行时更改纹理尺寸,可在运行时压缩为ASTC和DXT5格式,以节省内存空间。
-
创建
Texture2DInfo类包装纹理数据。 -
增加
Texture2D类相关的实用拓展方法。
Unity注册包请在UPM窗口中选择Unity Registry项搜索安装;托管包请在UPM中使用Add git RUL方式进行安装:
- Unity Burst
- Unity Mathematics
- UniTask:https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask
-
通过克隆仓库安装
将本仓库克隆到您的 Unity 项目的
Assets目录下, 如果使用克隆方式安装,需要 手动添加上方的依赖项。git clone https://github.com/Pixelsmao/UnityCommonSolution-NativeTextureAsyncLoader.git
-
使用UPM进行安装:
在 Unity 编辑器中,点击顶部菜单栏,打开 Package Manager 窗口.
Window > Package Manager在 Package Manager 窗口的左上角,点击 + 按钮,然后选择 Add package from git URL...。 在弹出的输入框中,粘贴本仓库的 Git URL:
https://github.com/Pixelsmao/UnityCommonSolution-NativeTextureAsyncLoader.git
然后点击 Add。
在运行时加载大尺寸图像(大于2K)时,ImageConversion.LoadImage
和 Texture2D.LoadImage 会变得非常缓慢。它们在加载图像时会阻塞Unity的主线程,持续时间可能从几百毫秒到几秒不等。这对于那些希望在运行时动态加载图像的游戏和应用程序来说,是一个致命的问题。
本包旨在将图像加载、图像解码和Mipmap生成的工作转移到其他线程中。它可以使游戏运行更加流畅,并减少在加载大图像时Unity主线程的卡顿。
本包使用了 FreeImage,这是Unity用于处理图像数据的同一库。
/// <summary>图像加载器使用的设置。</summary>
public struct LoaderSettings {
/// <summary>创建线性纹理。仅适用于创建新 <c>Texture2D</c> 的方法。默认为 false。</summary>
public bool linear;
/// <summary>加载后纹理数据在CPU上不可读。默认为 false。</summary>
public bool markNonReadable;
/// <summary>是否生成Mipmap。默认为 true。</summary>
public bool generateMipmap;
/// <summary>自动计算Mipmap层级数量。默认为 true。仅适用于创建新 <c>Texture2D</c> 的方法。</summary>
public bool autoMipmapCount;
/// <summary>Mipmap数量,包括基础层级。必须大于1。仅适用于创建新 <c>Texture2D</c> 的方法。</summary>
public int mipmapCount;
/// <summary>用于显式指定图像格式。默认为 FIF_UNKNOWN,图像格式将自动确定。</summary>
public FreeImage.Format format;
/// <summary>是否记录此方法捕获的异常。默认为 true。</summary>
public bool logException;
public static LoaderSettings Default => new LoaderSettings {
linear = false,
markNonReadable = false,
generateMipmap = true,
autoMipmapCount = true,
format = FreeImage.Format.FIF_UNKNOWN,
logException = true,
};
} var imageData = File.ReadAllBytes();
var texture = new Texture2D(1, 1);
var loaderSettings = AsyncImageLoader.LoaderSettings.Default;
var success = false;
// =====================================
// 将图像数据加载到现有纹理中
// =====================================
// 使用默认的LoaderSettings
success = await AsyncImageLoader.LoadImageAsync(texture, imageData);
// 类似于ImageConversion.LoadImage
// 读取后将纹理标记为不可读。
success = await AsyncImageLoader.LoadImageAsync(texture, imageData, true);
// 使用自定义的LoaderSettings
success = await AsyncImageLoader.LoadImageAsync(texture, imageData, loaderSettings);
// ==================================
// 从图像数据创建新纹理
// ==================================
// 使用默认的LoaderSettings
texture = await AsyncImageLoader.CreateFromImageAsync(imageData);
// 使用自定义的LoaderSettings
texture = await AsyncImageLoader.CreateFromImageAsync(imageData, loaderSettings);同步版本的函数与异步版本相同,只是函数名中去掉了 Async 后缀。它们适用于在单帧内进行调试和性能分析。
var imageData = File.ReadAllBytes();
var texture = new Texture2D(1, 1);
var loaderSettings = AsyncImageLoader.LoaderSettings.Default;
var success = false;
// =====================================
// 将图像数据加载到现有纹理中
// =====================================
// 使用默认的LoaderSettings
success = AsyncImageLoader.LoadImage(texture, imageData);
// 类似于ImageConversion.LoadImage
// 读取后将纹理标记为不可读。
success = AsyncImageLoader.LoadImage(texture, imageData, true);
// 使用自定义的LoaderSettings
success = AsyncImageLoader.LoadImage(texture, imageData, loaderSettings);
// ==================================
// 从图像数据创建新纹理
// ==================================
// 使用默认的LoaderSettings
texture = AsyncImageLoader.CreateFromImage(imageData);
// 使用自定义的LoaderSettings
texture = AsyncImageLoader.CreateFromImage(imageData, loaderSettings);如果图像具有Alpha通道,格式将为 RGBA32,否则为 RGB24。
如果 LoadImage 和 LoadImageAsync 的 generateMipmap 设置为 true
,则Mipmap数量将设置为该纹理的最大可能值。如果你想控制Mipmap的数量,可以使用 CreateFromImage 和 CreateFromImageAsync。
Mipmap使用2x2核的盒式滤波生成。最终结果与在编辑器中使用纹理导入时的Unity默认结果不同。
在 AsyncImageLoader 方法执行完毕后,图像数据仍在传输到GPU。因此,任何想要使用该纹理的对象(如材质或UI)都必须等待纹理上传完成,从而阻塞Unity的主线程。
目前没有简单的方法来检测纹理是否已完成上传。以下是一些解决方法:
- 在使用纹理前等待一秒钟或更长时间。
- (未测试) 使用
AsyncGPUReadback从纹理中请求一个像素。它将等待纹理上传完成后才会下载该像素。然后可以使用请求回调来通知Unity主线程纹理上传已完成。
本包灵感来源于Matias Lavik的 unity-async-textureimport。