Unity iOS使用ASTC格式纹理实践

article/2025/11/10 6:33:08

引言

上一篇文章描述了如何在不修改自定义渲染组件的前提下使用 alpha 分离的纹理来提升 iOS 的透明压缩纹理质量(见这里:https://indienova.com/indie-game-development/unity-alpha-separate/)。

在这个方案投入项目开始使用一段时间之后,UI 同学又来找我抱怨了:虽然一些贴图的不透明部分不会显得脏了,但是为什么有些纹理的半透明部分表现这么奇怪呀?这就涉及到上次方案中透明通道贴图格式的选择问题了。在上一篇文章中,我们的透明通道贴图在 iOS 上使用了 pvrtc4 的压缩方式,这样的做法造成了部分贴图半透明部分显示上的效果降低,在一些特定的情况下效果甚至没法接受。那么如何解决这个问题呢?这一次我们要来说明另一种贴图质量低下的解决方案:使用 ASTC 格式纹理,并且解释针对目前部分硬件的限制所作出的调整。

ASTC

关于纹理格式的一些基础知识可以在上一篇文章中开头的基础中看到,在此不做赘述。这里简单说明一下 ASTC 这种格式。

 

1. 概述

ASTC(Adaptive Scalable Texture Compression)是一种基于块的有损纹理压缩格式,完整细节在 2012 年被提出。这种压缩格式有多种压缩率可选,同时有着较高的压缩率和较好的压缩质量。

 

2. 压缩率

 

在上面的表中展示了从 ASTC 格式从 4x4 到 12x12 每一个像素所占的比特数(bpp),可以看到最大(也就是 4x4)的占用为每个像素一个字节,那么一张 1024x1024 的贴图,使用 ASTC 4x4 压缩后,他的大小就是 1MB,这个大小和 ETC2 RGBA 8bpp 格式的大小相同。

 

3. 纹理质量

从结果来看,在相同的内存占用前提下,ASTC 相较其他传统压缩格式的质量更优;而在相同的质量前提下,占用内存更小。关于 ASTC 的压缩类型选择和质量相关说明, 可以参考这里:https://developer.nvidia.com/astc-texture-compression-for-game-assets

 

4. 支持机型

iOS 上,苹果从 A8 处理器开始支持 ASTC 格式(即从 iphone6,iPad mini 4 开始支持),而以前的 iPhone 5s 和 iPad mini 3 及之前的设备都不支持。

Android 上,未来的压缩格式正在从 ETC2 转向 ASTC。但是因为 android 机多样性,目前的市场普及率我暂不可知。

基本使用

现在在 Unity 中要使用 ASTC 格式非常简单:选择纹理导入设置,选择 ASTC 格式,完成!

这就结束了吗?显然事情并没有这么简单,上面提到过的硬件的限制使得我们无法这么简单的选择,因为在不支持的硬件上使用 ASTC 格式,会被软解为 RGBA,从而数倍的增加其内存占用,让游戏瞬间被系统杀掉。

针对这些硬件限制,我们基于项目本身的特点一般有以下的考量:

  1. 在 iOS 上如果项目是个大型游戏,可以放弃低端机器的用户,那么就直接使用 ASTC
  2. 在 android 上,如果可以得到准确的市场占有率,并确定可以放弃这一部分市场的前提下,可以直接使用 ASTC
  3. 现在立项的移动端游戏,且未来会有开发时长 2 年以上的,可以考虑只使用 ASTC
  4. 否则,如果你想考虑低端用户,那么还是需要考虑 ASTC 和传统格式的兼容性问题,我们接下来就会讲到这套实现方案:根据硬件条件选择使用不同的纹理格式。

根据硬件条件选择使用不同纹理格式

1. 基本思路

首先,对于直接引用打入包内的方式是不适合本方案的。本方案基于通过 AssetBundle 加载资源的项目(包括动态加载和依赖加载)。

基本思路为:在打包时生成一份完整的 AssetBundle 包以后,再针对需要使用 ASTC 的纹理所在的 AssetBundle 包重新打一份 ASTC 版本的;在运行时根据硬件支持情况等信息来选择加载哪一份 AssetBundle 包(PVRTC/ASTC)。

这样在游戏运行过程中,如某个 prefab 引用了一个 sprite,可以通过硬件情况选择不同的 AssetBundle 包,加载不同包中相同的 Sprite,然后引用到不同压缩格式的纹理上,就达到了我们的目的。

 

2. 构建测试工程

基于上面的思路,我们来构建一个测试工程,测试工程需要包含以下内容:

  1. 打 AssetBundle 包流程
  2. 生成 BundleMap,记录 ASTC 信息,供运行时使用
  3. 生成 AtlasBundleMap,记录需要重新打 ASTC 版本 AssetBundle 包的信息,供打包时使用
  4. 运行时资源加载,根据硬件条件来选择不同的 AssetBundle 包

 

3. 实现细节

首先是打 AssetBundle 包流程,这块不会详细说,因为每个项目的实现都可能不同。在这里,我们的思路是:添加需要动态加载的 AB 包规则,最后计算出它们依赖的资源,按规则打成其他依赖 AB 包。下面的代码示意了这一过程。

var builder = new AssetBundleBuilder();
builder.AddSceneBundle("Assets/Scenes/Test.unity", "scenes_");
builder.AddSceneBundle("Assets/Scenes/Loading.unity", "scenes_");
builder.AddDirBundle("Assets/Textures/Dynamic", "", "textures_");
builder.UpdateSharedAssets();
builder.BuildAssetBundles(abPath, BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);

其中重点在 UpdateSharedAssets() 方法中,其中不仅计算了所有的依赖关系,同时记录了 AtlasBundleMap 和 BundleMap

下图为 BundleMap 的格式,最重要的几个字段是 BundleName(记录 AB 包名),AstcVariant(是否有其 ASTC 版本),AstcVariantBundleNameASTC 版本的 AB 包名)。这个文件会打入最终的 AB 包内,在运行时加载资源时根据 AstcVariant 和 AstcVariantBundleName 来判断并加载对应的 ASTC 版本的包。

