cocos2d-SpriteBatchNode与SpriteFrameCache加快渲染的优缺点

 大家都知道一个游戏里面会有大量的图片,每个图片渲染是需要时间的,下面分析两个类来加快渲染速度,加快游戏运行速度 
        一、SpriteBatchNode 
        1、先说下渲染批次:这是游戏引擎中一个比较重要的优化指标,指的是一次渲染凋用。也就是说,渲染的次数越少,游戏的运行效率越高。 
        2、SpriteBatchNode就是cocos2d-x为了降低渲染批次而建立的一个专门管理精灵的类。  
        有人会问,怎么快速知道到底渲染了多少次了,告诉你吧,游戏左下角有三行数据: 
        GL verts 表示给显卡绘制的顶点数 
        GL calls 表示代表每一帧中OpenGL指令的调用次数 
        FPS 这个是帧率不多说 
        主要看第二个“GL calls”代表每一帧中OpenGL指令的调用次数,这个数字越小,程序的绘制性能就越好。我们有没有法子让他小点了,答案当然是yes 
        首先我们使用sprite创建100个精灵,看看这个值是多少 
        code: 
        
        for(int i = 0; i < 100; ++ i)
        {
         char name[15];
         memset(name, 0, sizeof(name));
         sprintf(name, "%d.png", i % 10);
         auto sp = Sprite::create(name);
         sp->setPosition(Point(i*5,i*5));
         node->addChild(sp);
        }
        this->addChild(node);
         
        这个循环创建了100个精灵,显示出来,看效果 
         
          看左下角红色圈圈,有101次绘制,其中100个元素每个元素绘制一次,多出来的一次是绘制这个左下角信息自己。 
        在来看看使用SpriteBatchNode 
        code: 
         
        auto spBatchNode = SpriteBatchNode::create("0.png");
         spBatchNode->setPosition(Point::ZERO);
         this->addChild(spBatchNode);
         for(int i = 0; i < 100; ++ i)
         {
         count++;
         //float x = CCRANDOM_0_1() * visibleSize.width;
         //float y = CCRANDOM_0_1() * visibleSize.height;
         //log("x=%lf, y=%lf",x, y);
         char name[15];
         memset(name, 0, sizeof(name));
         sprintf(name, "%d.png", i % 10);
         auto sp = Sprite::createWithTexture(spBatchNode->getTexture());
         sp->setPosition(Point(i*5,i*5));
         spBatchNode->addChild(sp);
         }看效果图 
         
          看到没,立马减到2了,这快了太多了。这是一个提速,在来看看SpriteFrameCache 
        二、SpriteFrameCache 
         首先我们使用合图软件,将这10张图合成一张大图和一个plist文件。在使用CocoStudio导出时,选择“使用大图”即可将小图合成一张大图。当然我们也可以选择TexturePacker这种专业的合图软件,合成的图片分为“test.png”和“test.plist”两部分,然后使用SpriteFrameCache。  
        code: 
         
        SpriteFrameCache::getInstance()->addSpriteFramesWithFile("test.plist","test.png"); 
        Node* node = Node::create(); 
        char name[32]; 
        for(int i = 0;i<100;++i) 
        { 
        char name[15];
        memset(name, 0, sizeof(name));
        //auto sprite = Sprite::create(name); 
        auto sprite = Sprite::createWithSpriteFrameName(name); 
        sprite->setPosition(Point(i*5,i*5)); 
        node->addChild(sprite, 0); 
        } 
        this->addChild(node);
        这段代码中,我们调用addSpriteFramesWithFile函数,将大图载入到内存中,创建对象时,调用createWithSpriteFrameName从缓存纹理中载入图片。如此做我们所有的绘制调用都可以合并到一次OpenGL指令中,这些绘制指令的计算与合并都由Cocos2d-x引擎完成。编译运行如下图所示:
         
         
           
        我们可以非常明显的看到,优化后的程序“GL calls”依然变成了2次。 
        还有一种优化,就是当精灵超出屏幕后就剔除掉,这样也能减少OpenGL指令。 
          
        三、绘制剔除 
         相对于上一种优化,这个要更容易理解。它是指当一个元素移动到屏幕之外,就不进行绘制。  
        code: 
         
        Node* node = Node::create();
        
        for(int i  = 0;i<100;++i)
        {
         char name[15];
         memset(name, 0, sizeof(name));
         sprintf(name, "%d.png",i%10);
         auto sprite = Sprite::create(name);
         //auto sprite = Sprite::createWithSpriteFrameName(name);
         sprite->setPosition(Point(i*5,i*5));
         node->addChild(sprite, 0);
        }
        this->addChild(node);
        
        auto listener = EventListenerTouchOneByOne::create();
        listener->onTouchBegan = [=](Touch *pTouch, Event *pEvent)
        {
         return true;
        };
        listener->onTouchMoved = [=](Touch *pTouch, Event *pEvent)
        {
         node->setPosition(node->getPosition()+pTouch->getDelta());
        };
        Director::getInstance()->getEventDispatcher()->
         addEventListenerWithSceneGraphPriority(listener, this);
        
        return true;}
        
        效果图如下: 
         
           
        我们发现GL calls也变小了,这也是一种不错的方法 
          
        四、小结 总的来说,这两点优化可以说是对程序性能有了极大提升。同时在开发的过程中,也使程序员不必过多的纠结于渲染效率的优化。  

