Coco2d-x Framebuffer笔记

来源:互联网 发布:qq三国全服第一js鱼总 编辑:程序博客网 时间:2024/06/05 15:54

OpenGL Framebuffer

OpenGL中Framebuffer的特性:

1.Framebuffer由什么组成:color buffer,depth buffer,stencil buffer

2.The default framebuffer is created and configured when you create your window (GLFW does this for us). 

3.For a framebuffer to be complete the following requirements have to be satisfied:

  • We have to attach at least one buffer (color, depth or stencil buffer).
  • There should be at least one color attachment.
  • All attachments should be complete as well (reserved memory).
  • Each buffer should have the same number of samples.

4.两种attachment:texture attachment(可读写,一般用作color buffer)和renderbuffer attachment(可写,一般用作depth stencil buffer)

5.一般使用方法:用texture作为color attachment ,depth attachment 和stencil attachment 共同使用一个buffer(GL_DEPTH24_STENCIL8)作为一个DepthStencil attachment(GL_DEPTH_STENCIL_ATTACHMENT),并且使用renderbuffer object作为attachment。

OpenGL使用Framebuffer的流程:

1.Gen

GLuint fbo;glGenFramebuffers(1, &fbo);

2.Bind

glBindFramebuffer(GL_FRAMEBUFFER, fbo); 

3.Attachment

(1)Texture Color Attachment

GLuint texture;

glGenTextures(1, &texture);glBindTexture(GL_TEXTURE_2D, texture);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB,GL_UNSIGNED_BYTE, NULL);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,0); 

(2)Texture DepthStencil Attachment

GLuint texture;glGenTextures(1, &texture);glBindTexture(GL_TEXTURE_2D, texture);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8,800, 600, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texture,0); 

(3)Renderbuffer Color Attachments

GLuint rbo;glGenRenderbuffers(1, &rbo);glBindRenderbuffer(GL_RENDERBUFFER, rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 800, 600);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); 

(4)Renderbuffer DepthStencil  Attachments

GLuint rbo;glGenRenderbuffers(1, &rbo);glBindRenderbuffer(GL_RENDERBUFFER, rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 800, 600);glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);

4.check complete

if(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)// log info output

5.Delete

glDeleteFramebuffers(1, &fbo); 

Coco2d-x Framebuffer

1.使用framebuffer需要的所有参数:

1)Framebuffer size:width,height(Pixels Unit)

2)Attachment:color buffer(texture or renderbuffer),depth stencil buffer(renderbuffer)

3)Clear value for glClear*(type value):vec3 clearcolor, GLfloat cleardepth, int8 clearstencil

2.删减版framebuffer.h

class CC_DLL FrameBuffer : public Ref{public:    static FrameBuffer* create(uint8_t fid, unsigned int width, unsigned int height);        bool init(uint8_t fid, unsigned int width, unsigned int height);public:    //call glclear to clear frame buffer object : color, depth, stencil    void clearFBO();    void applyFBO();    void restoreFBO();    void setClearColor(const Color4F& color) { _clearColor = color;}    void setClearDepth(float depth) { _clearDepth = depth; }    void setClearStencil(int8_t stencil) { _clearStencil = stencil; }    // set _rt    void attachRenderTarget(RenderTargetBase* rt);// set _rtDepthStencil    void attachDepthStencilTarget(RenderTargetDepthStencil* rt);        bool isDefaultFBO() const { return _isDefault; }    unsigned int getWidth() const { return _width; }    unsigned int getHeight() const { return _height; }CC_CONSTRUCTOR_ACCESS:    FrameBuffer();    virtual ~FrameBuffer();// init _defaultFBO with GLView    bool initWithGLView(GLView* view);private:    //openGL content for FrameBuffer    GLuint _fbo;    GLuint _previousFBO;    //dirty flag for fbo binding, if true need apply new attachment    bool _fboBindingDirty;    //    uint8_t _fid;    //    Color4F _clearColor;    float   _clearDepth;    int8_t  _clearStencil;    int _width;    int _height;    RenderTargetBase* _rt;    RenderTargetDepthStencil* _rtDepthStencil;    bool _isDefault;public:    static FrameBuffer* getOrCreateDefaultFBO(GLView* glView);    static void applyDefaultFBO();    static void clearAllFBOs();private:    //static GLuint _defaultFBO;    static FrameBuffer* _defaultFBO;    static std::set<FrameBuffer*> _frameBuffers;};

3.FBO相关操作

1)Create FrameBuffer