下图为 AtlasBundleMap 的格式。这个文件记录了需要再打一份 ASTC 版本 AB 包的包名列表,在后续的打包过程中会用到。

经过上面的过程,完整的 AB 包已经都打出来了,下面需要重新打一批 ASTC 版本的 AB 包。首先重新打一次图集:

EditorSettings.spritePackerMode = SpritePackerMode.BuildTimeOnly;
Packer.SelectedPolicy = typeof(CustomSpritePackerPolicy).Name;
CustomSpritePackerPolicy.MakeAstc = true;
Packer.RebuildAtlasCacheIfNeeded(target, true, Packer.Execution.ForceRegroup);

上面需要注意的是:两次打图集需要有一个不同的标志:MakeAstc,第一次为 false,第二次为 true,在自定义的图集打包规则中才可以判断出两次需要打的是不同的图集。自定义图集规则中的实现为:

if (MakeAstc)
{if (IsTransparentCompressed(settings.format)){settings.format = Util.ASTC_RGBA_FORMAT;}else if (IsOpaqueCompressed(settings.format)){settings.format = Util.ASTC_RGB_FORMAT;}
}

更多的关于自定义图集规则可以参考官方文档:https://docs.unity3d.com/Manual/SpritePacker.html

之后使用同样的 BuildAssetBundleOptions,根据 AtlasBundleMap 中信息对相应资源再打一次 AB 包即可,打完后改名拷贝到之前的文件夹中,现在的 AB 包目录就像是这样

其中 astc_ 开头的都是对应的 AB 包的 ASTC 版本。

 

接下来我们来到运行时。首先是判断硬件是否支持 ASTC 格式:

public static bool DeviceSupportAstc()
{var support = true;support = support && SystemInfo.SupportsTextureFormat(ASTC_RGB_FORMAT);support = support && SystemInfo.SupportsTextureFormat(ASTC_RGBA_FORMAT);return support;
}

其次是加载资源:

