每一次完成一个学习完成一个功能,过了一段时间忘记当初是如何理解并实现的,因此就想记录下来以后顺手回来翻看
对于颜色混合的解释,网上已有大神做了解释,这里就直接拿来使用了,概念如下
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实现遮罩,也是初次学习。
CCClippingNode图文详解见http://www.mamicode.com/info-detail-247772.html