UGUI合批规则概述
- 遍历所有UI元素
- 根据深度Depth(优先级最高,-1表示不消渲染)、材质ID、图片ID、渲染顺序对所有UI进行排序
- 进行合批处理,比如UI1和UI2(两者必须是紧挨着的)是相同材质、相同图片就可以进行合批,如果UI1和UI2之间有一个中间层UI3(根UI1和UI2材质不同),就会打断合批
- Text必须文字的网格覆盖到image上面才算相交,Rect Transform框框相交不算
- 白色image的深度为0,最先渲染,然后判断Text是否相交,再判断材质ID和图片ID是否相同,如果相同则可以合批,由于不相同,以是Text深度为白色image+1为1(如果Text底下有许多image,则取最大的深度+1)
- 红色image由于底下有Text和白色image,以是计算出两个深度值分别1和0,取最大值加1,就是2
- 黄色和蓝色image会进行合批测试操作,深度值都是2(这里只是测试是否能合批,并还没有真正合批)
- 最后会得到一个排序数组list并把所有深度为-1的值剔除掉,0、1、2、2、2,传给合批部分的程序进行合批操作,判断相邻的元素是否能进行合批,通过判断数组的值是否相称
UGUI性能检察工具
合批部分的特殊例子
一个白色image、蓝色image覆盖了Text,白色image和Text哪个先渲染
- 根据分析工具可以看到白色image先渲染,文本后渲染(白色图片ID小一点)
- 如许得到的数组list,会先是白色image、Text、蓝色image,导致白色和蓝色无法合批
- 解决办法是把白色image和蓝色image赋值同一个texture
- 只要是满足合批条件,合批数组紧挨着,固然没有覆盖,也可以合批
- 能不能合批,在最后合批数组上才气决定
Mask合批
- mask无法跟mask外的物体进行合批,但是mask之间可以合批
- mask自己会产生两个drawcall,性能损耗
Mask为什么会产生两个drawcall
- 第一个drawcall是mask在设置模板缓存产生的
- 第二个drawcall是mask在还原模板产生的
- mask之间可以进行合批,设置模板缓存和还原模板时间,由于图片ID和材质是一样的,以是可以合批
- 设置模板缓存时间,会把必要显示部分的缓存值设置为1,遮罩的部分设置为0,在渲染的时间会取出我存在当前像素当中的一个模板缓存值,然后判断它呢是否为一。如果为一的话,才进行渲染,如果不为一,就不不渲染了
- 每一个像素点上,创建了一个如许类似于一个数据缓存,通过它的模板缓存值来判断是否显示,都是像素级别的单位
- 模板还原也要产生一次drawcall,把每个像素点的模板缓存扫除
Mask为什么不能合批
由于Mask会产生一个特殊的材质,材质不同就不能合批