FrameBuffer* FrameBuffer::create(uint8_t fid, unsigned int width, unsigned int height){    auto result = new (std::nothrow) FrameBuffer();    if(result && result->init(fid, width, height))    {        result->autorelease();        return result;    }    else    {        CC_SAFE_DELETE(result);        return nullptr;    }}FrameBuffer::FrameBuffer(): _clearColor(Color4F(0, 0, 0, 1)), _clearDepth(1.0), _clearStencil(0), _fbo(0), _previousFBO(0), _rt(nullptr), _rtDepthStencil(nullptr), _fboBindingDirty(true), _isDefault(false){    _frameBuffers.insert(this);}bool FrameBuffer::init(uint8_t fid, unsigned int width, unsigned int height){    _fid = fid;    _width = width;    _height = height;        GLint oldfbo;    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldfbo);    glGenFramebuffers(1, &_fbo);    glBindFramebuffer(GL_FRAMEBUFFER, _fbo);    glBindFramebuffer(GL_FRAMEBUFFER, oldfbo);        return true;}


new FrameBuffer 和init()都没有create RenderTarget,仅仅gen了一个FBO id,所以需要根据使用需求自己生成RenderTarget,并attach到FBO

2)Create RenderTarget

RenderTarget包括:RenderTargetBase(Render Target基类),RenderTarget(colorbuffer attachment为Texture2D的RenderTarget),RenderTargetRenderBuffer(colorbuffer attachment为RenderBuffer的RenderTarget),RenderTargetDepthStencil(DepthStencil attachment为RenderBuffer的RenderTarget),FrameBuffer。

//--------------------------------------------------------------------//// RenderTarget////--------------------------------------------------------------------RenderTarget* RenderTarget::create(unsigned int width, unsigned int height, Texture2D::PixelFormat format/* = Texture2D::PixelFormat::RGBA8888*/){    auto result = new (std::nothrow) RenderTarget();    if(result && result->init(width, height,format))    {        result->autorelease();        return result;    }    else    {        CC_SAFE_DELETE(result);        return nullptr;    }}bool RenderTarget::init(unsigned int width, unsigned int height, Texture2D::PixelFormat format){    if(!RenderTargetBase::init(width, height))    {        return false;    }        _texture = new (std::nothrow) Texture2D();    if(nullptr == _texture) return false;    //TODO: FIX me, get the correct bit depth for pixelformat    auto dataLen = width * height * 4;    auto data = malloc(dataLen);    if( nullptr == data) return false;        memset(data, 0, dataLen);    if(_texture->initWithData(data, dataLen, format, width, height, Size(width, height)))    {        _texture->autorelease();        CC_SAFE_RETAIN(_texture);        free(data);    }    else    {        CC_SAFE_DELETE(_texture);        free(data);        return false;    }    return true;}//--------------------------------------------------------------------//// RenderTarget////--------------------------------------------------------------------RenderTargetDepthStencil* RenderTargetDepthStencil::create(unsigned int width, unsigned int height){    auto result = new (std::nothrow) RenderTargetDepthStencil();        if(result && result->init(width, height))    {        result->autorelease();        return result;    }    else    {        CC_SAFE_DELETE(result);        return nullptr;    }}bool RenderTargetDepthStencil::init(unsigned int width, unsigned int height){    if(!RenderTargetBase::init(width, height)) return false;    GLint oldRenderBuffer(0);    glGetIntegerv(GL_RENDERBUFFER_BINDING, &oldRenderBuffer);        //generate depthStencil    glGenRenderbuffers(1, &_depthStencilBuffer);    glBindRenderbuffer(GL_RENDERBUFFER, _depthStencilBuffer);    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);    glBindRenderbuffer(GL_RENDERBUFFER, oldRenderBuffer);        return true;}//--------------------------------------------------------------------//// RenderTargetRenderBuffer////--------------------------------------------------------------------bool RenderTargetRenderBuffer::init(unsigned int width, unsigned int height){    if(!RenderTargetBase::init(width, height)) return false;    GLint oldRenderBuffer(0);    glGetIntegerv(GL_RENDERBUFFER_BINDING, &oldRenderBuffer);        //generate depthStencil    glGenRenderbuffers(1, &_colorBuffer);    glBindRenderbuffer(GL_RENDERBUFFER, _colorBuffer);    //todo: this could have a param    glRenderbufferStorage(GL_RENDERBUFFER, _format, width, height);    glBindRenderbuffer(GL_RENDERBUFFER, oldRenderBuffer);        return true;}RenderTargetRenderBuffer* RenderTargetRenderBuffer::create(unsigned int width, unsigned int height){    auto result = new (std::nothrow) RenderTargetRenderBuffer();        if(result && result->init(width, height))    {        result->autorelease();        return result;    }    else    {        CC_SAFE_DELETE(result);        return nullptr;    }}


