OSG 使用整理(6):使用FBO渲染到纹理
使用FBO渲染到纹理
1.1 FBO 帧缓冲
帧缓冲包括颜色缓冲、深度缓冲和模板缓冲,默认帧缓冲是在我们创建窗口时生成和配置好的。OpenGL中使用过程类似缓存对象分为创建、绑定、读写、解绑、释放。
a . 创建FBO,绑定纹理附件
一个完整的帧缓冲需要附加至少一个缓冲、至少一个颜色附件、所有附件都是完整的、每个缓冲都应该有相同的样本数。
unsigned int framebuffer; /* brief:创建fbo命令 para[in]: n 生成的fbo名称个数 para[in]: framebuffers 缓冲对象名称 */ glGenFramebuffers(1, &framebuffer); /* brief:绑定fbo命令 para[in]: framebuffers 缓冲对象名称,0为默认 */ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); /* brief:绑定fbo命令 para[in]: attachment为GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT 或者GL_STENCIL_ATTACHMENT para[in]: textarget为0或者GL_TEXTURE_2D para[in]: texture为纹理缓冲名称 */ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
b . 使用FBO渲染到纹理
通常的步骤是将新的帧缓冲绑定为激活的帧缓冲,渲染场景;绑定默认帧缓冲;绘制一个横跨整个屏幕的四边形,将帧缓冲作为它的纹理。
// 第一处理阶段(Pass) glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 我们现在不使用模板缓冲 glEnable(GL_DEPTH_TEST); DrawScene(); // 第二处理阶段 glBindFramebuffer(GL_FRAMEBUFFER, 0); // 返回默认 glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); screenShader.use(); glBindVertexArray(quadVAO); glDisable(GL_DEPTH_TEST); glBindTexture(GL_TEXTURE_2D, textureColorbuffer); glDrawArrays(GL_TRIANGLES, 0, 6);
1.2 osg中渲染到纹理方法
渲染到纹理可以使用glReadPixels()从像素缓冲区拷贝,然后glTexImage()赋值给纹理;也可以使用glCopyTexSubImage();也可以直接渲染到FBO,再使用FBO中的纹理附件。osg::Camera类中方法setRenderTargetImplementation()可以设置渲染目标为FRAME_BUFFER_OBJECT、PIXEL_BUFFER、FRAME_BUFFER中一种对应上述方法。创建RT相机如下所示,首先设置相机绑定的FBO要清空的缓冲区类型和颜色,设置渲染到FBO和渲染次序,然后创建纹理附件,设置相机视口大小,并绑定到FBO,最后设置独立相机的投影视图矩阵。
osg::Camera* createRTTCamera( osg::Camera::BufferComponent buffer, osg::Texture* tex, bool isAbsolute ) { osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setClearColor( osg::Vec4() ); camera->setClearMask(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT ); camera->setRenderOrder( osg::Camera::PRE_RENDER ); if ( tex ) { tex->setFilter( osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR ); tex->setFilter( osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR ); camera->setViewport( 0, 0, tex->getTextureWidth(),tex->getTextureHeight() ); camera->attach( buffer, tex ); } if ( isAbsolute ) { camera->setReferenceFrame( osg::Transform::ABSOLUTE_RF ); camera->setProjectionMatrix( osg::Matrix::ortho2D( 0.0, 1.0, 0.0, 1.0) ); camera->setViewMatrix( osg::Matrix::identity() ); camera->addChild( createScreenQuad(1.0f, 1.0f) ); } return camera.release(); }
1.2.1 读取并显示深度缓冲
使用渲染到纹理技术可以得到很多炫酷效果。示例为显示飞机模型的深度缓冲到屏幕上,过程如下:
a. 渲染原始节点到纹理上
b. 创建屏幕大小四边形节点
c. 创建四边形节点的shader,使用第一步的纹理
d. 渲染四边形到屏幕上
#include <osg/Texture2D> #include <osg/Group> #include <osgDB/ReadFile> #include <osgViewer/Viewer> int main( int argc, char** argv ) { osg::ArgumentParser arguments( &argc, argv ); osg::ref_ptr<osg::Node> scene = osgDB::readNodeFiles( arguments ); if ( !scene ) scene = osgDB::readNodeFile("cessna.osg"); osg::ref_ptr<osg::Texture2D> tex2D = new osg::Texture2D; tex2D->setTextureSize( 1024, 1024 ); tex2D->setInternalFormat( GL_DEPTH_COMPONENT24 ); tex2D->setSourceFormat( GL_DEPTH_COMPONENT ); tex2D->setSourceType( GL_FLOAT ); osg::ref_ptr<osg::Camera> rttCamera = createRTTCamera(osg::Camera::DEPTH_BUFFER, tex2D.get()); rttCamera->addChild( scene.get() ); osg::ref_ptr<osg::Camera> hudCamera = createHUDCamera(0.0, 1.0, 0.0, 1.0); hudCamera->addChild(createScreenQuad(0.5f, 1.0f) ); hudCamera->getOrCreateStateSet()->setTextureAttributeAndModes( 0, tex2D.get() ); osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild( rttCamera.get() ); root->addChild( hudCamera.get() ); root->addChild( scene.get() ); osgViewer::Viewer viewer; viewer.getCamera()->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR ); viewer.setSceneData( root.get() ); return viewer.run(); }
1.3 osg中使用slave相机搭建多Pass渲染管线
osg中Viewer对象中有个默认的主相机,slave相机用于显示多窗口程序,他们继承了主相机的视图、投影矩阵、渲染上下文。采用多个slave相机,可以让用户场景图不受额外pass影响,独立做到节点渲染、状态设置,多pass的slave相机关系如下:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!