osg渲染到纹理技术(一)
render-to-textures(RTT)允許
開發者根據場景的一部分圖像創建成一張紋理圖,烘焙到場景中的某一物體上,這種技術用于創建更好看的特殊的表現形式,或者被保存用于以后的延遲著色,和多通道渲染,或者更高級的渲染特效.
OSG中動態的實現渲染到紋理.需要以下三個步驟:
1.創建一張紋理用于下一步渲染的結果.
2.渲染到剛剛創建的紋理
3.得到這個渲染的紋理的結果,用于你想使用的地方
步驟詳解:我們首先需要創建一張空的紋理圖,osg::Texture對象中有setTextureSize()函數可以修改這張2D紋理的大小.以及添加一個深度參數用于3D紋理.其中最主要的是如何得到場景圖的一部分,這需要用到osg::Camera類的attach()方法,它需要一個紋理對象作為參數,以及枚舉類型作為參數(這個枚舉類型用于指定得到幀緩存中的那一部分,作為RTT的數據來源.)
//除了COLOR_BUFFER外還有DEPTH_BUFFER , STENCIL_BUFFER , and COLOR_BUFFER0 to COLOR_BUFFER15 //有多少種渲染目標的輸出類型,取決于你自己的顯卡 camera->attach( osg::Camera::COLOR_BUFFER, texture.get() );//把frame buffer中的color buffer作為渲染數據下一步就是設定合適的視圖和投影矩陣以及一個合適剛剛設定的texture的大小的viewport在所使用的相機對象中,然后就可以把得到的texture設定為node或者drawables的屬性.這樣這個texture的結果將會隨著相機的渲染結果每一幀變化.隨著視圖矩陣和投影矩陣的變化而變化.
這里需要注意的是:主攝像機不適合用于綁定一個texutre用于RTT.因為這將沒有任何輸出到屏幕上,會出現黑屏,但是如果你在進行離屏渲染或者不在乎任何顯示.
接下來一個問題是怎么把幀緩存的數據渲染到texture上.OSG提供了下面幾種方法.
1.使用glReadPiexels()方法直接讀取幀緩存中的數據(放回的是像素數據),再使用glTexImage*()方法(glTexImage2D的數據來自于客戶端內存),把像素數據保存為紋理.這種方式最簡單易行,但是它需要不斷的進行數據的拷貝到texture對象上,所以效率非常慢.
2.使用glCopyTexSubimage*()方法,它定義了一個2D紋理圖像,或者立方體映射圖像,它的像素數據來源于幀緩存,所以它的效率相對于glTexImage*()會提升很多.然而我們還有可優化的空間.
–---不需要進行數據拷貝,直接把scene的數據渲染到目標(不經過幀緩存)
3.pixel buffer(pbuffer)--像素緩沖區擴展,它可以創建一個帶有像素格式的不可見的緩沖區,就像一個窗口一樣.它應該在使用后銷毀,就像渲染窗口那樣做.
4.frame buffer object(FBO)--幀緩沖對象,這種方式在某些情況下比pbuffer要好(數據的存儲空間消耗少).
FBO簡介:
Opengl默認把framebuffer作為渲染的目的地,它是由窗口系統創建并管理的,FBO是一個二維的數據集合,包括color buffers\ depth buffer以及stencil buffer.
在Opengl擴展中,GL_ARB_framebuffer_object提供了額外的非顯示的FBO作為接口,FBO可以理解為應用程序可創建的framebuffer,用于區別默認窗口提供的frambuffer.通過FBO Opengl應用可以重定向渲染輸出,讓它輸出到FBO而不是窗口系統提供的framebuffer.
與窗口系統提供的幀緩沖區類似,它包含了一系列渲染目的地的集合:包括顏色,深度和模板緩沖區.FBO中的這些邏輯緩沖區稱為可附著的frame buffer.主要有兩種類型的可附著緩沖區(texture和render buffer),如果texutre被附著到FBO,則執行”渲染到紋理”.如果renderbuffer被附著到FBO,則opengl會執行”離屏渲染”.(renderbuffer是在GL_ARB_framebuffer_object擴展中定義的一種新類型的存儲對象。它在渲染過程中用作單個2D圖像的渲染目的地。)
下圖顯示了FBO,紋理和renderbuffer之間的連接。多個紋理對象或renderbuffer對象可以通過附著點附加到FBO上。
FBO中,有多個顏色附加點(GL_COLOR_ATTACHMENT0,...,GL_COLOR_ATTACHMENTn),
一個深度附加點(GL_DEPTH_ATTACHMENT)
一個模板附加點(GL_STENCIL_ATTACHMENT)。
顏色附著點的數量取決于實現,但每個FBO必須至少具有一個顏色附加點。您可以使用GL_MAX_COLOR_ATTACHMENTS查詢最大數量的顏色附加點,這些數據由顯卡支持。
FBO具有多個顏色附加點的原因是允許在同一時間將顏色緩沖區渲染到多個目的地。這個“多個渲染目標”(MRT)可以由GL_ARB_draw_buffers擴展完成。請注意,FBO本身不存放數據,它只有多個附著點。這有點像數據結構中的指針,它只存放指針,而不存放數據。
FBO提供了一種高效的切換機制;從FBO中分離先前的幀緩沖區,并將一個新的可附著的幀緩沖圖像附加到FBO中。切換可附著的幀緩沖圖像比在FBO之間切換要快得多。 FBO提供glFramebufferTexture2D()來切換2D紋理對象,并將glFramebufferRenderbuffer()切換到renderbuffer對象。
OSG中使用FBO的方式是:
camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER );渲染到紋理實例:
作者:kjwang 鏈接:https://zhuanlan.zhihu.com/p/38841667 來源:知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。#include <osg/Camera> #include <osg/Texture2D> #include <osgDB/ReadFile> #include <osgGA/TrackballManipulator> #include <osgViewer/Viewer>class FindTextureVisitor : public osg::NodeVisitor { public:FindTextureVisitor( osg::Texture* tex ) : _texture(tex){setTraversalMode( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN );}virtual void apply( osg::Node& node ){replaceTexture( node.getStateSet() );traverse( node );}virtual void apply( osg::Geode& geode ){replaceTexture( geode.getStateSet() );for ( unsigned int i=0; i<geode.getNumDrawables(); ++i ){replaceTexture( geode.getDrawable(i)->getStateSet() );}traverse( geode );}void replaceTexture( osg::StateSet* stateset ){if ( stateset ){osg::Texture* oldTexture = dynamic_cast<osg::Texture*>(stateset->getTextureAttribute(0, osg::StateAttribute::TEXTURE) );if ( oldTexture ) stateset->setTextureAttribute( 0, _texture.get() );}}protected:osg::ref_ptr<osg::Texture> _texture; };int main( int argc, char** argv ) {// setMinimumNumAlphaBits(1);osg::ref_ptr<osg::Node> model = osgDB::readNodeFile( "/home/aqrose23/Downloads/aq_depends/OpenSceneGraph/data/OpenSceneGraph-Data-master/lz.osg" );osg::ref_ptr<osg::Node> sub_model = osgDB::readNodeFile( "/home/aqrose23/Downloads/aq_depends/OpenSceneGraph/data/OpenSceneGraph-Data-master/glider.osg" );int tex_width = 1024, tex_height = 1024;osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;texture->setTextureSize( tex_width, tex_height );texture->setInternalFormat( GL_RGBA );texture->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR );texture->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR );FindTextureVisitor ftv( texture.get() );if ( model.valid() ) model->accept( ftv );osg::ref_ptr<osg::Camera> camera = new osg::Camera;camera->setViewport( 0, 0, tex_width, tex_height );camera->setClearColor( osg::Vec4(1.0f, 1.0f, 1.0f, 0.0f) );camera->setClearMask( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );camera->setRenderOrder( osg::Camera::PRE_RENDER );camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );camera->attach( osg::Camera::COLOR_BUFFER, texture.get() );camera->setReferenceFrame( osg::Camera::ABSOLUTE_RF );camera->addChild( sub_model.get() );osg::ref_ptr<osg::Group> root = new osg::Group;root->addChild( model.get() );root->addChild( camera.get() );osgViewer::Viewer viewer;viewer.setSceneData( root.get() );viewer.setCameraManipulator( new osgGA::TrackballManipulator );float delta = 0.1f, bias = 0.0f;osg::Vec3 eye(0.0f,-5.0f, 5.0f);while ( !viewer.done() ){if ( bias<-1.0f ) delta = 0.1f;else if ( bias>1.0f ) delta = -0.1f;bias += delta;camera->setViewMatrixAsLookAt( eye, osg::Vec3(), osg::Vec3(bias, 1.0f, 1.0f) );viewer.frame();}return 0; }本文轉自:https://www.zhihu.com/column/c_187589347
總結
以上是生活随笔為你收集整理的osg渲染到纹理技术(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: osg-3D世界到屏幕
- 下一篇: 小米终止对这款四款机型的系统更新 看看有