3)attach RenderTarget

Color Attachment

void FrameBuffer::attachRenderTarget(RenderTargetBase* rt){    if(isDefaultFBO())    {        CCLOG("Can not apply render target to default FBO");        return;    }    CC_ASSERT(rt);    if(rt->getWidth() != _width || rt->getHeight() != _height)    {        CCLOG("Error, attach a render target with different size, Skip.");        return;    }    CC_SAFE_RETAIN(rt);    CC_SAFE_RELEASE(_rt);    _rt = rt;    _fboBindingDirty = true;//因为更新_rt,下次applyFBO()需要重新attach color attachment}


DepthStencil Attachment

void FrameBuffer::attachDepthStencilTarget(RenderTargetDepthStencil* rt){    if(isDefaultFBO())    {        CCLOG("Can not apply depth stencil target to default FBO");        return;    }        if(nullptr != rt && (rt->getWidth() != _width || rt->getHeight() != _height))    {        CCLOG("Error, attach a render target Depth stencil with different size, Skip.");        return;    }    CC_SAFE_RETAIN(rt);    CC_SAFE_RELEASE(_rtDepthStencil);    _rtDepthStencil = rt;    _fboBindingDirty = true;//因为更新了_rtDepthStencil,下次applyFBO()需要重新attach depth stencil attachment}


4) applyFBO

void FrameBuffer::applyFBO(){    CHECK_GL_ERROR_DEBUG();    glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_previousFBO);    glBindFramebuffer(GL_FRAMEBUFFER, _fbo);//    CCASSERT(_fbo==0 || _fbo != _previousFBO, "calling applyFBO without restoring the previous one");    CHECK_GL_ERROR_DEBUG();    if(_fboBindingDirty && !isDefaultFBO())    {        CHECK_GL_ERROR_DEBUG();        if(RenderTargetBase::Type::Texture2D == _rt->getType())            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _rt->getTexture()->getName(), 0);        else            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _rt->getBuffer());        CHECK_GL_ERROR_DEBUG();        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, nullptr == _rtDepthStencil ? 0 : _rtDepthStencil->getBuffer());        CHECK_GL_ERROR_DEBUG();        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, nullptr == _rtDepthStencil ? 0 : _rtDepthStencil->getBuffer());        CHECK_GL_ERROR_DEBUG();        CCLOG("FBO is %d _fbo %d color, %d ds", _fbo, RenderTargetBase::Type::Texture2D == _rt->getType() ? _rt->getTexture()->getName() : _rt->getBuffer(), nullptr == _rtDepthStencil ? 0 : _rtDepthStencil->getBuffer());        _fboBindingDirty = false;    }    if(GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus(GL_FRAMEBUFFER))    {        CCLOG("FrameBuffer Status Error %d", (int)glCheckFramebufferStatus(GL_FRAMEBUFFER));    }    CHECK_GL_ERROR_DEBUG();}


在attach时没有进行_rt断言,所以需要注意记得attach

5)clearAllFBO

void FrameBuffer::clearAllFBOs(){    for (auto fbo : _frameBuffers)    {        fbo->clearFBO();    }}void FrameBuffer::clearFBO(){    applyFBO();    glClearColor(_clearColor.r, _clearColor.g, _clearColor.b, _clearColor.a);    glClearDepth(_clearDepth);    glClearStencil(_clearStencil);    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);    restoreFBO();}void FrameBuffer::restoreFBO(){    glBindFramebuffer(GL_FRAMEBUFFER, _previousFBO);}


