问答 RenderBufferLoadAction 的使用方式

侑虎科技 · 2020年05月27日 · 905 次阅读

1)RenderBufferLoadAction 的使用方式
2)关于 Mipmaps 与 Quality 使用的疑问
3)关于 Unity early-z 的一个疑问
4)Sprite 在 Resources 目录下的处理问题
5)锚点改变导致 Draw Call 倍增的问题


Script

Q:请问谁能比较系统地讲解下 RenderBufferLoadAction 和 RenderBufferStoreAction 的几种属性及使用方式吗?我看了下官方文档的解释仍然不是完全明白,也不太清楚在什么情况下使用。

A: 举一些例子来说明。

例子 1:比如,你先在 RenderTexture A 绘制了一个三角形,然后在 RenderTexture B 绘制任意一个东西,再然后想继续往 RenderTexture A 绘制东西,但是要求是 A 上的那个三角形还要在,那么就需要 RenderBufferLoadAction.Load。这个操作会导致 RenderTexture A 需要从 local memory 复制到 tile memory,这样就多了一倍的带宽。带宽是移动游戏发热的根本原因。

例子 2:比如,你在一个刚申请出来的 RenderTexture A 绘制一个三角形,那么就需要 RenderBufferLoadAction.Clear。否则,谁都不知道刚申请出来的这个 RenderTexture 是什么样子,所以需要 Clear 一下。Clear 操作只是给这个 RenderTexture 打个标记,虽然有代价,但是比较小。

例子 3:比如,在一个刚申请出来的 RenderTexture A 绘制一个三角形,但是你自己知道,你绘制的这个三角形是全屏的,会覆盖满整个屏幕,这个时候就不需要 Clear 了,直接 RenderBufferLoadAction.DontCare。这样毫无代价,效果也完全没问题。

例子 4:比如,你将 RenderTexture A 作为 Color RenderTexture,RenderTexture D 作为 Depth RenderTexture,绘制两个有前后顺序的三角形。然后,你将 RenderTexture A blit 到 RenderTexture B 上,这个时候,要对 RenderTexture A 设置为 RenderBufferStoreAction.Store,对 RenderTexture D 设置为 RenderBufferStoreAction.DontCare。这个操作,RenderTexture A 会从 tile memory 复制到 local memory,而 RenderTexture D 则会直接被抛弃,不会产生额外的带宽。

当然这个操作还有个前提,RenderTexture D 被通过的 RenderTextureMemoryless.Depth 设置为 memoryless。

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


Texture

Q:请教一下大家,之前我们的游戏在 1GB 内存的 iPhone 上有很严重的闪退问题,就将一些纹理设置成了 Mipmaps,然后在 Quality 中将低版本的 iOS 设置成 low,TextureQuality 改为了 HalfRes,的确是缓解了一点闪退问题。

但是在了解 Mipmap 的过程中发现,如果没有在 Quality 中开 Texture Streaming,实际上会加载所有的 Mipmaps 图而增加内存,用内存换取 GPU 带宽,这一步并不会优化内存。

以下有几个问题:
1.更改 Quality 的 level 是否与 Mipmaps 有关?我们之前的优化效果是单纯由于改为 HalfRes 带来的还是 Mipmaps 带来的?还是两者结合生效呢?
2.在开启 Texture Streaming 后勾选 Mipmaps 资源是否可以通过只加载选定压缩等级而降低内存占用?

A:回答如下:

1.结合生效。开启 Mipmap 后,TextureQuality 设置为 HalfRes,则最高画质为 HalfRes,随着摄像机远近的变化 Mipmap 生效回切到更低的画质。

2.可以,但不完全。勾选 Texture Streaming 后,可以通过设置 Memory Budget 来限制载入的最大内存。设置 Max Level Reduction 来限制显示的最高画质,两者结合可以达到您的需求。具体细节可以看张鑫在 UWA DAY 上的一门课程《Unity 引擎加载模块和内存管理的量化分析及优化方法》,在第五小节中有详细解释。

简单来讲是:如果 Memory Budget 足够大到可以加载全分辨率级别的纹理,则加载全分辨率级别纹理;如果不能,则只加载 Max Level Reduction 级别及更低级别的纹理。所以只设置 Max Level Reduction 是不够的,要相应调低 Memory Budget。

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


Rendering

Q:以下是关于 Unity 中 early-z 的一些说明:


我们在本地做了测试:

图中有一个球形和 Cube,球形在 Cube 之前,都是不透明物体。在球形的 Shader 中,去获取深度图中的深度值,并以颜色值显示,代码如下:

按照文章中所说,不透明物体从前往后渲染,也就是说应该先渲染球形然后是 Cube,可是为什么在球形的 Shader 中却能正确得到 Cube 所写入的深度信息,是我哪里理解有误还是测试案例不正确?

A:在绘制球之前,_CameraDepthTexture 已经确定了,题主写的 Shader 里面没有 ShadowCaster 这个 Pass,所以在绘制深度的时候球的深度没有计算在内,就只有 Cube 的深度值了。在给球的 Shader 里面加上 Fallback “Legacy Shaders/VertexLit”,就可以看到球的深度也被写入到_CameraDepthTexture 里面了。

从 FrameDebugger 里面可以看到:


球的 Shader 有 Fallback 的时候


球的 Shader 没有 Fallback 的时候

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


Texture

Q:本来是把 Sprite 放在 Resources 目录下的,打了图集后是要把整体放在 Resources 下吗?如果必须放,有什么好的方法吗?(目前没有使用 AssetBundle)

A1:把你想要通过 Resources 加载的资源放在 Resources 目录下即可,其它被引用的资源无论是在打包还是加载时都是不会丢失的。
该回答由 UWA 提供

A2:如果是 Resources 加载图集,就不需要原图在 Resources 下,不过原来直接引用原图的地方要替换 GUID 引用(可以做个脚本,以文本打开全部.mat 和.prefab,替换原图 GUID 到图集中 Sprite 的 GUID 和 FileID)。

此外 Sprite 源文件尽量不要放在 Resources 下,否则原图在打 AssetBundle 时会复制一份单图在 Bundle 里面,Unity 认为原图可能以 Texture2D 形式被单独加载。

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


Rendering

Q:游戏运行中,从对象池里拿 item 的时候动态设置物体锚点,为什么会导致 Draw Call 成倍增加?

A1:可以通过 Frame Debugger 来进行查看,看看都多了哪些 Draw Call。
该回答由 UWA 提供

A2:目测楼主打乱了 UGUI 的合批规则,导致 Draw Call 成倍增加,用 A1 回答的方法定位一下,遵循 UGUI 的合批规则改变一下 GameObject 的 Tree。

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


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

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册