private AssetBundle LoadBundleCore(string bundleName)
{if (Util.UseAstc && m_bundleMap != null){BundleMapData bundleMapData = null;if (m_bundleMap.TryGetValue(bundleName, out bundleMapData)){if (bundleMapData.AstcVariant){bundleName = bundleMapData.AstcVariantBundleName;}}else{Debug.LogError("Cannot find bundle name in bundle map: " + bundleName);}}var bundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + bundleName);return bundle;
}

这是所有加载 AB 包时都会调用到的方法(包括动态加载和依赖加载)。其中的过程也很简单:判断了硬件情况,根据 BundleMap 找到需要加载的 ASTC 版本的 AB 包名,并去加载。

 

到这里以后我们的测试工程就已经完成了(详细的代码可以看文末的代码仓库一节)。我们可以看到在这个 demo 中,我们可以显示当前动态加载和依赖加载的纹理格式,并切换到另一种纹理,实现了 ASTC 和传统格式之间的选择性加载。

我们再使用 Profiler 工具来对比一下两种不同格式的纹理的内存占用:

上图为 ETC2 格式(为了测试方便,没有使用 PVRTC,结果是一样的)的内存占用,64.2KB,即等于 256*256*8/8

上图为 ASTC 6x6 格式的内存占用,29.1KB,即等于 256*256*3.56/8
ASTC 6x6 的内存占用比 PVRTC 4bpp 还小了 10%,但是质量却要好的很多很多。

补充说明

1. 延伸一下,因为上面的方案多生成了一批图集相关的 AB 包,所以会让包体有所增大。如果你们项目中有资源更新,那么支持 ASTC 和不支持 ASTC 的设备就需要根据自己的情况来下载不同的资源包。如果要做的好的话这个问题也是需要考虑的。当然这里就不讨论了,有需要的同学可以自己研究。

2. 引言中提到的透明通道贴图 PVRTC RGBA 4bpp 格式造成了贴图的半透明区域显示质量差的问题。我之后也尝试使用 Alpha8 格式来代替,但是实际测试发现所有图都看不到了,通过看 Unity 的默认 spriterenderer 和 DefaultETC1 的 shader 才知道,他们都使用了 alpha 通道贴图的 R 通道,而 Alpha8 格式取不到,所以贴图都不显示了。要解决这个问题可能需要使用 R8 格式来代替 Alpha8 格式,但是因为我使用的 Unity2017 不支持,所以就没有继续尝试了。

结论

包括前一篇文章,在 iOS 上我们一共使用了 3 种贴图压缩格式的方案(android 同理):

  • 直接使用 PVRTC
  • 分离透明通道的 PVRTC+PVRTC,或者 PVRTC+Alpha8
  • 根据硬件情况的不同来选择使用 PVRTC 还是 ASTC

这几种方案各有优劣和使用场景,我下面就试着总结一下。

 

1. 方案优缺点对比

 

PVRTC:

  • 优点:开发方便,不需要做额外处理,所有 iOS 设备统一支持
  • 缺点:纹理质量很差

分离透明通道:

  • 优点:不受硬件限制
  • 缺点:开发繁琐(一次性),如果使用 pvrtc+pvrtc 方案,半透明区域质量不好;如果使用 pvrtc+alpha8 方案,内存占用会增加到 12bpp,且可能不支持所有 unity 版本

根据硬件选择使用 PVRTC 还是 ASTC:

  • 优点:内存占用少,纹理质量高
  • 缺点:开发繁琐(一次性),包体图集纹理占用存储空间多一倍

 

2. 方案适用场景对比

 

PVRTC:

  • 适用于:不那么关注贴图质量,希望内存占用低,希望开发成本低
  • 不适用于:有品质要求的项目

分离透明通道:

  • 适用于:希望透明贴图的非透明部分不脏,不希望包体增大,2018 以上版本 unity 项目,对于内存占用不那么敏感
  • 不适用于:2018 以下版本 unity 项目,希望内存占用低

根据硬件选择使用 PVRTC 还是 ASTC:

  • 适用于:对包体体积不那么敏感,有开发能力和时间,希望纹理质量高同时内存占用小
  • 不适用于:对包体体积敏感,开发能力和时间有限