4.Director中FBO使用流程

 1)mainloop

void DisplayLinkDirector::mainLoop(){    if (_purgeDirectorInNextLoop)//end()函数会把_purgeDirectorInNextLoop设置为true    {        _purgeDirectorInNextLoop = false;//把_purgeDirectorInNextLoop恢复为默认值        purgeDirector();//清除Director    }    else if (_restartDirectorInNextLoop)    {        _restartDirectorInNextLoop = false;        restartDirector();    }    else if (! _invalid)    {        drawScene();             // release the objects        PoolManager::getInstance()->getCurrentPool()->clear();    }}



2)drawScene

void Director::drawScene(){    // calculate "global" dt    calculateDeltaTime();        if (_openGLView)    {        _openGLView->pollEvents();    }    //tick before glClear: issue #533    if (! _paused)    {        _eventDispatcher->dispatchEvent(_eventBeforeUpdate);_scheduler->update(_deltaTime);        _eventDispatcher->dispatchEvent(_eventAfterUpdate);    }    _renderer->clear();    experimental::FrameBuffer::clearAllFBOs();    /* to avoid flickr, nextScene MUST be here: after tick and before draw.     * FIXME: Which bug is this one. It seems that it can't be reproduced with v0.9     */    if (_nextScene)    {        setNextScene();    }    pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);        if (_runningScene)    {#if (CC_USE_PHYSICS || (CC_USE_3D_PHYSICS && CC_ENABLE_BULLET_INTEGRATION) || CC_USE_NAVMESH)        _runningScene->stepPhysicsAndNavigation(_deltaTime);#endif        //clear draw stats        _renderer->clearDrawStats();                //render the scene        _openGLView->renderScene(_runningScene, _renderer);                _eventDispatcher->dispatchEvent(_eventAfterVisit);    }    // draw the notifications node    if (_notificationNode)    {        _notificationNode->visit(_renderer, Mat4::IDENTITY, 0);    }    if (_displayStats)    {        showStats();    }    _renderer->render();    _eventDispatcher->dispatchEvent(_eventAfterDraw);    popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);    _totalFrames++;    // swap buffers    if (_openGLView)    {        _openGLView->swapBuffers();    }    if (_displayStats)    {        calculateMPF();    }}



3)clearAllFBO

void FrameBuffer::clearAllFBOs(){    for (auto fbo : _frameBuffers)    {        fbo->clearFBO();    }}void FrameBuffer::clearFBO(){    applyFBO();    glClearColor(_clearColor.r, _clearColor.g, _clearColor.b, _clearColor.a);    glClearDepth(_clearDepth);    glClearStencil(_clearStencil);    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);    restoreFBO();}void FrameBuffer::restoreFBO(){    glBindFramebuffer(GL_FRAMEBUFFER, _previousFBO);}

4)renderScene

void GLView::renderScene(Scene* scene, Renderer* renderer){    CCASSERT(scene, "Invalid Scene");    CCASSERT(renderer, "Invalid Renderer");    if (_vrImpl)    {        _vrImpl->render(scene, renderer);    }    else    {        scene->render(renderer, Mat4::IDENTITY, nullptr);    }}



5)scene->render

