本地资源检测,特效检测中Overdraw相关问题

1)本地资源检测,特效检测中Overdraw相关问题
​2)Android上如何加速判定Bundle文件是否存在
3)xLua pcall异常捕获
4)Mipmap和带宽
5)Timeline卡顿严重时,Clip被完全跳过没有执行


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

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

Rendering

Q:咱们这个特效资源检测Overdraw和实际检测差距有点大。是不是统计峰值比较好一些?有可能一个特效播放时间特别长,但是峰值就很短的时间,这样一平均Overdraw就很低了。

A:首先要谈谈Overdraw的定义问题:

  1. Overdraw是一个描述像素重复绘制次数的概念。单个像素的重复绘制次数很容易理解,但是对于一个特效的Overdraw,笔者还没有找到什么公认的“标准”的计算公式,也不存在什么“官方”的定义。

对于一帧来说,Overdraw值可以定义为该帧总体绘制像素的次数 / 屏幕上实际绘制的像素数。而这个值也不能简单理解为“绘制的层数”。(试想如果总共在屏幕上绘制了1000个像素,其中只有一个像素绘制了10层,那这个重复绘制的像素对Overdraw值得贡献也是可以忽略的,计算结果为:1009/1000=1.009)。而对于整个特效播放过程中的Overdraw,具体公式如何定义,又是一个问题。

  1. sunbrando的开源库的计算方法:整个播放过程中,

分子是对每一帧绘制像素的次数求和,分母是对每一帧屏幕上实际显示的像素数求和。

这个公式确实可以从整体上衡量一个特效播放过程中的Overdraw。但是这种计算存在这样一个问题:有些帧特效占屏幕的比例很大,有些帧特效占屏幕的比例很小,而运算结果受屏幕占比大的帧影响比较大。比如第一帧绘制了1000个像素,只绘制了1层,而第二帧绘制了2个像素,绘制了10层,那么计算出的值为:(1000x1 + 2x10) / (1000 + 2) = 1.018 。

UWA本地资源检测对特效Overdraw的计算与上述开源库计算公式是相同的,不同的是特效播放的逻辑与相机对准的方式。

影响两个工具计算结果不同的因素有:

  1. 相机的对准方式不同。UWA的工具有一套相机自动对准的逻辑,相机的摆放不同,会造成Overdraw不同。
  2. 播放的时机不同。UWA的工具会创建好场景后,自动加载并实例化特效,进行播放。而开源库ParticleEffectProfiler的方案是先把特效放到场景中,启动场景后再执行相关的逻辑,进行检测。

楼主的案例中,除了相机对准方式不同导致两个工具计算结果不同之外,很大程度上受到了获取的特效播放时机的影响。

使用开源库工具进行检测,发现抓取相机的Overdraw数据前,已经进行了三次Update,如下图所示。也就是说,特效的Overdraw是从第4帧开始统计的。这与该工具的代码逻辑有关,就不对原因进行分析了。

而前三帧恰恰又是在数值上贡献最大的帧,如下图所示,前三帧特效中有一个面片占了很大的屏幕空间。

而第四帧开始,特效的像素占比就小了很多。

这是两个工具即使使用相同的对准方式,Overdraw计算结果也不相同的原因。

另外,UWA的特效检测还存在一个问题:相机视锥体的Size是不断调整的,那么不同的帧特效的屏幕占比会因此而改变,像素的绘制量也不同,对上述Overdraw值计算公式的贡献也就不一样。也就是说,相机的Size越小的帧,特效屏幕占比越大,对结果的影响越大。

这里有两套解决方案:

  1. 换公式,每帧都计算出OverdrawRate,再求平均。
  2. 用户自定义相机,相机的视锥体保持固定,这样就是放弃自动对准,使相机的设置更接近用户的实际使用环境。

UWA的工具会不断迭代,根据需求尽可能找到一套最佳策略来帮助开发者对项目进行规范。

如果在优化中要使用工具进行检测,并衡量优化的结果,建议使用一套工具即可。使用同一套标准至少可以对资源的性能进行一个排名,据此来选择优化的优先级,并使用同一套标准评估优化结果。

感谢Prin@UWA问答社区提供了回答

AssetBundle

Q:我们在Android平台上打包时,把Bundle放到Streaming Assets中,Patch文件放到持久化目录中。在启动时判断:Patch目录有Bundle就用Patch目录的,没有就看Streaming Assets目录有没有。

问题是:Android判断Streaming Assets下是否有文件,要用www或UnityWebRequest。这两种都是异步读文件,等待异步操作结束需要几毫秒以上,导致判断逻辑耗时很长(Bundle 较多)。

想请教下大家是怎么处理 Android上的文件判定问题呢?

A1:Streaming里放个资源字典文件,用这个判断。