- public virtual Material GetModifiedMaterial(Material baseMaterial)
- {
- if (!MaskEnabled())
- return baseMaterial;
- var rootSortCanvas = MaskUtilities.FindRootSortOverrideCanvas(transform);
- var stencilDepth = MaskUtilities.GetStencilDepth(transform, rootSortCanvas);
- if (stencilDepth >= 8)
- {
- Debug.LogWarning("Attempting to use a stencil mask with depth > 8", gameObject);
- return baseMaterial;
- }
- int desiredStencilBit = 1 << stencilDepth;
- // if we are at the first level...
- // we want to destroy what is there
- if (desiredStencilBit == 1)
- {
- // StencilMaterial.Add是最主要的方法,这里添加了特殊的材质,因为材质不同,所以不能和mask外的物体合批
- var maskMaterial = StencilMaterial.Add(baseMaterial, 1, StencilOp.Replace, CompareFunction.Always, m_ShowMaskGraphic ? ColorWriteMask.All : 0);
- StencilMaterial.Remove(m_MaskMaterial);
- m_MaskMaterial = maskMaterial;
- var unmaskMaterial = StencilMaterial.Add(baseMaterial, 1, StencilOp.Zero, CompareFunction.Always, 0);
- StencilMaterial.Remove(m_UnmaskMaterial);
- m_UnmaskMaterial = unmaskMaterial;
- graphic.canvasRenderer.popMaterialCount = 1;
- graphic.canvasRenderer.SetPopMaterial(m_UnmaskMaterial, 0);
- return m_MaskMaterial;
- }
- //otherwise we need to be a bit smarter and set some read / write masks
- var maskMaterial2 = StencilMaterial.Add(baseMaterial, desiredStencilBit | (desiredStencilBit - 1), StencilOp.Replace, CompareFunction.Equal, m_ShowMaskGraphic ? ColorWriteMask.All : 0, desiredStencilBit - 1, desiredStencilBit | (desiredStencilBit - 1));
- StencilMaterial.Remove(m_MaskMaterial);
- m_MaskMaterial = maskMaterial2;
- graphic.canvasRenderer.hasPopInstruction = true;
- var unmaskMaterial2 = StencilMaterial.Add(baseMaterial, desiredStencilBit - 1, StencilOp.Replace, CompareFunction.Equal, 0, desiredStencilBit - 1, desiredStencilBit | (desiredStencilBit - 1));
- StencilMaterial.Remove(m_UnmaskMaterial);
- m_UnmaskMaterial = unmaskMaterial2;
- graphic.canvasRenderer.popMaterialCount = 1;
- graphic.canvasRenderer.SetPopMaterial(m_UnmaskMaterial, 0);
- return m_MaskMaterial;
- }
复制代码 Mask留意要点
- Mask剔除的部分还是会影响深度计算的,从而影响合批,增长drawcall次数
- Mask剔除的部分还是会drawcall,只不外mask把绘制的像素剔除了
- Mask下的子物体可以正常进行合批
- mask之间只要满足合批条件,那么他们之间的元素也是可以或许进行合批的
RectMask2D
- RectMask2D自己不占用drawcall
- 由于现实的详细逻辑是在canvas render里进行的,涉及到渲染详细的操作都是内部用c++类做的,性能更好,这里通过性能分析渲染的面和点判断遮盖的部分是否被渲染出来
为什么RecMask2D比Mask性能更好
- RectMask2D自己不占用drawcall,Mask自己有两次drawcall
- RectMask2D对于被遮罩的部分并不会绘制,Mask是把遮罩的部分剔除了
重要代码
- public virtual void PerformClipping()
- {
- if (ReferenceEquals(Canvas, null))
- {
- return;
- }
- //TODO See if an IsActive() test would work well here or whether it might cause unexpected side effects (re case 776771)
- // if the parents are changed
- // or something similar we
- // do a recalculate here
- if (m_ShouldRecalculateClipRects)
- {
- MaskUtilities.GetRectMasksForClip(this, m_Clippers);
- m_ShouldRecalculateClipRects = false;
- }
- // get the compound rects from
- // the clippers that are valid
- bool validRect = true;
- // 获取需要剪切的区域
- Rect clipRect = Clipping.FindCullAndClipWorldRect(m_Clippers, out validRect);
- // If the mask is in ScreenSpaceOverlay/Camera render mode, its content is only rendered when its rect
- // overlaps that of the root canvas.
- RenderMode renderMode = Canvas.rootCanvas.renderMode;
- bool maskIsCulled =
- (renderMode == RenderMode.ScreenSpaceCamera || renderMode == RenderMode.ScreenSpaceOverlay) &&
- !clipRect.Overlaps(rootCanvasRect, true);
- if (maskIsCulled)
- {
- // Children are only displayed when inside the mask. If the mask is culled, then the children
- // inside the mask are also culled. In that situation, we pass an invalid rect to allow callees
- // to avoid some processing.
- clipRect = Rect.zero;
- validRect = false;
- }
- if (clipRect != m_LastClipRectCanvasSpace)
- {
- foreach (IClippable clipTarget in m_ClipTargets)
- {
- //设置剪切效果
- clipTarget.SetClipRect(clipRect, validRect);
- }
- foreach (MaskableGraphic maskableTarget in m_MaskableTargets)
- {
- maskableTarget.SetClipRect(clipRect, validRect);
- maskableTarget.Cull(clipRect, validRect);
- }
- }
- else if (m_ForceClip)
- {
- foreach (IClippable clipTarget in m_ClipTargets)
- {
- clipTarget.SetClipRect(clipRect, validRect);
- }
- foreach (MaskableGraphic maskableTarget in m_MaskableTargets)
- {
- maskableTarget.SetClipRect(clipRect, validRect);
- if (maskableTarget.canvasRenderer.hasMoved)
- maskableTarget.Cull(clipRect, validRect);
- }
- }
- else
- {
- foreach (MaskableGraphic maskableTarget in m_MaskableTargets)
- {
- //Case 1170399 - hasMoved is not a valid check when animating on pivot of the object
- maskableTarget.Cull(clipRect, validRect);
- }
- }
- m_LastClipRectCanvasSpace = clipRect;
- m_ForceClip = false;
- UpdateClipSoftness();
- }
复制代码 RectMask2D留意要点
- 遮罩的部分由于没有绘制,以是不影响深度计算,不影响合批
- 会打断合批,一个RectMask2D下的子物体不可以跟另一个RectMask2D下的子物体进行合批,但RectMask2D下的子物体可以进行合批
- RectMask2D组件的Image之间可以进行合批
根据应用场景选择使用哪个(Mask、RectMask2D)
只必要一个遮罩
选择用RectMask2D性能更好
必要多个遮罩,遮罩下有多个子物体
选择用Mask可以对不同Mask之间的子物体进行合批,这种情况就会比RectMask2D性能更好
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! 更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |