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()); }}
- Coco2d-x Framebuffer笔记
- coco2d-x学习笔记
- coco2d-x 学习笔记2
- Coco2d-x 内存管理笔记
- cocos2d-x-3.1 常用宏 (coco2d-x 学习笔记五)
- cocos2d-x-3.1 NotificationCenter (coco2d-x 学习笔记八)
- coco2d笔记
- coco2d 笔记
- coco2d-x手记
- coco2d-x使用备忘录
- coco2d-x 动作类
- Coco2d-x linux编译
- coco2d-x xuexi
- coco2d-x 纹理研究
- coco2d-x touch事件
- 安装coco2d-x
- coco2d-x内存优化
- coco2d-x坐标转换
- SFTP服务搭建
- 进程地址空间,堆和栈关系
- mob短线简单验证,具体逻辑在添加
- ':app:mockableAndroidJar' clean 出错
- 新版本Butterknife的使用
- Coco2d-x Framebuffer笔记
- Android vold进程二 VolumeManager和CommandListener简介
- TTEFS-基于LayerFsd的文档透明加密SDK
- 关于js弹出框的设置? WinOpen();
- 1918 简单计算器
- PHP初学者的资源整理
- win10不兼容 软件 ietest
- 对象传递和引用
- 颜色常识学习记录