感谢lanyt@UWA问答社区提供了回答

A2:可以这样来处理:
有一个全局的Bundle资源的配置文件,里面记录了所有Bundle的信息,这里面会包含其相对路径。只有从包里面读这个文件是需要异步的,如果从Patch目录读这个文件也是同步的(例如使用FileStream)。
得到了所有Bundle的相对路径后,在实际需要加载某Bundle时,先使用File.Exist或者直接判断AssetBundle.LoadFromFile的返回值是否为null来判断Patch目录是否有该Bundle,如果没有的话再使用包内路径重新调用AssetBundle.LoadFromFile即可。
经测有效,把文件判断分散开,Patch目录可以直接用File,不存在就认为是在Streaming Assets目录,最后利用Load的结果来更新,看是否存在的记录。

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

A3:有一个不错的开源库,能够同步读取StreamingAssets下的文件:
《BetterStreamingAssets》

感谢张迪@UWA问答社区提供了回答

LUA

Q:想请问下在xLua中使用pcall/xpcall实现C#中的Try Catch功能的时候,在iOS/Android/模拟器等平台上,有什么需要注意的地方。

由于对Lua底层不是很了解,想确认下,线上项目使用是否可行。还有这个的性能消耗有多少,Update里可以用吗?

项目使用的是xLua,版本是2.1.14,Unity版本是2019.4。

A:大范围的使用中,pcall和xpcall本身肯定有一定的性能影响,不过我们倒是没有做过很完备的性能测试对比。印象中之前做过一些检索,没有找到特别明确的答案。
Lua中源码的实现对比可以参考这里:
https://stackoverflow.com/questions/16642073/whats-the-difference-behind-normal-function-call-and-pcall/16642612
可以看到pcall的确比常规的call多做了一些事情,只是这是Lua做异常捕获的唯一方式,当你不想游戏逻辑被错误信息打断的时候,只能使用它。
pcall/xpcall在各种平台和模拟器上除了略微的性能影响之外没有任何问题,因为它是Lua原生的方式,如果使用LuaJIT,注意一下Lua和LuaJIT下的区别封装即可。

感谢贾伟昊@UWA问答社区提供了回答

Rendering

Q1:请问,Mipmap究竟能不能降低带宽,如果不能降低,能否详细告诉一下原因,谢谢。

A1:可以降低!
Mipmap是为了解决Texel和Pixel没有1:1对应的一种处理方式。一般来说如果处理远处物体的渲染,依然使用正常的纹理采样,那么其实1个Pixel就一般需要采样到多个不相邻的Texel[1:n的关系],那么不相邻这就可能涉及到一个Cache Miss的问题。而Cache Miss必然需要从显存中重新采样纹理数据,这自然就会消耗带宽。

感谢会丢锅的Coder@UWA问答社区提供了回答

A2:是可以降低带宽开销的。
主要是由于在渲染相邻Pixel的时候,采样的Texel可能是在内存中不连续的,而GPU的Texture Cache是很小的。
如果没有Mipmap,在渲染远处物体时,GPU可能需要不停的在储存Texture的各段Memory不停的访问,Cache Miss很严重。而使用了Mipmap后,相当于离线将每个Texel覆盖的Texture的面积变大,这样可以提升Texture Cache的命中率,从而减少直接从内存读取数据的次数,从而节省了带宽的开销。

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

Q2:请问上文中:
1. “而使用了Mipmap后,相当于离线将每个Texel覆盖的Texture的面积变大”,这里是Pixel还是Texel?
2. 还有就是Memeory是指内存是吧?不是已经把一张图提交给了GPU显存了吗?

A:可以看下我知乎的这个回答,解决你对Pixel和Texel的疑惑:
《shader 中,fwidth 或者说 ddx/ddy 到底是什么意思?》

感谢止戈@UWA问答社区提供了回答

Timeline

Q:Timeline,如果在播放时卡顿严重,会出现前面位置的Clip被完全跳过没有执行,有没有人碰到过类似的问题?

Timeline 信号的这个描述,是不是即使信号跳过了,依旧会执行?
The Retroactive property, when enabled, will trigger the signal if the timeline begins playing after the signal’s time.
The Emit Once property, when enabled, will trigger the signal only once when the timeline loops.

A:勾上之后是会执行,具体逻辑可参考TimeNotificationBehaviour脚本(Timeline中Signal Track的mixer逻辑脚本),如下做了简单注释:

如果需要倒放也会Trigger,也可以参考这个扩展自己的Timeline。

感谢羽飞@UWA问答社区提供了回答

封面图来源:Barracuda Style Transfer code sample


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

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

    作者:侑虎科技原文地址:https://segmentfault.com/a/1190000038709545

    %s 个评论

    要回复文章请先登录注册