您的位置:首页 > 其它

利用颜色混合ccBlendFunc实现遮罩效果

2017-06-26 15:50 183 查看
每一次完成一个学习完成一个功能,过了一段时间忘记当初是如何理解并实现的,因此就想记录下来以后顺手回来翻看

对于颜色混合的解释,网上已有大神做了解释,这里就直接拿来使用了,概念如下

1、概念

 “混合”是指两种颜色的叠加方式。在新图片将要渲染画到屏幕上的时候,将用在新图片中的红、绿、蓝和透明度信息,与屏幕上已经存在的图片颜色信息相融合。

    说的具体一点,就是把某一像素位置上原来的颜色和将要画上去的颜色,通过某种方式混在一起,从而实现特殊的效果。

    新图片颜色被称作“源颜色”,而屏幕上已存在的图片颜色则被称作“目标颜色”。

    OpenGL会把源颜色和目标颜色各自取出,并乘以一个系数(源颜色乘以的系数称为“源因子”,目标颜色乘以的系数称为“目标因子”),然后相加,这样就得到了新的颜色。

2、计算公式

假设:颜色信息的四个分量(红,绿,蓝,透明度)

        (1)“源颜色”  :(Rs, Gs, Bs, As)

        (2)“目标颜色”:(Rd, Gd, Bd, Ad)

        (3)“源因子”  :(Sr, Sg, Sb, Sa)

        (4)“目标因子”:(Dr, Dg, Db, Da)

    那么混合产生的新颜色可以表示为:

        (Rs*Sr + Rd*Dr , Gs*Sg + Gd*Dg , Bs*Sb + Bd*Db , As*Sa + Ad*Da)

    如果颜色的某一分量超过了1.0,则它会被自动截取为1.0,不需要考虑越界的问题。

3、混合因子



4、使用方法

Sprite精灵类中有一个设置混合方式的函数setBlendFunc(BlendFunc),另外混合方式的属性值是以BlendFunc结构体作为数据的,定义方式为:{
'源因子' , '目标因子' }

    混合方式可用于精灵纹理图片颜色信息的混合与叠加。

1.理解颜色混合。精灵有个成员函数:setBlendFunc(),这个函数以一个ccBlendFunc类型的变量为参数。这个ccBlendFunc是个结构体。这个结构体中有两个变量:src和
dest. 举个例子:

代码:

ccBlendFunc  spriteBlend;

spriteBlend.src = GL_ONE;

spriteBlend.dst = GL_ZERO;

pSprite->setBlendFunc(spriteBlend);

假设精灵pSprite是源颜色.则setBlendFunc的作用就是把精灵pSprite的各个像素的R,G,B,A分量和源颜色因子1.0(src
= GL_ONE)相乘.  如果精灵pSprite是目标颜色,则setBlendFunc的作用就是把精灵pSprite的各个像素的R,G,B,A分量和目标颜色因子(dst
= GL_ZERO)相乘.

 

如何界定pSprite是源颜色还是目标颜色呢?

如果这个时候还存在一个精灵pSpriteOther.如果pSprite先调用visit(),然后pSpriteOther后调用visit()(visit()的作用是递归的渲染精灵和他的孩子节点)。。。则先调用visit()的为目标颜色,后调用visit的为源颜色。即:pSprite是目标颜色,pSpriteOther为源颜色。

 

2.做精灵的遮罩效果为什么要用CCRenderTexture这个类。

你可能会觉得我们只需要先把mask(遮罩)精灵渲染上去,然后再渲染被遮罩的精灵,并且指定这两个精灵的blendFunc就行了。可是,实际上这样是行不通的!

因为被渲染上去的mask精灵下面如果还有其他的精灵。这样的话被渲染到mask精灵之上的精灵在做颜色混合的时候会出现意想不到的结果。达不到我们做遮罩的效果。

这样的话,我们需要一个比较干净的画板,这个干净的画板只有两个精灵在做颜色混合。这样的话这两个精灵在做颜色混合的时候就能达到我们想要的结果。不会受到不干净的背景造成的混合误差。这个背景就是CCRenderTexture.

 

当然如果我们的layer上只有精灵做混合的话就用不着CCRenderTexture了。但是实际项目中基本上是不能的。

CCSize size = CCDirector::sharedDirector()->getWinSize();
//创建干净的画板
CCRenderTexture *pRt = CCRenderTexture::create(size.width,size.height);
CCAssert(pRt, "RenderTexture is invalid");
addChild(pRt);
pRt->setPosition(size.width/2,size.height/2);
//创建遮罩图片
CCSprite *pMask = CCSprite::create("CalendarMask.png");
CCAssert(pMask,"mask sprite is invalid");
pMask->setPosition(CCPointMake(pMask->getContentSize().width/2, pMask->getContentSize().height/2));
//创建被遮罩图片
CCSprite *pFlower = CCSprite::create("Calendar1.png");
CCAssert(pFlower, "Flower sprite is invalid");
pFlower->setPosition(CCPointMake(pFlower->getContentSize().width/2, pFlower->getContentSize().height/2));

//先设置好 遮罩精灵 和 被遮罩精灵 在被渲染的时候采用什么样的颜色混合法则
ccBlendFunc maskBlend = {GL_ONE, GL_ZERO};
ccBlendFunc flowerBlend = {GL_DST_ALPHA, GL_ZERO};
pMask->setBlendFunc(maskBlend);
pFlower->setBlendFunc(flowerBlend);

//开始把各种精灵渲染到画板上
pRt->begin();
//先渲染遮罩精灵。但是因为有个画板先被渲染。所以pMask是第二个被渲染的,即后被渲染。
//所以在这一刻pMask是源颜色。调用pMask->visit()的时候吧精灵pMask上的每个像素的RGBA分量和1.0相乘。
//所以遮罩图片被元模原样的渲染出来.
pMask->visit();
//再渲染被遮罩的精灵.在这一刻,之前先有pMask被渲染。所以pFlower后被渲染。pFlower就是源颜色。之前的pMask就是目标颜色。
//调用pFlower->visit()的时候,精灵pFlower上的对应像素的RGBA分量和pMask上的对应像素的A分量相乘.因为前面设置了GL_DST_ALPHA。 //因为例子中目标图片(下面的图片)除了白色区域之外其他都是透明色的,因此只需在渲染pFlower时按照目标透明度显示即可实现
pFlower->visit();
//停止渲染到画板
pRt->end();
以上代码取自http://blog.csdn.net/qq51931373/article/details/9141979,做出来的效果如下:



遮罩图片(PNG)目标颜色



这个遮罩图片是个不规则的边缘的图片,其本事是个矩形。除了白色区域有像素外,其他区域没像素,是全透明的。以上图片中显浅蓝色的区域是我截取的时候故意这样做的 。实际上这一区域是全透明的。

被遮挡图片(源颜色)



采用GL_DST_ALPHA把遮挡图片对应像素的RGBA分量和 被遮挡图片的A分量相乘.这样的话,遮挡图片中透明的区域在被遮挡图片上对应的区域就全透明了。

之前一直使用CCClippingNode实现遮罩,也是初次学习。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: