1)AssetBundle异步加载被中断的问题
2)LuaDLL.lua_pcall()自身产生开销问题
3)法线在手机渲染时出现的错误问题
4)UNITY_MATRIX_I_V 和Camera.main.worldToCameraMatrix.inverse区别
这是第272篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。
UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)
Resources
Q:在使用异步接口yield return AssetBundle.ASyncLoad的时候,难免会想到:这个异步处理完之前如何Cancel掉这个任务?也就是说一个AssetBundle加载到一半,现在要放弃加载,应该怎么处理?
A1:其实底层调用GetAssetBundleBlocking,会在这个函数内部调用PreloadManager的加载更新逻辑,其实就是把Async操作改成了Sync了,会一直阻塞到AssetBundle加载成功。
但是也有坑,这儿因为执行了PreloadManager.UpdatePreloading,内部还会做GC。遇到过把不应该卸载的资源给卸载了,说是Unused,但是实际正在使用。
感谢黄程@UWA问答社区提供了回答
A2:资源加载管理的第一难题就是异步IO怎么被Cancel掉,或者说从设计上怎么去实现等同的效果。
但是相对于从Flash到Cocos到Unity来说,Unity还是做的很好的。之前的任何引擎要处理好这个问题,非常之困难,需要很多代码的支持,包括多线程更低层次的相关代码。这一块Unity做得非常好,我们不用绞尽脑汁去实现异步IO Cancel的问题,只需要做好上层架构,设计出类似的功能。
Unity的异步加载会返回一个Request对象,该对象有一个Get属性AssetBundle,仔细查看该Get函数API会发现。当调用该属性时,会促使底层异步IO中断(具体怎么实现的,有C++源码的才能知道),并立即同步加载该资源,且回调,回调顺序是和你调用顺序相当的(比如异步加载调用了2次并设置了回调,现在触发中断并立即完成,会优先回调异步设置的回调)。
所以基于这个设计一个好的引用计数器管理资源非常重要。
大部分项目的引用计数器设计都是待资源完成后添加引用计数。这种设计的适用场景非常局限。在大型项目中使用环境非常复杂的资源加载情况下(异步加载中调用同步,异步加载中需要取消,异步加载中取消后立即同步等)会出现非常多的未知问题和开发中的局限性,这种设计只适合微型项目快速开发。
所以一个完备的引用计数设计应该是调用加载方法时,就生成该资源未来被加载完成后的数据壳子,并添加引用计数(因为加载本身其实也是一次引用,包括bundle.AsynLoadAsset,其实任何的异步加载自身都需要添加一次引用,防止上层代码的逻辑,造成引用计数器非法=0触发bundle.unload方法),完成后减少引用计数。那么同步加载时需要查找数据壳子,如果该资源正在异步加载,需要调用其request.assetBundle让其立即中断异步并立即同步完成加载。(否则同步加载时底层会抛出警告。)
基于这个我们可以设计一套非常完备的Cancel系统,上层调用Cancel时,其实就是让其外部引用-1,因为理论上我们能拿到的所有接口无法真正中断一次IO,只有待其加载完成后,发现引用计数等于0时,才会Unload掉资源。
设计思路这里只是抛出一点,具体怎么去实现和设计各抒己见。只是如果一个资源管理器不能适应任何(绝大部分)加载情形,那么这还是一个资源管理器吗?
感谢1 9 7 3-311135@UWA问答社区提供了回答,欢迎大家转至社区交流:
AssetBundle异步加载被中断的问题 -- UWA问答:帮助开发者找到更好的答案
Lua
Q:为什么LuaDLL.lua_pcall()自身会产生这么大的开销?
A1:是不是Lua自身逻辑消耗比较高,这个可以看Lua侧的消耗:《Lua Profiler——快速定位Lua性能问题》。
感谢jjjzzz@UWA问答社区提供了回答
A2:lua_pcall只是通过压栈的方式调用了Lua,具体消耗还得在Lua那边看看,估计是某函数C#和Lua疯狂调用比较厉害。
感谢萧小俊@UWA问答社区提供了回答
A3:用DeepProfile才能知道具体是哪个方法调用高,这里只是C# call到Lua,后面的栈信息已经没有了,不能单纯的说LuaDLL.lua_pcall()开销大。
感谢1 9 7 3-311135@UWA问答社区提供了回答,欢迎大家转至社区交流:
AssetBundle异步加载被中断的问题 -- UWA问答:帮助开发者找到更好的答案
Rendering
Q:法线在手机渲染时出现的错误问题:
用的版本是Unity 2019.4 URP。Editor模式下是正确的,在默认Unity Build的打包正确,将资源打成AssetBundle后渲染出现错误。Shader使用了多种,包括默认的Lit Shader,都会出现该问题。
A:怀疑是渲染管线的Shader问题,变体收集问题,最后一一排除后变成Mesh问题。有好大哥MoMo的奶爸告诉我,Unity部分版本的Optimize Mesh Data选项默认打开,会优化掉部分网格,导致以上的问题。
感谢题主霸气九号@UWA问答社区提供了回答,欢迎大家转至社区交流:
AssetBundle异步加载被中断的问题 -- UWA问答:帮助开发者找到更好的答案
Rendering
Q:URP中Shader的UNITY_MATRIX_I_V 和C#中Camera.main.worldToCameraMatrix.inverse获取到的矩阵并不一样,在Shader中用ViewSpace的坐标乘以UNITY_MATRIX_I_V并不能够得到正确的世界坐标,乘以Camera.main.worldToCameraMatrix.inverse则可以,请问他们二者的区别是什么呢?
A:我这边做的测试并没有发现这两个矩阵有什么不同。
fixed4 frag (v2f i) : SV_Target { fixed4 col = UNITY_MATRIX_I_V[0]; return col; }
在Shader中修改Frag来调用UNITY_MATRIX_I_V:
void Start() { Debug.Log(Camera.main.cameraToWorldMatrix); Debug.Log(m_camera.cameraToWorldMatrix); Debug.Log(Camera.main.worldToCameraMatrix.inverse); }
在C#中打印这个矩阵,从Frame Debugger和控制台输出的结果来看这两个矩阵没有什么不同。
使用URP的Shader Simple Lit,计算逆矩阵之后的结果也是一致的:
感谢宗卉轩@UWA问答社区提供了回答,欢迎大家转至社区交流:
AssetBundle异步加载被中断的问题 -- UWA问答:帮助开发者找到更好的答案
20211025
更多精彩问题等你回答~
封面图来源于网络
今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。
官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)