今天主要学习一下Cocos2d-x 3.x里边有关自动材质合并的应用问题,对这方面没搞清楚的童鞋可以关注一下。

1.opengl的渲染

       要想了解自动材质合并,那么就必须清楚它是怎么实现的。opengl的管线渲染度娘一抓一大把我就不详细的说了。主要提与自动材质合并概念有联系的俩个关键点,顶点着色器与片段着色器。他们是干啥的我真不想说,因为度娘也会告诉你。但是我想告诉你的是实际上自动材质合并就是省略上传材质步骤,而只上传顶点坐标,通过这样减少大量材质上传寄存器的IO消耗来达到渲染优化。

2.Cocos2d-x的自动材质合并实现方式

       大体实现的理论是通过相关材质合并(也就是我们通常用texturepacker进行的图片合并操作)以及显示对象的图层管理来实现的。

CCRenderer文件中Renderer::drawBatchedTriangles()方法有如下代码:

for(const auto& cmd : _batchedCommands)

{

auto newMaterialID = cmd->getMaterialID();

if(_lastMaterialID != newMaterialID || newMaterialID == MATERIAL_ID_DO_NOT_BATCH)

{

//Draw quads

if(indexToDraw > 0)

{

glDrawElements(GL_TRIANGLES, (GLsizei) indexToDraw, GL_UNSIGNED_SHORT, (GLvoid*) (startIndex*sizeof(_indices[0])) );

_drawnBatches++;

_drawnVertices += indexToDraw;

startIndex += indexToDraw;

indexToDraw = 0;

}

//Use new material

cmd->useMaterial();

_lastMaterialID = newMaterialID;

}

indexToDraw += cmd->getIndexCount();

}

这段代码意思很简单,是否与上一次提交的材质ID相同,如果相同那么不去重复进行材质提交,如果不同那么提交新的材质ID的材质到GPU的材质寄存器以用于渲染操作。

       这里我们可以明白一个道理,它的优化方法很单纯,也就是说临近的俩个渲染对象如果他们所使用的材质相同,那么他们在渲染的时候只有第一个使用到该材质的对象会向GPU提交材质到寄存器,之后临近的所有使用到该材质的对象将不再进行材质提交过程。

这优化就是如此简单。

3.例子

如下图,我们对一个角色对象进行优化设计


1.jpg

       因为在程序中每一个角色对象所用到的动画材质可能不同,所以我们把它单独放入到一个显示容器中,这个容器只会存在角色对象。

        我们把角色名字统一放入到另一个角色名字的容器中这样所有的名字就成为一个材质批次关系

       角色脚下的阴影我们可以放入到第三个容器中,这样所有角色的脚下阴影就可以合并成一个批次进行处理。

       这样的层级设计我们假设有10个不同形象的角色,我们以原始方式每个角色所有元素放入到一个容器中,这样每个角色有3个批次,10个角色存在30个批次。

       而按照优化过的层级去进行填充,每个角色的独特角色动画有10个批次,角色名称1个批次,角色阴影1个批次,总计拥有12个批次。

这就是优化,如此简单,只需要简单的调整下容器关系。

4.更复杂的优化

       实际上我们还可以实现更加个性化的优化,这要涉及到我们自行去编写一个新的shader。

       比如一个角色对象,我们赋予它一个角色对象的shader,而我们的容器中只存在这种新型shader的角色对象。

       这个shader我们一次不再使用一个材质寄存器,而是使用最小的提供的8个材质寄存器,而每次只需要更新必须更新的材质寄存器,就可以实现一个更加复杂与适合我们需求的优化方案了。