cocos2d-x 精灵遮罩
转自:http://bbs.9ria.com/thread-220210-1-4.html
首先得理解一些东西。
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了。但是实际项目中基本上是不能的。
OK。看看我们的Code.
CCSize size = CCDirector::sharedDirector()->getWinSize();
//创建干净的画板
CCRenderTexture *pRt = CCRenderTexture::create(size.width,size.height);
CCAssert(pRt, "RenderTexture is invalid");
addChild(pRt);
pRt->setPosition(size.width/,size.height/);
//创建遮罩图片
CCSprite *pMask = CCSprite::create("CalendarMask.png");
CCAssert(pMask,"mask sprite is invalid");
pMask->setPosition(CCPointMake(pMask->getContentSize().width/, pMask->getContentSize().height/));
//创建被遮罩图片
CCSprite *pFlower = CCSprite::create("Calendar1.png");
CCAssert(pFlower, "Flower sprite is invalid");
pFlower->setPosition(CCPointMake(pFlower->getContentSize().width/, pFlower->getContentSize().height/)); //先设置好 遮罩精灵 和 被遮罩精灵 在被渲染的时候采用什么样的颜色混合法则
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->visit();
//停止渲染到画板
pRt->end();
上面看注释就懂了。
先看遮罩图片(PNG)目标颜色
这个遮罩图片是个不规则的边缘的图片,其本事是个矩形。除了白色区域有像素外,其他区域没像素,是全透明的。以上图片中显浅蓝色的区域是我截取的时候故意这样做的 。实际上这一区域是全透明的。
再看被遮挡图片(源颜色)
采用GL_DST_ALPHA把遮挡图片对应像素的RGBA分量和 被遮挡图片的A分量相乘.这样的话,遮挡图片中透明的区域在被遮挡图片上对应的区域就全透明了。
效果如下图。
黑色的区域是layer的背景.
话中貌似用CCRenderTexture的方式效率很低下,但是本人也没深究过。
2、高效率遮罩
先说下模板缓冲(stencil buffer),这在05年还算是一个比较普及的技术。cocos2d-x现在的版本是不支持stencil buffer的,但opengl es是支持的。
可以简单的动手改造一下:
创建stencil buffer。在ES1Renderer.m文件中找到resizeFromLayer方法,将if (depthFormat_){}大括号中的代码替换成以下内容:
if (depthFormat_)
{
if( ! depthBuffer_ )
glGenRenderbuffersOES(, &depthBuffer_); glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthBuffer_);
if( multiSampling_ )
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, samplesToUse_, depthFormat_,backingWidth_, backingHeight_);
else
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, depthFormat_, backingWidth_, backingHeight_);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthBuffer_);
// add by frankyang at 2012/5/8
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_STENCIL_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthBuffer_);
// bind color buffer
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer_);
}
设置stencil buffer格式。在AppController.mm中找到的didFinishLaunchingWithOptions方法,将其中的depthFormat参数改为GL_DEPTH24_STENCIL8_OES,如下:
// Add the view controller's view to the window and display.
window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
EAGLView *__glView = [EAGLView viewWithFrame: [window bounds]
pixelFormat: kEAGLColorFormatRGBA8
//depthFormat: GL_DEPTH_COMPONENT16_OES
depthFormat:GL_DEPTH24_STENCIL8_OES
preserveBackbuffer: NO
sharegroup:nil
multiSampling:NO
numberOfSamples:];
设置每帧渲染开始时清除stencil buffer。在CCDirector.cpp中找到drawScene方法,将其中
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
改成
glClear(GL_COLOR_BUFFER_BIT | GL_COLOR_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
这样就可以正确清除stencil buffer。
启动模板测试,设置模板函数。这里要用到三个函数:
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0x1, 0x1);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
第一个是启用模板测试,第二个是设置模板测试函数,第三个是设置模板缓冲操作方式。
模板测试简单来说就是先往模板缓冲中写入模板值,然后渲染时根据模板测试结果来决定像素是否写入color buffer。
具体解释大家可以看这个帖子深入了解OpenGL-模板测试
为了灵活的写入模板值,我借鉴了Quaz2D中maskLayer的概念,在要渲染的Layer前后插入MaskBeginLayer和MaskEndLayer。
用MaskBeginLayer来填充模板缓冲,并设定好之后需要的模板测试函数;用MaskEndLayer来恢复模板测试状态。
void MaskBeginLayer::visit()
{
if (getChildrenCount() != ) {
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0); glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0x1, 0x1);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); CCLayer::visit(); glDisable(GL_ALPHA_TEST);
glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
}
}
void MaskEndLayer::visit()
{
glDisable(GL_STENCIL_TEST); CCLayer::visit();
}
这里要注意透明像素也会写入stencil buffer,所有特别用了alphatest。
经过真机测试,这样实现mask性能是无损的。由于不影响alpha blend,使用起来比较灵活。唯一不好的是mask不支持渐变,要么全透,要么全部透。
现在我在研究直接用alpha blend操作实现mask,性能一样无损,还可以支持渐变,但也有其局限性,且听下回分解。
cocos2d-x 精灵遮罩的更多相关文章
- Cocos2D添加精灵纹理滤镜实现图像复古效果的转换
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 大家知道Cocos2d本身是一个非常强悍的2d游戏引擎,其中自 ...
- Unity遮罩之Mask、RectMask2D与Sprite Mask适用场景分析
遮罩,顾名思义是一种可以掩盖其它元素的控件.常用于修改其它元素的外观,或限制元素的形状.比如ScrollView或者圆头像效果都有用到遮罩功能.本系列文章希望通过阅读UGUI源码的方式,来探究遮罩的实 ...
- (三)相遇射线的3D碰撞盒
序 在2D游戏中,我们知道处理碰撞时,需要设置精灵遮罩图.同样,进入3D,处理碰撞时需要3D模型作为“遮罩图”. 索尼克 飞檐走壁 目的 (1)处理模型间的碰撞问题 (2)获取鼠标 ...
- 【Cocos2D-x 3.5实战】坦克大战(2)游戏开始界面
关于游戏的素材都是在网上到处搜集到的,然后自己再用二流的ps技术修修改改的,所以有可能混在一起有点不搭调(没有办法啊,没有美工Orz.. 项目已经建立好了,然后我们需要把我们下载的素材放到Resour ...
- cocos2d_x_05_Box2D物理引擎
一.认识Box2D 帮助文档,共69页 二.创建一个物理世界 先导入主头文件 #include <Box2D/Box2D.h> 三.物理世界一览 像素转成米 的比例因子 就是32 三.运动 ...
- Unity3d 2017
Unity3d引擎的新纪元--Unity3d 2017 来源 http://blog.csdn.net/dark00800/article/details/75209544 Unity3d不久之前正式 ...
- Sprite Atlas与Sprite Mask详解
https://www.sohu.com/a/169409304_280780 Unity 2017.1正式发布后,带来了一批能帮助大家更加简化工作流的新功能.今天这篇文章,将由Unity技术经理成亮 ...
- [一位菜鸟的COCOS-2D编程之路]精灵表单的制作以及简易动画的生成
1.第一步:使用Zwoptex 制作精灵表单 2.制作的表单的名称为 cocos2Dpng,cocos2D.plist: 3.精灵的动画效果 主要分为五部分. // on "init&quo ...
- Cocos2d学习之路三(使用Zwoptex创建精灵表单和CCAnimate动画)
创建精灵表单: 创建动画先要把图片整合到一个图片上然后生成plist文件: 方法下载Zwoptex软件:http://www.zwopple.com/zwoptex/ 然后打开选择 create ne ...
随机推荐
- poj 3253 Fence Repair (哈夫曼树 优先队列)
题目:http://poj.org/problem?id=3253 没用long long wrong 了一次 #include <iostream> #include<cstdio ...
- Eclipse环境下JBoss调试,解决引用的工程不被部署的问题
其实算是一个很小的经验,在eclipse环境下进行jboss的部署,因为要定义某公共包的问题,将代码down下来做了个工程,部署时发现jboss提示:class not found! 从jboss部署 ...
- 解决android手机sd卡安装pak后直接打开,按home键异常问题
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) { finish(); return; }
- [开发工具] 史上最全系列之开发环境搭建之DDMS
原文链接:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=275774 一.简介 DDMS 的全称是DalvikDebug Mon ...
- Spring Bean之间的关系
bean之间的关系:继承和依赖继承bean的配置 Spring允许继承bean的配置,被继承的bean称为父bean,继承这个父bean的bean称为子bean 子bean从父bean中继承配置,包括 ...
- java问题若干
1.Java处理本身包含双引号的String 解决:使用转义字符.如:String str = "select * from \"TAB_catalog\" " ...
- MySQL中间层 Atlas
Atlas是由 Qihoo 360, Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目.它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基础上,修改了大量bu ...
- static用法详解
一. 面向过程程序设计 1.静态全局变量 在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量.我们先举一个静态全局变量的例子,如下: //Example 1 #include & ...
- UPC OJ 一道水题 STL
Problem C: 字符串游戏 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 10 Solved: 3 [Submit][Status][Web ...
- HDU 1024 DP Max Sum Plus Plus
题意:本题的大致意思为给定一个数组,求其分成m个不相交子段和最大值的问题. kuangbin专题. dp[i][j]=Max(dp[i][j-1]+a[j] , max( dp[i-1][k] ) + ...