图1.5 小水果
在Renderer的render函数中打上断点,如图1.6所示。
图1.6 render函数
在Renderer的render函数中打上断点,如图1.6所示。我们查看调用堆栈的上一级,可以看到我们的大导演在每帧的循环中做了这些事情。如图1.7,1.8,1.9所示。首先更新scheduler,而后让当前的场景visit(所有节点draw函数就在这里调用的),最后调用render,推出当前矩阵,交换背缓冲。
图1.7 大导演的drawScene (1)
图1.8 大导演的drawScene (2)
图1.6 大导演的drawScene (3)
而后我们再回到render的函数中,看一下他的visitRenderQueue函数,如图1.7,1.8所示。我们首先看最常用的Quard的渲染。如果当前缓存的Quard顶点数量还没达到VBO_SIZE(10922),就把这些顶点数据拷贝到quard数组中,再用command中保存modelView矩阵对这些顶点进行变换。而对于其他的命令,就是调用他的execute方法。对于自定义的execute,其代码如图1.9
所示,就是调用一下他的绑定函数func,这通常在自定义节点的draw函数中绑定,这也是我绘制3D场景所用的方法。
图1.7 visiteRendereQueue的QUAD_COMMAND
图1.8 visiteRendereQueue的其他命令类型
图1.9 自定义命令的
1.4 AutoBatch原理讲解
而后,我们再看看他的drawBatchQuard是怎么做的。如图1.10,1.11所示,这个函数首先判断是否有顶点,若没有则return掉。而后向显存传入数据,绑定VAO。之后的那一段(图1.11)就包含传说中的的autoBatch,drawCall合并(
)。遍历数组,当当前命令的材质与上一个相同,则batch,否则绘制之
前BUFFER,把这个quard给batch进去。
图1.10 drawBatchedQuads(1)
图1.11 drawBatchedQuads(2)
也就是说,如果我们相邻添加的Sprite的纹理不同,引擎是不会做batch的,正如图1.5所示,虽然我们只用了6张纹理,但drawCall仍然是10001。下面我们来做个试验,来说明这个问题。
首先,把之前的代码修改为如图1.12所示的样子,只让程序绘制一种水果。我们可以看到,引擎经行了Autobatch,绘制所有的水果的drawCall只有1次(另一次是glClear())。
图1.12 代码1
图1.13 autobatch效果
再次修改代码,如图1.14所示,交替添加两种水果的sprite。drawCall又变回10001。再次修改代码,如图1.16所示。
图1.14 代码2
图1.15 autobatch效果2