打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
如何在cocos2d-x实现高效的mask

http://www.cocoachina.com/bbs/read.php?tid=103708

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,性能一样无损,还可以支持渐变,但也有其局限性,且听下回分解。     
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Cocos2d: Stencil buffer is not enabled.
CSharpGL初步封装Texture和Framebuffer
OpenGL ES Emulator横向比较
多重采样(MultiSample)下的FBO反锯齿
OpenGL 的渲染流水线
SurfaceTexture in Android
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服