Cocos2d-x性能分析之GL calls

GL calls

GL calls指的是OpenGL ES渲染一个场景时每一帧所执行的绘制次数。在开发过程中,我们当然希望这个值是越小越好,绘制次数减少,游戏的性能也会有所提升。

如何减少绘制次数

Cocos2d-x引擎通过视口剪裁和批绘制的方式来减少绘制次数。同时UI元素的可见性也会决定系统是否对该元素进行绘制。

视口剪裁

如果一个UI元素位于视窗之外,那么OpenGL ES将不会去绘制该元素,从而除去了不必要的一些绘制,减少了绘制次数。

可见性

被设置为不可见的UI元素也不会被绘制,但如果只是将元素透明度设为0,则该元素还是会被绘制进当前场景。所以当我们不想显示某个元素时,最好是使用setvisible将其设为不可见,而不是设置其透明度。

批绘制

在Cocos2d-x 3.0版本之前,通常使用CCSpriteBatchNode对精灵进行批处理绘制,从而减少绘制次数。
从Cocos2d-x 3.0版本开始,引擎实现了自动批绘制技术,系统会自动帮我们实现批绘制,而不需要像之前一样将元素添加到CCSpriteBatchNode中。

自动批绘制技术主要会受以下几个因素影响:
纹理;
层级;
顺序;

纹理

首先是纹理的影响,先来进行一个试验。

准备两张图片资源,test1.png和test2.png,同时使用TexturePacker生成一份它们的合图资源test.plist和test.png.

通过不同纹理创建两个精灵

auto sprite1 = Sprite::create("res/test1.png");
if (sprite1 != nullptr)
{
    sprite1->setPosition(Vec2(200, 100));
    this->addChild(sprite1, 0);
}
    
auto sprite2 = Sprite::create("res/test2.png");
if (sprite2 != nullptr)
{
    sprite2->setPosition(Vec2(200, 140));
    this->addChild(sprite2, 0);
}

在这里插入图片描述
此时的GL calls显示为2。

通过同一纹理创建两个精灵

使用合图资源创建两个精灵

SpriteFrameCache::getInstance()->addSpriteFramesWithFile("res/test.plist");
    
auto sprite1 = Sprite::createWithSpriteFrameName("test1.png");
if (sprite1 != nullptr)
{
    sprite1->setPosition(Vec2(200, 100));
    this->addChild(sprite1, 0);
}
    
auto sprite2 = Sprite::createWithSpriteFrameName("test2.png");
if (sprite2 != nullptr)
{
    sprite2->setPosition(Vec2(200, 140));
    this->addChild(sprite2, 0);
}

在这里插入图片描述
此时的GL calls显示为1。

我们可以发现,使用同一纹理之后,两个UI元素的绘制次数从原来的2次变为1次。这是因为批绘制技术将使用相同纹理的UI元素合并成一次绘制。但是这种合并也是有前提条件的,这个前提条件就是这些UI元素必须在UI树种是相邻的。那么在开发过程中,哪些因素会影响UI元素在UI树中的位置呢?主要是层级UI元素添加的顺序

顺序

还是使用上面的资源为例。首先我们使用单图test1.png和test2.png创建3个UI元素。

auto sprite1_1 = Sprite::create("res/test1.png");
if (sprite1_1 != nullptr)
{
    sprite1_1->setPosition(Vec2(200, 100));
    this->addChild(sprite1_1, 0);
}
    
auto sprite1_2 = Sprite::create("res/test1.png");
if (sprite1_2 != nullptr)
{
    sprite1_2->setPosition(Vec2(200, 120));
    this->addChild(sprite1_2, 0);
}
    
auto sprite2 = Sprite::create("res/test2.png");
if (sprite2 != nullptr)
{
    sprite2->setPosition(Vec2(200, 140));
    this->addChild(sprite2, 0);
}

在这里插入图片描述
此时的GL calls显示为2。(因为sprite1_1和sprite1_2使用的是同一纹理,所以会合并成一次绘制)

接下来我们换一下3个UI元素的添加顺序

auto sprite1_1 = Sprite::create("res/test1.png");
if (sprite1_1 != nullptr)
{
    sprite1_1->setPosition(Vec2(200, 100));
    this->addChild(sprite1_1, 0);
}
    
auto sprite2 = Sprite::create("res/test2.png");
if (sprite2 != nullptr)
{
    sprite2->setPosition(Vec2(200, 140));
    this->addChild(sprite2, 0);
}
    
auto sprite1_2 = Sprite::create("res/test1.png");
if (sprite1_2 != nullptr)
{
    sprite1_2->setPosition(Vec2(200, 120));
    this->addChild(sprite1_2, 0);
}

在这里插入图片描述
此时的GL calls变为了3。

为什么添加了相同的UI元素,绘制次数却会不同呢?这是因为添加顺序的改变,使sprite1_1和sprite1_2不再相邻,在UI树种它们之间还存在一个sprite2,所以即使它们使用的是相同的纹理,但是系统并不会将它们合并成一次绘制。

层级

上述例子中,在添加顺序不变的情况下,有没有办法使sprite1_1和sprite1_2也合并成一次绘制呢?答案是改变sprite2的层级。

auto sprite1_1 = Sprite::create("res/test1.png");
if (sprite1_1 != nullptr)
{
    sprite1_1->setPosition(Vec2(200, 100));
    this->addChild(sprite1_1, 0);
}
    
auto sprite2 = Sprite::create("res/test2.png");
if (sprite2 != nullptr)
{
    sprite2->setPosition(Vec2(200, 140));
    this->addChild(sprite2, 1);
}
    
auto sprite1_2 = Sprite::create("res/test1.png");
if (sprite1_2 != nullptr)
{
    sprite1_2->setPosition(Vec2(200, 120));
    this->addChild(sprite1_2, 0);
}

在这里插入图片描述
可以发现,改变sprite2的层级之后,GL calls又变回了2,也就是使用同一纹理的sprite1_1和sprite1_2又合成了一次绘制。
这是因为sprite2层级的改变使得sprite1_1和sprite1_2在UI树种的位置又变为了相邻。所以系统又将它们合成了一次绘制。

总结

1.视窗之外的UI元素不会被绘制;
2.可见性visible设置为false的UI元素不会被绘制,透明度设置为0的UI元素仍旧会被绘制;
3.使用plist合图可以减少绘制次数;
4.UI树中相邻且纹理相同的UI元素才会被合并绘制;
5.层级和添加顺序会影响UI元素在UI树中的位置,从而影响绘制次数;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值