新绘制系统的特点
- 将逻辑绘制从主循环中分离。每个UI元素的类型更多的是根据它在应用程序中的特征而不是绘制方式的不同划分的,也就是说,多个不同类型的UI元素可能拥有相同绘制方式。
- 采用应用程序级别的视口裁剪。
- 采用自动批绘制技术。
- 更简单地实现绘制的自定义。
绘制系统概览
绘制流程分为三个阶段:
- 通过UI树的遍历生成绘制命令。
- 对绘制命令进行排序。
- 执行绘制命令。
RenderCommand
Cocos2d-x渲染系统管理下的每一次绘制调用都是一个RenderCommand。
- 每个RenderCommand实例中包含一个globalOrder属性,它是用来决定绘制顺序的重要属性。
RenderCommand的另一个重要的属性类型,主要有:
- QUAD_COMMAND
根据1个纹理和4个顶点绘制一幅图片。 - BATCH_COMMAND
用来绘制一个TextureAtlas,如Label、TitleMap。TextureAtlas实际上是Cocos2d-x对绘制来自同一纹理的多个精灵的一个封装。 - GROUP_COMMAND
可以用来包装多个RenderCommand集合,GROUP_COMMAND中的每一个RenderCommand都不会参与全局排序。
- QUAD_COMMAND
QUAD_COMMAND
QuadCommand用于绘制一个或多个矩形区域,每个矩形是一个纹理的一部分,如Sprite、Tiles、ParticleSystemQuad。一个QuadCommand中包含以下4部分内容:
- TextureID:OpenGL ES绘制使用的纹理。
- Shader Program:着色器程序。
- BlendFunc:指定混合模式。
- Quads:需要绘制的1个或多个矩形区域的定义,包括每个点的坐标、颜色和纹理坐标。
Cocos2d-x 3.0提供了一种叫自动批绘制(Automatic Batching)的技术,即对多个相邻的QuadCommand,如果它们使用了相同的纹理、着色器、混合模式及其他一些OpenGL ES的状态设置,则只会调用一次OpenGL ES绘制命令。这使得应用程序可以不依赖诸如手动将Sprite添加到SpriteBatchNode的方式就能实现批绘制,尤其是多个不同类型的UI元素。
GROUP_COMMAND
GoupCommand通常不包含具体的GL绘制命令,它只指向一个新的RenderQueue。
也就是说,默认情况下,所有的RenderCommand都被添加到索引为0的RenderQueu中,我们称其为主绘制栈。如果添加的RenderCommand是GroupCommand类型的话,而且这个GoupCommand会新建一个RenderCommand并且指向它。那么,Render其实持有多个RenderQueue。
RenderQueue
场景中的每个UI元素的各种类型的绘制命令RenderCommand将被发送到一个叫做RenderQueue的绘制命令栈上。
RenderCommand排序
遍历完UI树并添加到绘制栈后,RenderQueue对所有globalOrder为0的RenderCommand都不执行排序,而是以它们被添加到RenderQueue中的顺序为准,只对少数特殊设置了globalOrder属性的Node进行排序。
元素的可见性
自动裁剪
自动裁剪:在遍历UI树时进行位置计算,如果发现其位于屏幕之外,则不会发送绘制命令到Render中,但是,目前它仅在Sprite元素上使用。
即使如此,如果一个应用程序有很大的场景,则不应该完全依赖自动裁剪。因为自动裁剪只是减少了绘制命令调用的次数,而这些元素所使用的纹理仍然占据着内存。所以,对于大场景,还需要注意对纹理内存的管理。对不可见的元素可以手动移出场景并删除其使用的纹理。
visible属性
当一个元素的属性为false的时候,遍历UI树时将被忽略。但是,不会影响事件的分发,对于触摸事件,就会造成一种非预期的结果:一个元素虽然不可见,但是它能够接收触摸事件。因此在触摸事件中应该判断其可见性。
元素什么时候被绘制
对于这种绘制系统的设计,我们不知道其什么时候被返回。
有两种情况处理这种情况:
- 注册一个Schedule。在下一帧被执行时读取绘制结果,并注销该Schedule,因为该Schedule只使用一次。
- 添加一个CustomCommand来提供一个通知,在被Render执行时会调用应用程序指定的一个
func()
方法进行绘制,所以可以将func作为一个绘制时机的回调函数。