cocos2dx遮罩失效的解决与分析

7 篇文章 0 订阅
2 篇文章 0 订阅

问题描述

  CCClippingNode在Windows下显示正常,能够正常裁剪,但移植真机后,iOS系统下却无法正常裁剪;

解决办法

  使用cocos2dx建立的默认工程,是不开启Stencil Buffer的,需要自己手动开启;

  开启办法:打开AppController.mm,将初始化EAGLView的代码里的GL_DEPTH_COMPONENT16改成GL_DEPTH24_STENCIL8_OES即可。  


解释:关于openGL的渲染机制

什么是模板缓冲(Stencil Buffer)

模板缓冲类似于深度缓冲。事实上,它使用深度缓冲的一部分(因此,深度缓冲常常被称做depth-stencil缓冲)。深度缓冲让程序员可以设置一个模板函数测试"reference(参考)"模板值-一个全局值 – 每次当这个值仍然在模板缓冲时像素才会被绘制。

模板测试的结果决定了像素的颜色值是否要被写入到渲染目标,像素的深度值是否要被写入深度缓冲。

例如,当参考模板值为0时将一些物体绘制到场景中,而此时模板缓冲已经清除为1,那么当绘制这些物体时模板缓冲就会为0。如果接着将参考值设置为1,而且StencilFunction设置为 CompareFunction.LessEqual,那么只有那些模板值不为0的对应区域的像素会被绘制。这是使用模板缓冲创建一个限制当前绘制区域的基本用法。

模板缓冲还有许多更高级的用法。指定StencilOperations除了可以进行替换或抛弃操作,还可以在每次模板测试后减少或增加模板缓冲,这可以和StencilMask值组合起来保证模板测试只作用在模板缓冲的一部分区域上。

要使用模板缓冲,DepthFormat必须保留一些字节用于模板缓冲。DepthFormat.Depth24Stencil8深度格式使用了8位用于一个模板缓冲。当你将这个格式与RenderState.StencilMask属性组合起来时,它可以提供8个不同的模板缓冲。Depth24Stencil4 深度格式使用4位用于模板缓冲,而DepthFormat.Depth15Stencil1格式只允许1位。可以将ClearOptions.StencilBuffer传递到GraphicsDevice.Clear方法单独清除模板缓冲。

你可以使用DepthStencilBuffer类创建自己的depth-stencil缓冲。当创建一个自定义渲染目标时你需要创建自己的depth-stencil缓冲。

深度缓冲是一个与你的渲染目标(render target)相同大小的缓冲,这个缓冲记录每个像素的深度。

  当一个像素第二次被绘制时– 例如当一个物体在另一个物体之后被绘制- 深度缓冲要么保留前面的深度值,要么使用第二个像素的深度值替换当前深度值。那个深度保留哪个深度抛弃取决于你选择的深度函数。例如,如果当前深度函数是CompareFunction.LessEqual时,只有小于等于当前深度值的值才会被保留,而大于当前深度值的值会被抛弃。这叫做深度测试,每次绘制像素时都会进行深度测试。当对一个像素进行深度测试时,它的颜色会被写入渲染目标,而深度被写入深度缓冲。

  像素的深度值是由视矩阵和投影矩阵决定的。在近裁平面上的像素深度值为0,在远裁平面上的像素的深度值为1。场景中的每个对象都需进行绘制,通常最靠近相机的像素会被保留,这些对象阻挡了在它们后面的对象的可见性。

  深度缓冲通常还包含stencil bits – 所以深度缓冲又被叫做depth-stencil缓冲。深度格式(depth format)表示深度缓冲的构造。深度缓冲总是32 bits,但可以用不同的方式组合,类似于纹理格式。常用的深度格式是Depth32,这种格式中32 bits都用来存储深度信息。另一个常用格式是DepthFormat.Depth24Stencil8,这种格式中24 bits用于深度计算而8 bits用于模版缓冲(stencil buffer)。DepthFormat.Depth24Stencil8Single不常用,这种格式使用24 bits以浮点数计算深度缓冲。在PresentationParameters中使用AutoDepthStencilFormat属性可以设置默认深度格式。

  使用RenderState.DepthBufferEnable可以打开或关闭深度缓冲。使用 RenderState.DepthBufferFunction可以改变用于深度测试的比较函数。将ClearOptions.DepthBuffer传递给GraphicsDevice.Clear方法可以清楚深度缓冲。使用 DepthStencilBuffer类可以创建自己的深度缓冲。可见示例How To: Create a Depth Texture 学习如何创建一个自定义DepthStencilBuffer。

使用:

如何在cocos2d-x实现高效的mask(遮罩)

cocos2d-x目前无法利用opengl es2.0的shader来实现mask效果,如果按照 老外提供的renderTexture 来实现性能就太差了。
遍寻网上后在cocoachina上找到一个 深入了解OpenGL-模板测试 ,经过改造后终于可以在cocos2d-x中使用,与各位同仁分享一下。

先说下模板缓冲(stencil buffer),这在05年还算是一个比较普及的技术。cocos2d-x现在的版本是不支持stencil buffer的,但opengl es是支持的。
可以简单的动手改造一下:
创建stencil buffer。在ES1Renderer.m文件中找到resizeFromLayer方法,将if (depthFormat_){}大括号中的代码替换成以下内容:
if (depthFormat_) 
    {
        if( ! depthBuffer_ )
            glGenRenderbuffersOES(1, &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:0];

设置每帧渲染开始时清除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() != 0) {
            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,性能一样无损,还可以支持渐变,但也有其局限性,且听下回分解。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Box2DCocos2D是两个游戏开发框架。Box2D是一个用于物理模拟的开源库,可以模拟刚体的运动和碰撞等物理效果。Cocos2D是一个用于2D游戏开发的跨平台框架,提供了丰富的图形渲染和用户交互功能。\[1\] 在使用Cocos2D和Box2D进行游戏开发时,你可以利用Box2D来处理游戏中的物理效果,比如重力、碰撞和刚体运动等。Cocos2D提供了与Box2D的集成,使得开发者可以方便地在Cocos2D中使用Box2D的功能。你可以通过创建物理世界、添加刚体和设置碰撞检测等来实现游戏中的物理效果。\[2\] 如果你刚刚接触Cocos2D和Box2D,建议你先学习Cocos2D和Box2D的基础知识,然后再深入学习如何在Cocos2D中使用Box2D。你可以参考一些入门教程,比如《Cocos2D入门》和《Box2D入门》。如果你对OpenGL ES 2.0和自定义Cocos2D 2.X着色器等背景知识感到困惑,你可以查阅相关教程来获取更多的帮助。\[3\] #### 引用[.reference_title] - *1* *3* [如何使用Box2DCocos2D制作一款像Fruit Ninja一样的游戏-第1部分](https://blog.csdn.net/kaka626/article/details/9397825)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [用Box2Dcocos2d-x制作弹弓类游戏](https://blog.csdn.net/qq55008307/article/details/8090839)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值