参考资料

  • ASTC 纹理压缩格式详解:
    https://zhuanlan.zhihu.com/p/158740249
  • Using ASTC Texture Compression for Game Assets:
    https://developer.nvidia.com/astc-texture-compression-for-game-assets

代码仓库

https://github.com/RayRiver/UnityAstcSupportDemo

参考链接:

ASTC纹理压缩格式详解

UI优化方案(2)——RGBA,压缩格式,纹理大小计算

 

 

 

 

 

 

 


http://chatgpt.dhexx.cn/article/GxQ1M1jQ.shtml

相关文章

ASTC纹理压缩格式详解

https://zhuanlan.zhihu.com/p/158740249 一、ASTC纹理压缩格式介绍 ASTC是在OpenGL ES3.0出现后在2012年中产生的一种业界领先的纹理压缩格式,它的压缩分块从4x4到12x12最终可以压缩到每个像素占用1bit以下,压缩比例有多种可选。ASTC格式支持RGBA&…

astc纹理压缩格式

astc是当前android和ios平台下压缩最好的纹理格式,并且主流的机器基本都支持, astc:支持非2次幂的,2次幂的,等宽高的 一、ASTC纹理压缩格式介绍 ASTC是在OpenGL ES3.0出现后在2012年中产生的一种业界领先的纹理压缩格式。 它的压…

ASTC textures

ASTC textures 原文:https://arm-software.github.io/opengl-es-sdk-for-android/astc_textures.html This document describes usage of compressed ASTC textures. Introduction This tutorial shows how Adaptive Scalable Texture Compression (ASTC) can be …

[图形学]ASTC纹理压缩格式

纹理压缩的目的 1,降低内存,特别是移动端应用,内存占用不应过大,否则低端机很容易崩溃 2,降低带宽,手游类应用,在渲染时会有大量贴图传输到GPU,不限制的话不仅会严重影响渲染性能&a…

ASTC纹理压缩格式(Adaptive Scalable Texture Compression)

原文:这是一个pdf的下载链接 介绍 Adaptive Scalable Texture Compression(ASTC)是一种世界领先的新型纹理压缩格式。这种压缩格式已经加入Khronos标准,并已在某些硬件平台中提供。本文介绍了它的工作原理、使用方法和如何最大程度地使用它。更深入的信…

ASTC纹理压缩格式介绍

一、ASTC纹理压缩格式介绍 ASTC是在OpenGL ES 3.0出现后,在2012年中产生的一种业界领先的纹理压缩格式,它的压缩分块从4x4到12x12最终可以压缩到每个像素占用1bit以下,压缩比例有多种可选。ASTC格式支持RGBA,且适用于2的幂次方长宽…

选择软件人力外包公司看这几点没错

近几年,大数据、云计算等各种互联网技术飞速发展,深入到我们工作生活的各个角落。很多企业为了提升竞争力也加快了信息化建设的步伐,而信息化建设的关键就是软件人才,谁能快速构建真正高效的软件开发团队,谁就能先一步…

10 个Web3 设计灵感网站

10 个Web3 设计灵感网站:Cosmos、Axies Infinity、DeSo Foundation、Foundation App、Llama、Snapshot、Juicebox、Alchemy、RabbitHole 正如Twitter前首席执行官Jack Dorsey最近发的一条推文“你不拥有web3,但风险投资家拥有”,而Marc Andre…

web 服务器有哪些

<1>什么是web服务器 "网络服务"&#xff08;Web Service&#xff09;的本质&#xff0c;就是通过网络调用其他网站的资源。 Web Service架构和云 如果一个软件的主要部分采用了"网络服务"&#xff0c;即它把存储或计算环节"外包"给其他…

要不要进外包?

互联网行业的估计都听过这句话:外包&#xff0c;你是外包&#xff0c;麻烦不要偷吃公司零食&#xff0c;注意素质&#xff01; 事情是这样的:她说自己被外派到一家大公司上班&#xff0c;因为那家公司是大公司&#xff0c;在休息的时候还提供零食和下午茶。大家都知道女生爱吃…

