易游网-易游模拟器

 找回密码
 立即注册
查看: 4271|回复: 1

[游戏开发] cocos2dx渲染批次优化理解

[复制链接]

3382

主题

3401

帖子

38

积分

超级版主

Rank: 8Rank: 8

积分
38

技术达人

发表于 2021-1-11 15:24:58 | 显示全部楼层 |阅读模式
渲染队列
可以理解为游戏的一个渲染集合,按不同层级,从后(背景)往前(前景),半透明要在不透明前面。
每一个渲染对应1个或多个command,这些Command根据globalZOrder被放到不同的队列里。队列在渲染过程中按固定顺序进行绘制.
globalZOrder 和 localZOrder的区别在于GlobalOrder决定的是在哪个渲染队列,localZOrder决定的是子控件的层级.界面渲染时按照从父节点开始,深度遍历子节点依次把Command放到队列里,所以localZOrder影响的是放到队列里的先后顺序.
当globalZOrder < 0时,对象被放置在背景层;>0 时被放置在前景层。
当=0时(默认值)根据是否是3D对象来分别放到UI层还是3D渲染层.一般默认UI是盖在3D上面的。
[队列层级]
1、背景
2、3D不透明对象
3、3D半透明对象
4、2D界面对象
5、前景
前面的序号表示了渲染的优先级,eg 1是最先被渲染的.现在一般3D对象使用的不多,基本都是队列4比较多。

Command
粗略来说分为2大类,一类是表示渲染操作,另外1类是逻辑,主要是设置或恢复状态等用。
图片或UI在渲染的时候会转化为1个或多个Command(看具体的控件类型)提交到队列里面。下面是常见Command的类型
1、BatchCommand
2、MeshCommand
3、TrianglesCommand
4、CustomCommand
5、QuadCommand(在后续版本中去除和TrianglesCommand融合)

BatchCommand
独立渲染层完成了batch操作,主要是针对明显可以混合的类型,比如粒子和SpriteBatchNode,后者通过TextureAtlas去绘制。一般网上说的优化走SpriteBatchNode,就是走的这个Command

MeshCommand
3D中使用,比如1个3D模型的渲染,走的这个

TrianglesCommand
用的极少,SpritePolygon这种自定义面片使用,请无视

CustomCommand
当标准渲染管道不满足需求(比如设置特殊渲染状态)或一些优化考虑时会使用这个Command来自定义渲染。这个使用也比较多
        LayerColor
          优化考虑(不需要设置纹理)
        DrawNode
          自定义各种曲线啥的
        Label
          字体也是生成文字到1张纹理上面,然后通过TextureAtlas去绘制,但字体有样式定制,被独立出来了,类似SpriteBatchNode
        ProgressTimer
          需要绘制各种形状,比如Fan替代Triangle图元
        模版缓存渲染
          ClippingNode或Layout(开启模版测试)或ScrollView(开启内容裁剪)
        效果
          天空,地表,动态模糊,渲染到纹理,
QuadCommand
  能用4边形表示的。比如常见的Sprite,Spine Skin这些。

批次合并
批次的概念是一次OpenGL的绘制操作,比如glDrawElements。一般1个渲染command对应1次draw操作,如果多个command可以合并成1个command做1次绘制,就是批次合并概念。

合并的要求
代码允许合并(用户设置)
材质一样
同一渲染队列(cocos后续版本继续减少了一些渲染队列来增加合并可能)
同一Command类型
材质不能有自定义参数,不同的位置旋转缩放不影响合并,顶点在CPU中已算好,颜色存储在顶点中,shader中只要使用vp变换就好
批缓冲区大小(65536 / 4 = 16384)差不多1次最多渲染16384个方面,超过进入下1批次。
Command对合批的支持
BatchCommand ×
MeshCommand √
TrianglesCommand √
CustomCommand ×
QuadCommand √
什么是材质一样
材质一样是指ID一样,ID是根据纹理,shader,混合类型来生成。所以当3个都一样时,并且shader不带自定义参数时,ID是一样的,也就是材质一样的。

3D模型需特殊处理,增加了顶点和索引缓冲区的处理。也就是要判断5个都相同
一般不在同一个Command对应的Shader基本不一样了,混合类型一般也是自动设置,其中图片带Alpha和不带的混合类型是不一样的。

cocos2dx以GL Call数目来作为批次的判断
举例:
node1
->node1_2
->sprite1
node2
->sprite2
上面这种sprite1和sprite2是可以合并,gl call = 1,注意空节点不打断合并

由于深度遍历渲染
node1
->image_1
->->image_1_0
->BitmapFontLabel_2
gl call = 2

改变GlobalOrder,也会导致gl call 增加
改变混合方式,也会导致gl call增加
插入文本位置不同,会导致call变大
比如 label->sprite1->sprite2 和 sprite1->label->sprite2 前者drawcall为2 后者为3
文本无法合批(普通label和bmfontlabel都无法合并,文本是在CustomCommand)

带来一个问题,那文本如何合批?
首先TTF字体就不用考虑。
文本合批可以用LabelAtlas类,把文本渲染从CustomCommand转为QuadCommand

总结
合批的要求和原理都比较简单,能比较清晰的知道元素是怎么渲染的,合理的安排层级,把相同材质的元素按顺序放置到队列里面就可以了。
对于游戏中常用的文本,可以做抽取出来做成altas的方式来加速渲染,其他精灵可以通过合集或batchNode的方式来合批。

# 合批切换的消耗
批次切换是不可避免的,那怎么理解批次切换的消耗呢?
OpenGL的渲染类似CS的结构,像纹理,顶点这些属于服务器对象。一般顶点又多是动态形式存在的,就是由内存更新到显存。理论上切换的时候按最小代价的切换,比如先切换shader参数,再考虑切换shader->再到切换顶点或纹理这样逐级考虑。


0

主题

6

帖子

0

积分

普通会员LV2

Rank: 1

积分
0
发表于 2021-4-10 15:18:04 | 显示全部楼层
文本打断纹理合批怎么破,比如物品格子
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|易游网-易游模拟器 Copyright @2015-2021 ( 浙ICP备15028007号-1 )

GMT+8, 2024-11-27 09:37 , Processed in 0.017956 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表