Shader打AssetBundle包变体丢失问题

Shader打AssetBundle包变体丢失问题

1)Shader打AssetBundle包变体丢失问题
​2)Unity升级后在iOS平台的贴图导入问题
3)字体文件AssetBundle包崩溃
4)给主相机设置RT的注意事项
5)FBX的导入WeldVertices的设置问题


这是第271篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)

AssetBundle

Q:Unity官方后处理PostProcessing,进行AssetBundle打包时,变体太多(4000+),修改了uber.shader,屏蔽了项目中不可能使用的关键字(后期要使用也可以通过热更修改)。

AssetBundle打包后,发现变体没完全打包,Editor下查看Shader变体数量是300+,打包后使用AssetStudio查看AssetBundle,发现只打了100+的变体,大部分丢失。运行通过断点调试也验证了所有Key均设置,FrameDebug中也丢失了一些关键字。

uber.shader下所有关键字均是multi_compile 定义,理论上multi_compile定义的关键字都会全编译所有组合,但是打包后出现丢失。

A:在进行单元测试中,在一个空项目中打包uber.shader,发现打包后,变体正确。但是开发项目和打包项目依旧生成不正确。怀疑是Unity缓存原因。于是删除Library目录下shaderCache,再次打包,还是不正确。再次删除已生成的AssetBundle资源,完全重新生成,终于正确。

所以multi_compile定义的关键字打包出现问题,需要删除缓存和已生成的AssetBundle才能最终正确生成新的AssetBundle。

感谢题主1 9 7 3-311135@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/6167ff118f8c834241dc7777


Asset

Q:我们一直用贴图后处理脚本对贴图进行导入,在iOS平台使用ASTC_6x6格式。但是升级到Unity 2019,打开iOS工程,经同步缓存和导入完成后,大部分贴图的预览界面上并没有显示压缩格式和压缩后的尺寸,而是显示no yet compressed,似乎导入操作没有完成。Android平台并没出问题。

这样的贴图会显示模糊,并且打出的Bundle还会更大。手动Reimport可以解决。但是如果另外建立一份工程拷贝,则又会出现同样的问题。求问有什么解决方法?

A1:经查,是我这边的纹理资源导入后处理脚本(iOS)有问题,但是其在Unity 2018下不会体现出来,但是在Unity 2019中会直接让某些贴图的导入工作无法完成。由于使用了 Unity Accelerator(也就是Asset Pipeline v2对应的缓存服务器),重新导入也不会生成新的缓存,只能让进行重新导入的项目局部正常。

我们的导入后处理脚本中在iOS下,对JPG单独使用了不带透明通道的ATSC压缩。在Unity 2019中,ATSC压缩不再区分是否带透明通道。修改脚本+删除Unity Accelerator缓存+重新导入某个Working copy(同时也重建了缓存)可解决。

注意:上述无法导入完成的情况,打出包来会有两个明显的问题:包体变大、图片模糊。

感谢题主加菲教主@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/614ee1bc8f8c834241ba925e


AssetBundle

Q:AssetBundle打包参数BuildAssetBundleOptions.DisableWriteTypeTree。会极大缩减AssetBundle包大小,同时也带来运行时SerializaFile相同数量级下内存占用缩减一半左右,并提高加载速度。

官方说明比较简单:如果开启DisableWriteTypeTree选项,则可能造成AssetBundle对Unity版本的兼容问题。基于其带来的运行时优势,还是决定使用该选项。

导出测试包一切运行正常,热更新也运行正常,本来以为该优化就完结。但是后来发现相同的AssetBundle资源,在编辑器下AssetBundle运行会崩溃(必然出现),导出的测试包(所有平台)一切正常。(该问题必须要解决,因为游戏发布后线上的问题可以在本地调试复现,如果本地不能运行AssetBundle包或者运行不同的AssetBundle包原则上不允许。)

A:开始排查问题:首先定位到崩溃的资源,是TMPTextPro相关的字体资源包(复合包,包含了多个资源内容)。

验证BuildAssetBundleOptions.DisableWriteTypeTree的影响,屏蔽BuildAssetBundleOptions.DisableWriteTypeTree打包参数。打包后编辑器运行不崩溃,肯定了该参数造成的问题。(这里当时猜测是Unity内部代码的某个宏导致的,导致了在Editor下和发布时走了不同的解析代码,但是又没有源代码,无法具体验证。)

开始排除问题:
首先排除Unity的编辑器缓存造成的该问题,重置后依旧崩溃。

开始拆解问题包,将所有资源内容单个打包(一个资源对应一个包)。最后精确定位到是TMPTextPro的字体FontAsset资源包调用AssetBundle.LoadAsset()方法时崩溃。

分析问题:设置DisableWriteTypeTree参数将不在AssetBundle中包含相关的文件TypeTree信息,是因为没有该信息后导致的反序列化不正确,为什么其它资源能正常解析,就单单FontAsset会出现问题?打开TMP_FontAsset.cs源码,查看发现这么一段代码。

#if UNITY_EDITOR
///


/// Persistent reference to the source font file maintained in the editor.
///

[SerializeField]
internal Font m_SourceFontFile_EditorRef;
#endif

发现它居然在可序列化类中加入了条件编译,造成导出运行和编辑器运行该类的实现不一样。

这就是为什么导出包运行正确,编辑器崩溃的原因。因为AssetBundle打包时的UNITY_EDITOR是不成立的,会设置对应平台的宏。所以打包时FontAsset资源的数据是不包含m_SourceFontFile_EditorRef该属性的序列化信息,未开启DisableWriteTypeTree时,因为有TypeTree信息,编辑下运行程序能通过TypeTree信息正确反序列化,当设置DisableWriteTypeTree时,反序列化失败,直接崩溃。

解决:给属性m_SourceFontFile_EditorRef添加标签[NonSerialized],再对应修改一些Editor代码,让功能在Editor下也正确。

感谢题主1 9 7 3-311135@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/616a8e668f8c834241dfd78b


Rendering

Q:用setTargetBuffers方法将一张低分辨率RT设置给主相机。在屏幕分辨率不变的情况下,对场景相机做了降级。然后出现了一个问题是:所有的后处理都失效了,查看后发现所有OnRenderImage方法的Source都为null(我理解为没有设置Rendertarget,默认为屏幕)。我将上面那张FrameBuffer强行代替Source传入后处理,查看FramedeBugger,后处理几个Draw Call能正常渲染,但是仍旧不能对最终效果生效,也就说没有写入到上面的FrameBuffer。

我之前的解决方法是魔改所有OnRenderImage,传入FrameBuffer代替Source,输出到另外一张FinalBuffer,最后再绑定到屏幕上,下面是测试代码。



但项目中后处理比较多,且ImageBuffer仍存在后处理中,无端增加了RenderTexture的开销。

现在的处理方法是直接设置TargetTexture,但逻辑操作上会绕一层。想问下引起上面的原因,或者说有什么更好的解决方法?

环境是2019.4.3f + built-in + OpengES3.0,然后再用CommandBuffer将低分辨率适配到高分辨率。

A1:实践下来,建议还是用CommandBuffer来操作,比较灵活:

  1. OnPreRender阶段先设置好TargetBuffer(ColorBuffer:RTA、DepthBuffer:RTB)。
  2. 使用CommandBuffer在CameraEvent.BeforeImageEffects或者AfterImageEffects这个事件上做所有的后处理。
  3. 核心在于第一次Blit的Source为ColorBuffer,最后一次Blit的Destination为BuiltinRenderTextureType.CameraTarget,中间可以穿插任何后处理效果。

而且如果发现改了ColorBuffer的分辨率,画面没有正常缩放,需要第二步后处理的CameraEvent改为AfterEverything:

还有就是如果改了TargetBuffer,需要对SceneCamera做特殊处理。

感谢范世青@UWA问答社区提供了回答

A2:下图是这两种方法的实验对比,至于两者区别的根本原因,是其方法内部实现的差异:SetTargetBuffers的实现过程是没有设置渲染目标(也就是屏幕)的RenderTexture的,这也就是为何用该方法时OnRenderImage中的Source是null。

该问答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/61518a318f8c834241be8ac3


Asset

Q:问下在FBX的导入设置里面,weldVertices是需要设置为True还是False?

A:建议设置为True。相同顶点会被合并,可以减少内存和Mesh渲染的压力。

感谢萧小俊@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/6164066a8f8c834241d70ffa

20211018
更多精彩问题等你回答~

  1. Unity增量打包AssetBundle没变化的资源也会被重新打包
  2. 在模型有UV2的情况下开启Generate Lightmap UVs
  3. 如何实现AAB包的增量更新

封面图来源于网络


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)