为什么程序员做外包会被瞧不起?

二哥&#xff0c;有个事想询问下您的意见&#xff0c;您觉得应届生值得去外包吗&#xff1f;公司虽然挺大的&#xff0c;中xx&#xff0c;但待遇感觉挺低&#xff0c;马上要报到&#xff0c;挺纠结的。 以上是读者小 K 给我发的私信。除此之外&#xff0c;还有个读者 down 也问…

被迫选择了到了外包公司

即使大厂裁员下来的员工愿意被迫选择了到了外包公司&#xff0c;迫不得已做外包的工作&#xff0c;那么&#xff0c;中小型企业那势必也得裁员&#xff0c;为了接收从大厂下来的&#xff0c;有大厂背景的员工&#xff0c;那么就会裁掉自己公司的员工。 这样看来&#xff0c;这…

测试应届生是去自研小公司好还是外包公司好?

我不知道当年怎么想的&#xff0c;能在一个外包公司一干就是3年&#xff0c;后来终于跳出来了&#xff0c;现在的公司虽然不是什么大厂吧&#xff0c;但至少是个正经的互联网企业&#xff0c;待遇也不错。其实很多地方的朋友都有提到外包公司的一些弊端。 外包公司&#xff1a…

网站建设公司该不该把web前端外包出来!精辟

如今的网站建设公司其实过的并不好&#xff0c;一些建站平台、模板建站、仿站等都对网站定制造成了比较大的影响&#xff0c;网站建设公司如何降低用人成本、灵活的整合第三方资源成为度过“特殊时期”的重要手段&#xff0c;迎接下一波春天的到来。 网站建设公司该不该把前端…

外包公司面试门槛高吗?软件测试员进外包公司容易吗?

虽然很多测试人员都抵制外包&#xff0c;但实际情况则是依旧有大量软件测试员&#xff0c;选择加入到外包这个圈子。外包公司面试门槛高吗?外包公司容易进吗?本篇来解答一下这个问题。 外包公司面试门槛高吗&#xff1f; 外包的面试门槛&#xff0c;相对大厂要低很多。尤其…

我的web前端工作日记11------在腾讯外包的这一年

说在前面的话 本文只是大概说一下自己在腾讯做了一年前端外包的收获和一些心得感悟&#xff0c;希望自己能客观的描述&#xff0c;能给一些后来者参考取舍&#xff0c;看是否值得去腾讯做外包。写的没啥逻辑&#xff0c;都是想到啥就写啥&#xff0c;所以大家将就着看看。 一…

进程平均周转时间的计算

题目&#xff1a; 有4个进程A,B,C,D,设它们依次进入就绪队列&#xff0c;因相差时间很短可视为同时到达。4个进程按轮转法分别运行11,7,2,和4个时间单位&#xff0c;设时间片为1。四个进程的平均周转时间为 &#xff08;&#xff09;&#xff1f; 分析 要理解周转时间的含义&am…

操作系统进程完成时间,周转时间,带权周转时间, 平均周转时间, 带权平均周转时间计算

计算规则 周转时间作业完成时刻-作业到达时刻&#xff1b; 带权周转时间周转时间/服务时间&#xff1b; 平均周转时间作业周转总时间/作业个数&#xff1b; 平均带权周转时间带权周转总时间/作业个数&#xff1b;

平均周转时间和平均带权周转时间怎么算?

周转时间&#xff1a;从作业被提交给系统开始&#xff0c;到作业完成为止的这段时间间隔称为作业周转时间。 带权周转时间&#xff1a;即作业的周转时间T与系统为它提供服务的时间Ts之比&#xff0c;即W  T/Ts 周转时间 作业完成时刻 - 作业到达时刻带权周转时间 周转时间…

操作系统:周转时间和其他时间

1&#xff0c;周转时间 周转时间&#xff1a;作业被提交给系统开始&#xff0c;到作业完成为止的这段时间间隔。 包括&#xff1a;&#xff08;1&#xff09;作业在外存后备队列上的等待作业调度的时间。&#xff08;2&#xff09;进程在就绪队列上等待进程调度的时间。&#x…