RenderBufferLoadAction的使用方式

RenderBufferLoadAction的使用方式

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问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5e856425acb49302349a1119


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问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5e844ff9f464f7051353075e


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问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5e7f50c986713137aaa097cf


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问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5e7d578518502d37b0fc2634


Rendering

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

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

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

感谢郑骁@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5e8327036a616e19893abe02

封面图来源:
Unity 3D Scripts:Unity 3D中的一些基本C#脚本。
https://lab.uwa4d.com/lab/5cb4f14872745c25a8aeea09


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

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