[{"data":1,"prerenderedAt":87},["ShallowReactive",2],{"\u002F2013-04-19-cocos2d-x%E4%B8%ADmask%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8F%8A%E4%BC%98%E5%8C%96":3},{"id":4,"title":5,"body":6,"date":64,"description":12,"extension":65,"meta":66,"navigation":69,"path":81,"seo":82,"stem":83,"tags":84,"__hash__":86},"blogs\u002F_legacy\u002F2013\u002F2013-04-19-cocos2d-x%e4%b8%admask%e7%9a%84%e5%ae%9e%e7%8e%b0%e5%8f%8a%e4%bc%98%e5%8c%96.md","cocos2d-x中Mask的实现及优化",{"type":7,"value":8,"toc":60},"minimark",[9,13,16,19,22,33,36,42,45,51,54],[10,11,12],"p",{},"关于cocos2d-x内的Mask来做类似光点或者视野控制等功能的思路，最早是在一篇外文上看到的。",[10,14,15],{},"拿来用过之后发现效果还是不错，于是直接放进了程序里。可是在实际运用时发现其运行效率不是那么理想，尤其是以pc平台为目标时由于配置不同造成的帧率下降比较明显。对代码进行分析之后发现，Mask的功能使用的是CCRenderTexture动态生成纹理并覆盖在目标层上的。在每一次绘制中，这个纹理都会重新生成一次，这就造成了极大的效率上的浪费。同时CCRenderTexture貌似使用了FBO，在某些旧的显卡上会引发极大的帧率丢失。",[10,17,18],{},"于是着手对其进行改造，事实上之所以要每次循环都重新生成纹理是因为mask本身的位置会不断更新。而如果打算单独使用sprite+glblencfunc来解决的话，由于绘制顺序的关系很难找到一个好的动态mask解决方案。当然准备一个大概四倍视口的mask图片是可以的，但是这样的话效率也比较低下，只能留作备选方案。",[10,20,21],{},"最终选择的解决方案是使用clippingnode，clippingnode是使用模板测试来实现的，这是gl的基础功能，不会对硬件有太大的需求。以一个CCColorlayer为Clipping的content，首先进行模板测试，然后再叠加作为遮罩的sprite就好了。",[23,24,29],"pre",{"className":25,"code":27,"language":28},[26],"language-text","        csb_st = CCSpriteBatchNode::create(\"Images\u002Fcircle.png\");\n\n        cp_board = CCClippingNode::create();\n        cp_board->setContentSize(visibleSize);\n        cp_board->setPosition(CCPointZero);\n        cp_board->setAnchorPoint(CCPointZero);\n        cp_board->setStencil(csb_st);\n        cp_board->setInverted(true);\n\n        \u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\n\n        CCLayerColor* clc = CCLayerColor::create(ccc4BFromccc4F(m_renderColor),visibleSize.width,visibleSize.height);\n        clc->setAnchorPoint(CCPointZero);\n        clc->setPosition(CCPointZero);\n        cp_board->addChild(clc);            \u002F\u002Fcontent\n        cn_borad->addChild(cp_board,m_iLaDep+1);\n\n        CC_BREAK_IF(!f_refresh_circles());\n","text",[30,31,27],"code",{"__ignoreMap":32},"",[10,34,35],{},"sprite的话使用传说中的经典地图遮罩blend就好了：",[23,37,40],{"className":38,"code":39,"language":28},[26],"        ccBlendFunc cbf = {GL_DST_COLOR, GL_ZERO};\n\n        cns_blocks = CCSpriteBatchNode::create(\"Images\u002Fcircle.png\");\n        cns_blocks->setBlendFunc(cbf);\n        cp_board->addChild(cns_blocks);\n\n        \u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\u002F\n        m_AkaruCircle = CCSprite::create(\"Images\u002Fcircle.png\");\n        m_AkaruCircle->setBlendFunc(cbf);\n        m_AkaruCircle->setPosition(ccp(200,200));\n        m_AkaruCircle->setScale(4);\n        m_Board->addChild(m_AkaruCircle,m_iLaDep);\n",[30,41,39],{"__ignoreMap":32},[10,43,44],{},"当然，这样的话由于GLZERO的blend结果是(0,0,0,0)，如果不是做纯黑的不透明遮罩，即便精心的准备遮罩图片，多少还是会有一些违和感存在，如果出现这种情况而无法从其他方面进行修正的话，还是必须使用rendertexture。由于rendertexture的效率因素，我们必须尽量减少其负担，只是对sprite进行处理，除非需要动态改变遮罩的背景色，我们都不会对sprite进行重新生成。",[23,46,49],{"className":47,"code":48,"language":28},[26],"    ccBlendFunc cbf = {GL_ZERO, GL_ONE_MINUS_SRC_ALPHA};\n\n    CCSprite* t_sp = CCSprite::create(\"Images\u002Fcircle.png\");\n    t_sp->setPosition(CCPointZero);\n    t_sp->setAnchorPoint(CCPointZero);\n    t_sp->setBlendFunc(cbf);\n\n    CCSize vs = t_sp->getContentSize();\n    CCRenderTexture* t_crt = CCRenderTexture::create(vs.width, vs.height);\n    t_crt->beginWithClear(m_renderColor.r, m_renderColor.g, m_renderColor.b, m_renderColor.a);\n\n    t_sp->visit();\n\n    t_crt->end();\n\n    m_AkaruCircle = CCSprite::createWithTexture(t_crt->getSprite()->getTexture());\n    \u002F\u002Fm_AkaruCircle->autorelease();\n    m_AkaruCircle->setScale(4);\n    m_Board->addChild(m_AkaruCircle,m_iLaDep);\n",[30,50,48],{"__ignoreMap":32},[10,52,53],{},"这样一来Mask的总体效率就是一次模板测试加上两次spritebachnode的绘制，可以作为频繁使用CCRenderTexture的替代方案使用了。代码如下，由于目前的代码结构的关系，要测试的话spotlight类需要被继承，然后在适当的地方调用f_init才行。",[23,55,58],{"className":56,"code":57,"language":28},[26],"http:\u002F\u002Fpan.baidu.com\u002Fshare\u002Flink?shareid=418465&uk=1913549955\n",[30,59,57],{"__ignoreMap":32},{"title":32,"searchDepth":61,"depth":62,"links":63},2,3,[],"2013-04-19","md",{"layout":67,"status":68,"published":69,"author":70,"author_login":71,"author_email":72,"author_url":73,"wordpress_id":74,"wordpress_url":75,"date_gmt":76,"excerpt":77},"post","publish",true,{"display_name":71,"login":71,"email":72,"url":73},"chaoshikari","chaoshikari@gmail.com","\u002F",584,"\u002F\u002F?p=584","2013-04-19 02:36:10 +0000",{"type":7,"value":78},[79],[10,80,12],{},"\u002F2013-04-19-cocos2d-x中mask的实现及优化",{"title":5,"description":12},"_legacy\u002F2013\u002F2013-04-19-cocos2d-x%e4%b8%admask%e7%9a%84%e5%ae%9e%e7%8e%b0%e5%8f%8a%e4%bc%98%e5%8c%96",[85],"cocos2d-x","w5H-e_q5-z-K_GRIO7KBBcCSB0I-LhvGFj22Pb2c2yI",1788763183300]