注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

熊猫正正的博客

熊猫正正的天空

 
 
 

日志

 
 

在 COCOS2D-X 中实现蒙版支持(一)——使用 CCRENDERTEXTURE  

2014-07-30 11:36:20|  分类: ios游戏开发 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
  • 本站文章除注明转载外,均为本站原创或者翻译。
  • 本站文章欢迎各种形式的转载,但请18岁以上的转载者注明文章出处,尊重我的劳动,也尊重你的智商;
  • 本站部分原创和翻译文章提供markdown格式源码,欢迎使用文章源码进行转载;
  • 本文标题:在 cocos2d-x 中实现蒙版支持(一)——使用 CCRenderTexture
  • 本文链接:http://zengrong.net/post/2060.htm


在 cocos2d-x 中实现蒙版支持(一)——使用 CCRenderTexture

Get a masked sprite in cocos2d-x use CCRenderTexture

在 cocos2d-x 框架中,并没有为我们提供蒙版支持。想想 AS3 中的 mask 属性,多么地让人怀念啊!

这个系列文章讲解如何在 cocos2d-x 中实现蒙版的支持。

依赖

本文基于 cocos2d-x 2.2.1 和 quick-cocos2d-x 2.2.1 rc 。

系列文章

CCRenderTexture

我们可以将这个类看成 AS3 中的 BitmapData 类。它实现了一块屏幕之外的画布,我们可以利用 OpenGL ES 在上面进行渲染,然后将得到的像素进行处理,并绘制在屏幕上。

实现方案

为了实现遮罩,我们需要两张图片,一张为遮罩图片(mask.png),一张为被遮罩图片(helloworld.jpg)。

mask.png

mask.png

这张图片中有颜色的部分,根据颜色的 alpha 的值,显示被遮罩图片中对应的像素;没有颜色的部分(alpha为0),则不显示任何被遮罩图片的像素。

helloworld.jpg

helloworld.jpg

最终效果如下:

masked.png

masked.png

流程如下:

1. 分别创建遮罩图片和被遮罩图片的 CCSprite 对象,统一使用左下角对齐;

1
2
3
4
5
6
7
CCSprite* __pMask = CCSprite::create("mask.png");
__pMask->setAnchorPoint(ccp(0, 0));
__pMask->setPosition(ccp(0, 0));
 
CCSprite* __pImg = CCSprite::create("helloworld.jpg");
__pImg->setAnchorPoint(ccp(0, 0));
__pImg->setPosition(ccp(0, 0));

2. 创建两个混合模式对象,分别设置给蒙版图像和被蒙版图像;

这两个 ccBlendFunc 实现了以蒙版图像的像素透明度来显示被蒙版图像。具体的含义,可以参考这里: glBlendFunc

一个更直观的例子和实时预览工具,可以看这里:Visual glBlendFunc + glBlendEquation Tool 。

1
2
3
4
5
ccBlendFunc __maskBF = { GL_ONE, GL_ONE };
__pMask->setBlendFunc(__maskBF);
 
ccBlendFunc __imgBF = { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA };
__pImg->setBlendFunc(__imgBF);

3. 创建一个 CCRenderTexture 的实例,将其初始化为被遮罩图片的大小;

1
2
CCSize __size = __pImg->getContentSize();
CCRenderTexture* __pRender = CCRenderTexture::create(__size.width, __size.height);

4. 依次绘制蒙版图像和被蒙版图像,注意是先绘制蒙版图像,再绘制被蒙版图像;

1
2
3
4
__pRender->begin();
__pMask->visit();
__pImg->visit();
__pRender->end();

5. 创建一个新的 CCTexture2D 对象,并根据此纹理建立一个 CCSprite ,搞定。

1
2
3
4
5
CCTexture2D* __pTex = new CCTexture2D();
__pTex->initWithImage(__pRender->newCCImage(true));
__pTex->autorelease();
CCSprite* __newSprite = CCSprite::createWithTexture(__pTex);
this->addChild(__newSprite);

