所謂「入坑」,只不過爲本身的不熟練找藉口而已。
如今學習OSG已經三週,跟着書、視頻作些簡簡單單的小demo而已,有時候真是感受本身無從下手。
不曉得的本身算不算是轉行,以前研究點雲數據處理
,有一點點opengl的基礎,雖然說工做進入某高校,項目是某沉浸式VR系統開發,目前爲止也止有我一我的在搞!
。。。。
有些扯遠了,上述純屬瞎扯淡,毫無邏輯。。。。。。node
斷斷續續的用了大半個月的osg,給個人感受就是:出了問題不知如何下手處理!好比對某圖形節點設置狀態,可是可視化出來卻沒有本身想要的效果,程序也不報錯。
之因此會有上述煩惱,可能緣由在於本身對opengl和計算機圖形學並不深刻了解,理論上的匱乏形成了實際問題沒法有效解決,這是其一;其二,或許是我的經驗不夠,思考很少,在學校習慣了被老師同窗指點,本身缺不去深刻考慮,經驗須要積累,在之後工做中要多思考,多感悟,多總結,不怕錯
壞了,又有些扯遠了,仍是回到osg吧!記性很差,就多記錄一下本身的小收穫吧!segmentfault
osg中,當設置某節點的渲染狀態時,該狀態會賦予當前節點及其子節點
,所以,若要實現多節點多狀態渲染時,必定注意節點之間的父子關係,最好一個節點設置一個本身想要的狀態,除非父節點及其子節點的渲染狀態同樣。
渲染狀態的管理經過osg::StateSet
管理,能夠將其添加到任意的節點(node、group、geode等)和DrawAble類。如要設置渲染狀態的值,須要:數組
osg::StateSet *state = obj->getOrCreatStateSet() ;
其中,obj
能夠是節點或Drawable實例,且:getOrCreatStateSet()
方法是在osg::Node中聲明的,這就意味着geode或group均可以使用。state>setMode(GL_LIGHTING,osg::StateAttribute::OFF);//關閉燈光狀態 state->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);//設置紋理 //開啓shader osg::ref_ptr<osg::Program> shaderProg = new osg::Program; shaderProg->addShader(new osg::Shader(osg::Shader::VERTEX,vertexShader)); shaderProg->addShader(new osg::Shader(osg::Shader::FRAGMENT,fragShader)); state->setAttributeAndModes(shaderProg,osg::StateAttribute::ON); //設置渲染屬性和模式 ->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);//管理深度測試 //設置渲染順序,第一個參數越小,渲染越靠前,默認第一個參數爲 -1 state->setRenderBinDetails(10, "RenderBin"); //默認渲染排序 state->setRenderBinDetails(100,"DepthSortedBin"); //由遠到近 state->setRenderBinDetails(1000,"TraversalOrderBin"); //按遍歷順序 //開啓混合透明度 state->setMode(GL_BLEND,osg::StateAttribute::ON); //設置渲染模式
等等等等緩存
顯然,geode是幾何節點,且是葉節點,geometry類管理osg中各類各樣的幾何體。
我的總結:在使用geode畫osg自帶的幾何圖形時,老是:ide
//畫個圓柱 osg::TessellationHints *hins = new osg::TessellationHints; hins->setDetailRatio(1.0f);//設置圓柱的精度爲0.1,值越小,精度越小 osg::ref_ptr<osg::Cylinder> cy = new osg::Cylinder; //圓柱 osg::ref_ptr<osg::ShapeDrawable> sd = new osg::ShapeDrawable(cy); //直接用幾何對象初始化shapedrawable實例 cy->setCenter(osg::Vec3(400.0,300,0)); cy->setHeight(0.1); cy->setRadius(150); sd->setTessellationHints(hins); geode->addDrawable(sd); //必不可少(到這裏才真正繪製) /*以上囉嗦代碼固然能夠這樣寫:*/ geode->addDrawable(new osg::ShapeDrawable(osg::Cylinder(center),Radius,Height),teseel); //畫個盒子 osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints; //設置精度 hints->setDetailRatio(0.1); osg::ref_ptr<osg::ShapeDrawable> shape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(x,y,z),長,寬,高),hints.get()); geode->addDrawable(shape);
TessellationHints(精度)參數對圓柱幾何的影響以及shapedrawable繼承關係:!函數
自定義幾何體時:學習
osg::ref_ptr<osg::Geode> geo = new osg::Geode; osg::ref_ptr<osg::Geometry> geom = new osg::Geometry(); osg::ref_ptr<osg::Vec3Array> vex = new osg::Vec3Array; osg::ref_ptr<osg::Vec4Array> color = new osg::Vec4Array; osg::ref_ptr<osg::Vec3Array> normal = new osg::Vec3Array; osg::ref_ptr<osg::LineWidth> width = new osg::LineWidth; //線寬 //設置法向量及其綁定方式 geom->setNormalArray(normal,osg::Array::Binding::BIND_OVERALL); normal->push_back(osg::Vec3(0.0,-1.0,0.0)); //設置頂點 vex->push_back(osg::Vec3(-10.5,5,-10.0)); vex->push_back(osg::Vec3(10.5,5,-10.0)); vex->push_back(osg::Vec3(10.0,5,10.0)); vex->push_back(osg::Vec3(-10.0,5,10.0)); geom->setVertexArray(vex.get()); //設置顏色 color->push_back(osg::Vec4(0.1,0.2,0.3,0.5)); color->push_back(osg::Vec4(1.1,0.9,0.3,0.50)); color->push_back(osg::Vec4(0.2,0.5,0.3,0.50)); color->push_back(osg::Vec4(0.4,0.2,0.7,0.50)); geom->setColorArray(color); geom->setColorBinding(osg::Geometry::AttributeBinding::BIND_PER_VERTEX); //設置紋理綁定方式 osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints; hints->setDetailRatio(0.1); //設置透明度 geom->getOrCreateStateSet()->setMode(GL_BLEND,osg::StateAttribute::ON); /*osg::DrawArrays至關於對opengl中glDrawarray的封裝*/ geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::Mode::LINE_LOOP,0,4)); //設置頂點的關聯方式(此處,以線段的方式鏈接) //設置線寬 width->setWidth(20.0); geom->getOrCreateStateSet()->setAttributeAndModes(width); geo->addDrawable(geom.get());
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::Mode::LINE_LOOP,0,4));
的基本圖元及drawable繼承方式:測試
固然,上一篇入門文章viewer::run()多多少少也和camera有關。如今算是進一步吧。
先看看camera的繼承關係圖
spa
很明顯,camera繼承自node、group、transform,也就是說他們具備的屬性,camera也具備。設計
就像上篇文章所述,osgviewer->run()會自動設置一個場景漫遊器,該漫遊器包含了透視投影矩陣、視口大小、屏幕寬高比以及遠近裁剪面、攝像機位置等等參數,若是想要修改遠近裁剪面應該首先關閉osg的自動判斷遠近裁剪面的函數:
viewer->getCamera()->setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR); viewer->getCamera()->setProjectionMatrixAsPerspective(fovy,aspectRatio,zNear,zFarSurface);
osgUtil::CullVisitor
是osg的場景揀選訪問器。
osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface(); if (!wsi) return ; unsigned int height,width; wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0),width,height); //獲取屏幕的長寬 //設置圖形環境特性 osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits(); traits->x = 0; traits->y = 0; traits->width = width; traits->height = height; traits->windowDecoration = false; //窗口修飾 關 traits->doubleBuffer = true; //是否支持雙緩存 traits->sharedContext = false; osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits); if (!gc.valid()) { return ; } gc->setClearMask(GL_COLOR_BUFFER_BIT); gc->setClearColor(osg::Vec4(0.5,0.5,0.5,1.0)); //設置全局上下文的背景色 osg::ref_ptr<osg::Camera> master = new osg::Camera; master->setGraphicsContext(gc); viewer->addSlave(master); //將相機添加到場景中。
在HUD和RTT中,建立相機是很是重要的,HUD的相機要最後渲染,防止被覆蓋
HUD相機:
osg::Camera *CreatTextHUD() { osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setViewMatrix(osg::Matrix::identity()); //設置視圖矩陣爲單位矩陣 camera->setAllowEventFocus(false); //不響應其餘鼠標事件 camera->setRenderOrder(osg::Camera::POST_RENDER);//最後渲染 camera->setClearMask(GL_DEPTH_BUFFER_BIT); camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);//設置參考幀 爲絕對座標系 camera->setProjectionMatrixAsOrtho2D(0,1024,0,768); //設置二維正交投影 osg::ref_ptr<osg::Geode> geode = new osg::Geode; geode->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);//關閉燈光狀態 osg::ref_ptr<osgText::Text> text = new osgText::Text; geode->addDrawable(text); text->setPosition(osg::Vec3(0,0,0)); text->setFont("simsun.ttc"); //設置爲宋體 text->setText(L"宋體 測試"); //必定不要忘記加「L」字符 text->setCharacterSize(50); camera->addChild(geode); return camera.release(); }
RTT相機
void CreatRTT(osgViewer::Viewer *viewer) { osg::ref_ptr<osg::Group> group = new osg::Group; osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("nathan.osg"); group->addChild(node); //設置圖形上下文 osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; traits->x = 0; traits->y = 0; traits->width = 800; traits->height = 600; traits->sharedContext = false; traits->doubleBuffer = true; traits->windowDecoration = false; osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits); //建立主相機 osg::ref_ptr<osg::Camera> master = new osg::Camera; master->setGraphicsContext(gc); master->setViewport(0,0,800,600); viewer->addSlave(master); //建立rtt相機 osg::ref_ptr<osg::Camera> rttCamera = new osg::Camera; rttCamera->setRenderOrder(osg::Camera::PRE_RENDER); rttCamera->setGraphicsContext(gc); rttCamera->setViewport(0,0,800,600); rttCamera->addChild(node); //添加相機並設置瞄準鏡的放大倍數爲8倍,最後false表示:該添加入的相機不接受主窗口任何內容。 viewer->addSlave(rttCamera,osg::Matrix::scale(8,8,8),osg::Matrix::identity(),false); osg::Texture2D *t2d = new osg::Texture2D; t2d->setInternalFormat(GL_RGBA); rttCamera->attach(osg::Camera::COLOR_BUFFER,t2d); group->addChild(CreatHUD(t2d)); viewer->setSceneData(group); return ; }
上邊的函數實際上是建立了一個瞄準鏡的效果:
自我感受(或許並不對,僅限於目前認知水平)
:osg添加多相機主要功能是爲了多窗口多視圖顯示。一個相機可以渲染多個視圖,一個場景可以添加多個相機,多個相機可以實現從不一樣角度、方位、視角觀察同時觀察同一個模型。
viewer->setCameraManipulator(osgGA::CameraMaipulator *)
,和viewer->addEventHandler(osgGA::EventHandler *)
,前者的函數參數是osgGA::CameraMaipulator *
類型,後者參數爲osgGA::EventHandler *
類型,且osgGA::CameraMaipulator *
是繼承自osgGA::EventHandler *
的。
對比:
設置漫遊的本質就是修改主相機的各類參數矩陣,並將修改後的參數返回場景中的主相機
(影響的最頂層的相機節點).其實本質上)
:從類的繼承關係來看,漫遊器是從事件處理類中繼承而來,若是事件處理函數我的寫得足夠好、足夠豐富,應該可以替代漫遊器的,這也是爲何二者在不少時候添加自定義類時程序並不報錯,但就是達不到預想效果的緣由。矩陣的自動返回操做
,從而控制相機,其矩陣自動返回的主要函數是:virtual void setByMatrix(const osg::Matrixd& matrix) = 0; //設置相機的位置姿態矩陣 virtual void setByInverseMatrix(const osg::Matrixd& matrix) = 0; //設置相機的視圖矩陣 virtual osg::Matrixd getMatrix() const = 0; //獲取相機的姿態矩陣 virtual osg::Matrixd getInverseMatrix() const = 0;
這也就是爲何自定義的漫遊器必須重載這四個函數的緣由所在。(事件處理不須要重載這幾個函數)
關係:
若是總結爲一句話,應該是:CameraManipulator是EventHanler的子類,EventHandler自己也能夠實現漫遊功能,只不過osg開發者爲了更加豐富便捷的控制事件與漫遊,從而單獨設計了一個漫遊操做器,以便使用者可以更加輕鬆方便的控制本身的場景。
清除camera中的深度緩存:camera->setclearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH)
;
注:以上內容只是本身在比較皮毛的層面的記錄,並無過多的深刻源碼解析,內容或許有誤,懇請指正留言,不勝感激!
另:有作點雲處理研究的朋友也可多多交流。