限制:

Sprite 和 SpriteBatchNode

v2.2 2.2版本中推荐的优化游戏方式是将 SpriteBatchNode 对象设置为 Sprite 对象的父节点。 虽然使用 SpriteBatchNode 对象仍然是一个非常好的优化游戏的方式,但是它仍然有一定的限制:
•Sprite 对象的孩子只能是 Sprite (否则,Cocos2d-x 会触发断言) ◦当 Sprite 的父节点是 SpriteBactchNode 时,不能添加 ParticleSystem 作为 Sprite的子节点。
◦这将导致当 Sprite 的父节点是 SpriteBatchNode 时,不能使用 ParallaxNode

•所有的 Sprite 对象必须共享相同的纹理ID (否则,Cocos2d-x 会触发断言)
•Sprite 对象使用 SpriteBatchNode 的混合函数和着色器。

虽然 v3.0 仍然支持 SpriteBatchNode (与之前的版本拥有相同的特效和限制),但是我们不鼓励使用它。相反,我们推荐直接使用 Sprite,不需要再它作为子节点添加到 SpriteBatchNode 中。

但是,为了能让 v3.0 有更好的表现,你必须要确保你的 Sprite 对象满足以下条件:
•贡献相同的纹理ID(把它们放在一个spritesheet中,就像使用 SpriteBatchNode 一样)
•确保它们使用相同的着色器和混合函数(就像使用 SpriteBatchNode 一样)

如果这么做, Sprites 将会像使用 SpriteBatchNode 一样的快…(在旧设备上大概慢了10%,在新设备上基本上察觉不出)

v2.2 和 v3.0 最大的区别在于:
•Sprite 对象可以有不同的纹理ID。
•Sprite 对象可以有不同种类的 Node 作为子节点,包括 ParticleSystem。
•Sprite 对象可以有不同的混合函数和不同的着色器。

但是如果你这么做,渲染器 可能无法对它所有的子节点进行批处理(性能较低)。但是游戏仍然可以正常运行,不会触发任何断言。

总结:
•保持将所有的精灵放在一张大的 spritesheet 中。
•使用相同的混合函数(使用默认)
•使用相同的着色器(使用默认)
•不要将精灵添加到 SpriteBatchNode

只有当你需要一些额外的性能上提升(虽然很小),SpriteBatchNode 才会是你最后的选择(你需要对它的限制条件很熟悉)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值