在这一步中,还有一个做法,就是直接从 CCRenderTexture 中包含的 CCSprite 对象中获取 CCTexture2D 对象,然后创建新的 CCSprite:

1
2
3
4
CCTexture2D* __pTex = __pRender->getSprite()->getTexture();
CCSprite* __newSprite = CCSprite::createWithTexture(__pTex);
__newSprite->filpY(true);
this->addChild(__newSprite);

但由于得到的纹理是根据Y轴反转过的,我们必须再把它反转回来。

那么上面使用 de style="border: 0px; font-family: monospace, serif; font-size: 15px; font-style: inherit; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; -webkit-hyphens: none; line-height: 1.6;" >newCCImagede> 得到的纹理为什么不用翻转呢?

其实不然, de style="border: 0px; font-family: monospace, serif; font-size: 15px; font-style: inherit; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; -webkit-hyphens: none; line-height: 1.6;" >newCCImage(true)de> 这个调用中的参数 true 就代表需要翻转纹理。

完整代码(C++)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ccBlendFunc __maskBF = { GL_ONE, GL_ONE };
ccBlendFunc __imgBF = { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA };
 
CCSprite* __pMask = CCSprite::createWithTexture($sprite->getTexture());
__pMask->setAnchorPoint(ccp(0, 0));
__pMask->setPosition(ccp(0, 0));
 
CCSprite* __pImg = CCSprite::createWithTexture($sprite->getTexture());
__pImg->setAnchorPoint(ccp(0, 0));
__pImg->setPosition(ccp(0, 0));
 
__pMask->setBlendFunc(__maskBF);
__pImg->setBlendFunc(__imgBF);
 
CCSize __size = __pImg->getContentSize();
CCRenderTexture* __pRender = CCRenderTexture::create(__size.width, __size.height);
__pRender->begin();
__pMask->visit();
__pImg->visit();
__pRender->end();
 
CCTexture2D* __pTex = new CCTexture2D();
__pTex->initWithImage(__pRender->newCCImage(true));
__pTex->autorelease();
CCSprite* __newSprite = CCSprite::createWithTexture(__pTex);
this->addChild(__newSprite);

完整代码(lua)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
--- Create a masked sprite
-- @author zrong(zengrong.net)
-- Creation: 2014-01-21
function display.newMaskedSprite(__mask, __pic)
    local __mb = ccBlendFunc:new()
    __mb.src = GL_ONE
    __mb.dst = GL_ZERO
 
    local __pb = ccBlendFunc:new()
    __pb.src = GL_DST_ALPHA
    __pb.dst = GL_ZERO
 
    local __maskSprite = display.newSprite(__mask):align(display.LEFT_BOTTOM, 0, 0)
    __maskSprite:setBlendFunc(__mb)
 
    local __picSprite = display.newSprite(__pic):align(display.LEFT_BOTTOM, 0, 0)
    __picSprite:setBlendFunc(__pb)
 
    local __maskSize = __maskSprite:getContentSize()
    local __canva = CCRenderTexture:create(__maskSize.width,__maskSize.height)
    __canva:begin()
    __maskSprite:visit()
    __picSprite:visit()
    __canva:endToLua()
 
    local __resultSprite = CCSpriteExtend.extend(
        CCSprite:createWithTexture(
            __canva:getSprite():getTexture()
        ))
        :flipY(true)
    return __resultSprite
end

性能忧虑

在进行了上面的处理之后,CCSprite 其实就变成了一张单独的纹理图片,在显示的时候就和我们从文件中调用的图片一样进行渲染。

这种做法虽然方便,但它会对GPU造成一定的消耗,毕竟合并的工作是实时完成的。GPU在程序运行的过程中帮我们进行了类似 Photoshop 所做的图层合并处理。如果这样的操作过多,肯定会对性能有影响。

在 cocos2d-x 中实现蒙版支持(二)——使用 CCClippingNode(待完成) 一文中,我们会再看看另一种性能更好的实现遮罩的方法。

  评论这张
 
阅读(125)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017