解释SpriteAtlas的Variant与Scale机制

解读

国内项目面试时,面试官真正想确认的是:

  1. 你是否亲手落地过高清/低清资源分包动态下载方案;
  2. 能否用Variant+Scale在不重新打包图集的前提下,让同一套图集在iPhone SE、iPad Pro、4K电视上一次性采样正确,并且内存不涨、包体不增
  3. 是否理解Unity底层对Texture2D.masterTextureLimitmipmap biasVariant Scale优先级顺序,从而解释为什么“Scale=0.5”在部分安卓机上没生效

知识点

  1. SpriteAtlas Variant:

    • 本质是一张指向另一张SpriteAtlas的软链接,在打包时不复制纹理数据,仅记录scale因子平台标签
    • 通过Variant名字后缀(如“@2x”“@0.5x”)让SpriteRenderer、UI Image、Addressables运行时自动切换引用,无需改代码
    • Android APK Expansion (OBB)iOS On-Demand Resource中,Variant可被单独标记为远程包,实现高清资源按需下载
  2. Scale机制:

    • 值范围0.1~1.0线性影响最终纹理尺寸;Scale=0.5表示宽高调至50%内存占用降至25%
    • mipmap共存时,Unity会优先取Variant Scale再算mipmap层级,因此Scale=0.5 + mipmap level1实际得到原始25%尺寸
    • Linear颜色空间下,Scale后贴图滤波重新走一遍sRGB→Linear转换,若原图集带透明渐变,需要勾选Variant sRGB防止色偏
    • GPU压缩格式继承规则:Variant会继承主图集的压缩设置,但PVRTC 4bpp在Scale<0.5时会被自动降级为ETC2_RGB,导致iOS低端机出现色差,需手动覆盖Platform Settings
  3. 运行时切换流程:

    • SpriteAtlasManager.atlasRequested回调里按屏幕dpi/内存等级决定加载哪一套Variant
    • Addressables.LoadAssetAsync<SpriteAtlas>("UIAtlas@0.5x")返回的Variant不会触发主图集加载依赖链完全隔离,因此内存峰值可控
    • AssetBundle模式下,Variant必须与主图集打在同组,否则Sprite引用会丢失,表现为紫色图元

答案

“SpriteAtlas的Variant是Unity提供的零冗余多分辨率方案。打包时我只需在SpriteAtlas Inspector里点击Create Variant,填好Scale=0.5,Unity会生成一张不复制像素数据虚拟图集。运行时我通过SpriteAtlasManager.atlasRequested回调,按dpi>400加载@2x、内存<1G加载@0.5x,同一份代码无需改动。Scale机制会把原始纹理宽高同步缩小内存平方级下降,但压缩格式继承需要手动检查,否则iOS PVRTC在Scale<0.5时会被降级为ETC2,出现色带。整个流程我已在XX项目落地,高清资源放可下载包首包减少120MB低端机内存降低35%无线上紫图问题。”

拓展思考

  1. 如果策划要求同一套图集在4K电视上显示@2x,但TV端内存只有1.5G,如何用Variant+自定义mipmap bias做到既清晰又不爆内存
  2. 当项目使用Addressables + SpriteAtlas Variant时,远程Variant更新后本地缓存的主图集已存在,如何保证Sprite引用不重新打包又能立即生效
  3. Unity 2022.3新增的Runtime SpriteAtlas Variant API允许动态创建Variant,请设计一套按帧率实时降级的方案,防止中低端机发热降频