void Scene::render(Renderer* renderer, const Mat4& eyeTransform, const Mat4* eyeProjection){    auto director = Director::getInstance();    Camera* defaultCamera = nullptr;    const auto& transform = getNodeToParentTransform();    for (const auto& camera : getCameras())    {        if (!camera->isVisible())            continue;        Camera::_visitingCamera = camera;        if (Camera::_visitingCamera->getCameraFlag() == CameraFlag::DEFAULT)        {            defaultCamera = Camera::_visitingCamera;        }        // There are two ways to modify the "default camera" with the eye Transform:        // a) modify the "nodeToParentTransform" matrix        // b) modify the "additional transform" matrix        // both alternatives are correct, if the user manually modifies the camera with a camera->setPosition()        // then the "nodeToParent transform" will be lost.        // And it is important that the change is "permanent", because the matrix might be used for calculate        // culling and other stuff.        if (eyeProjection)            camera->setAdditionalProjection(*eyeProjection * camera->getProjectionMatrix().getInversed());        camera->setAdditionalTransform(eyeTransform.getInversed());        director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);        director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, Camera::_visitingCamera->getViewProjectionMatrix());// apply viewport        camera->apply();        //clear background with max depth        camera->clearBackground();        //visit the scene        visit(renderer, transform, 0);#if CC_USE_NAVMESH        if (_navMesh && _navMeshDebugCamera == camera)        {            _navMesh->debugDraw(renderer);        }#endif        renderer->render();        camera->restore();        director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);        // we shouldn't restore the transform matrix since it could be used        // from "update" or other parts of the game to calculate culling or something else.//        camera->setNodeToParentTransform(eyeCopy);    }#if CC_USE_3D_PHYSICS && CC_ENABLE_BULLET_INTEGRATION    if (_physics3DWorld && _physics3DWorld->isDebugDrawEnabled())    {        director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);        director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, _physics3dDebugCamera != nullptr ? _physics3dDebugCamera->getViewProjectionMatrix() : defaultCamera->getViewProjectionMatrix());        _physics3DWorld->debugDraw(renderer);        renderer->render();        director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);    }#endif    Camera::_visitingCamera = nullptr;//    experimental::FrameBuffer::applyDefaultFBO();}


6)camera->apply

void Camera::apply(){    applyFrameBufferObject();    applyViewport();}void Camera::applyFrameBufferObject(){    if(nullptr == _fbo)//如果没有设置_fbo说明使用的是默认FBO,不需要bindFBO    {        // inherit from context if it doesn't have a FBO        // don't call apply the default one//        experimental::FrameBuffer::applyDefaultFBO();    }    else    {        _fbo->applyFBO();    }}void Camera::applyViewport(){    glGetIntegerv(GL_VIEWPORT, _oldViewport);    if(nullptr == _fbo)    {        glViewport(getDefaultViewport()._left, getDefaultViewport()._bottom, getDefaultViewport()._width, getDefaultViewport()._height);    }    else    {        glViewport(_viewport._left * _fbo->getWidth(), _viewport._bottom * _fbo->getHeight(),                   _viewport._width * _fbo->getWidth(), _viewport._height * _fbo->getHeight());    }}


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 白色衣服被红色衣服染了怎么办 手机微信里面不能拍手功怎么办 肇事逃逸轻伤且对方不私了怎么办 数学差怎么办脑子不好啊数学学不老 手机号丢失微信密码丢失怎么办找回 悦借钱输入五次密码被锁怎么办 生源地助学贷款密码忘了怎么办 生源地助学贷款登录密码忘了怎么办 助学贷款支付宝密码忘了怎么办 微信密码忘记了手机号也换了怎么办 换手机号了微信密码忘记了怎么办 qq密码忘记了手机号也换了怎么办 一年只能修改一次昵称我能怎么办 华为手机的账号和密码丢失怎么办 华为手机的账号和密码丢失了怎么办 手机号被别人注册了微博怎么办 微博账号一天内多次解冻怎么办 露娜注册时邮箱填错了怎么办 苹果4s手机显示已停用怎么办 新买的微博小号太多内容了怎么办 向海关申报价格低于实际价格怎么办 百度云下载内容包含违规信息怎么办 跨境汇款错了不能退款怎么办 公司欠钱没有还被起诉了。怎么办 战网的姓名不是身份证名字怎么办 手机号码被别人注册了微信怎么办 手机号码被别人注册过微信怎么办 手机号码换了微信密码忘了怎么办 手机号码停了微信密码忘了怎么办 微信好友发的视频删了怎么办 随机生成的微信号搜索不到怎么办 支付宝账户登录密码忘记了怎么办 淘宝支付宝登录密码忘记了怎么办 生源地贷款支付宝账号忘了怎么办 手机号丢了微信找不到密码怎么办 支付宝知道名字不知道姓怎么办 东西丢了从监控里找到怎么办 两人合影其中一人去世怎么办 税务登记证注销但是发票丢失怎么办 发票登报挂失后到国税还要怎么办 广州个体执照没办国税地税怎么办