osg實例介紹
轉自:http://blog.csdn.net/yungis/article/list/1
[原]osgmotionblur例子 |
該例子演示了運動模糊的效果。 一下內容是轉自網上的: 原理: 引用內容 對於運動畫面,將當前幀畫面與上一幀畫面進行alpha融合,以產生出殘影——運動模糊效果。 通過使用累積緩存來完成這項工作。 OpenGL提供一個累積緩存,可以用來存儲當前指定的顏色緩存里面的內容,並進行一定的運算操作。 通過函數glAccum可以對累積緩存進行操作。 glAccum介紹如下: 引用內容 void glAccum(GLenum op, GLfloat value) op值用於指定操作類型,包括: GL_ACCUM 從指定的顏色緩存里面讀取像素數據,將其像素值(R, G, B, A)乘以value的結果加上累積緩存里面的值以后再保存到累積緩存; GL_LOAD 從指定的顏色緩存里面讀取像素數據,將其像素值乘以value的結果直接保存到累積緩存; GL_ADD 將累積緩存里面的像素值與value相加以后保存到累積緩存; GL_MULT 將累積緩存里面的像素值與value相乘以后保存到累積緩存; GL_RETURN 將累積緩存里面的像素值乘以value以后保存到指定的顏色緩存; 在這個例子中,用到了GL_MULT、GL_ACCUM、GL_RETURN。 在主程序中osg::DisplaySettings::instance()->setMinimumNumAccumBits(8,8,8,8);設置了積累緩沖區各位數。 然后,osgViewer::Viewer::Windows windows; viewer.getWindows(windows); for (osgViewer::Viewer::Windows::iterator itr = windows.begin(); itr != windows.end(); ++itr) { (*itr)->add(new MotionBlurOperation (persistence)); }在視景體中每個圖形窗體都添加了MotionBlurOperation類,MotionBlurOperation繼承Operation,在virtual void operator () (osg::Object* object)方 法中如果是第一次渲染,則清楚積累緩沖區的值,glClearColor(0, 0, 0, 0); glClear(GL_ACCUM_BUFFER_BIT); 之后,glAccum(GL_MULT, s); glAccum(GL_ACCUM, 1 - s); glAccum(GL_RETURN, 1.0f);通過這三個函數計算。 我們一個一個的進行說明,首先,glAccum(GL_MULT, s);積累緩沖區中的值乘以s,結果寫進積累緩沖區中,glAccum(GL_ACCUM, 1 - s);然后,顏色緩沖區中的值乘以1-s,結果寫入積累緩沖區中,最后,glAccum(GL_RETURN, 1.0f);把積累緩存區中的值乘以1,寫入顏色緩存區中,完成運動模糊的效果,這里可以看出積累緩沖區中的值只有一份,是每一幀不同比率的一個累計,也就是說第一幀的累計效果也是存在的,只是隨着幀數的增加,第一幀的影像比率趨近於0了。這幾個函數中不難得出,s值越大,前幾幀的效果存在的時間越長,運動模糊效果越明顯,如果s趨近於1,程序將很長時間是黑屏,因為glClearColor(0, 0, 0, 0);glClear(GL_ACCUM_BUFFER_BIT);積累緩沖區顏色值為黑色,s趨近於1,第一幀的影像非常大,所以很長時間一直為最初的顏色——黑色。 這里必須要深入研究一下,glAccum應用的時刻,以上的說明中可以看出,glAccum應該是一幀中顏色緩沖區中的值計算完之后應用,在這個例子中用了otionBlurOperation, MotionBlurOperation繼承Operation。我們就看看Operation是做什么的。到了Operation的定義,說它是實現圖形操作的基類,子類必須重寫virtual void operator () (Object*) = 0;方法,實現相應的功能。在GraphicsContext類中typedef std::list< ref_ptr<Operation> > GraphicsOperationQueue; GraphicsOperationQueue _operations;定義了一個Operation類型的一個鏈表,這個鏈表又在什么地方應用的了?還回到GraphicsContext::runOperations()中,記得上一篇osgmemorytest例子中,提到過GraphicsContext::runOperations(),在這里實現(*(camera->getRenderer()))(this);渲染工作。這一次我們又找的了這個函數,(*_currentOperation)(this);遍歷_operations這個鏈表,然后執行每個Operation中的operator () (Object*)方法,從runOperations()這個函數中,我們知道了osg的渲染過程,先進行渲染,然后在執行_operations中的操作。 我們回到例子中,MotionBlurOperation這個類,把它加入到了所有的圖形上下文中osgViewer::Viewer::Windows windows; viewer.getWindows(windows); for (osgViewer::Viewer::Windows::iterator itr = windows.begin(); itr != windows.end(); ++itr) { (*itr)->add(new MotionBlurOperation (persistence)); },glAccum函數執行的時候正好和我們之前所判斷的一樣,先渲染,渲染后對顏色緩存區中的值進行累積。 對這個例子和積累緩沖區總算有了一些理解,但這里還存在一個問題,如果想只對場景中的某個部分做運動模糊應該如何處理???比如有一個足球場,一個運動中的足球,只對這個足球進行運動模糊處理,如何去做??? 這個問題自己還沒有去驗證,自己想的一個大概方法是,相同位置的的兩個相機,一個關注足球之外的場景,不做運動模糊處理;另外一個只關注足球,做運動模糊處理,然后,兩幅場景融合為一個場景。
作者:yungis 發表於2013/7/30 23:44:12
原文鏈接
閱讀:518 評論:1
查看評論
|
[原]osgmemorytest例子 |
osgmemorytest這個例子也從一幀入手。 eventTraversal(); updateTraversal(); renderingTraversals(); 事件回調、更新回調、渲染。 OpenGL是狀態機,調整好各個狀態,然后繪制幾何體。OSG中同理,renderingTraversals中根據每個StateSet繪制Drawable。無論是加載的模型還是自己繪制的幾何體,最后都是Drawable。 renderingTraversals中最主要的還進行了剔除(CullVisitor),這里不多說,主要說OSG中OpenGL的狀態的執行。 進入renderingTraversals函數內部,找到(*itr)->runOperations();(對於單線程來說),這句話進行了場景的繪制工作。順着這個藤一直摸下去,為了思路清晰,列出序號: 1、調用了GraphicsContext::runOperations(); 2、在GraphicsContext::runOperations()中找到(*(camera->getRenderer()))(this); 3、跟到了Renderer中的void Renderer: ![]() { if (_graphicsThreadDoesCull) { cull_draw(); } else { draw(); } }。 4、在Renderer的draw方法中找到了 sceneView->draw(); 5、如果不需要立體顯示,在 sceneView->draw();中會找到_renderStage->drawPreRenderStages(_renderInfo,previous); _renderStage->draw(_renderInfo,previous); 6、然后執行了RenderStage中的drawInner 7、RenderBin::draw(renderInfo,previous); 8、drawImplementation(renderInfo,previous); 9、RenderLeaf* rl = dw_itr->get(); rl->render(renderInfo,previous); 10、state.apply(rg->getStateSet());_drawable->draw(renderInfo);最終實現繪制 好復雜的一條路了,對於多線程而言與以上的步驟有些不同,但大體差不多。 幾個重要的類,GraphicsContext--Renderer--SceneView--RenderStage(RenderBin)--RenderLeaf--Drawable。 最終的實現都在具體的Drawable中,就像上面說的,無論是加載的模型還是自己繪制的幾何體,最后都是Drawable。這樣最終會調用可用的Drawable實現繪制。 以上這么一條復雜的路線,要重點說的是第10步中的state.apply(rg->getStateSet()); 下面從這個調用說起,State存儲了OpenGL需要的所有的狀態,是OSG與OpenGL狀態的接口,進入這個函數中看看做了什么。 在這個函數中找到了applyAttributeList(_attributeMap,dstate->getAttributeList());這么一句話,深入下去。循環調用了applyAttribute這個函數,而傳遞的就是StateAttribute,這就是OSG中某個狀態屬性,在applyAttribute中找到了attribute->apply(*this);狀態屬性執行了apply把State傳入進去。進入StateAttribute中的apply,不禁大失所望,什么也沒有?? StateAttribute是基類,打開API文檔,看看繼承StateAttribute的狀態屬性吧,有幾十個之多,我們重點找幾個看看。 Fog,進入Fog的Fog::apply(State& state),在這里看見了OpenGL函數,glFogi以及一系列的設置。 PolygonOffset,進入PolygonOffset的PolygonOffset::apply(State&),在這里看見了glPolygonOffset執行多邊形偏移。 Texture2D,進入Texture2D::apply(State& state),在這里看見了glTexImage2D。 ... attribute->apply(*this)這么短短的一句話,就執行了所有狀態屬性的設置。 這篇文章的標題是osgmemorytest,怎么繞了這么多?下面回到osgmemorytest例子中。 定義了好多的基類,MemoryTest、GLObject、GLMemoryTest。 有用的是ContextTest,osg::ref_ptr<osg::GraphicsContext> window = osg::GraphicsContext::createGraphicsContext(traits.get());創建了GraphicsContext,根據pbuffer來決定是PixelBuffer還是Window。 StateAttributeObject中執行了_attribute->apply(*renderInfo.getState());看到這里就知道了為什么上面說了那么多,都是在說這個類的作用。 TextureTest中最終都調用了StateAttributeObject。 FboTest中也調用了StateAttributeObject。 DrawableObject調用了_drawable->draw(renderInfo); GeometryTest調用了DrawableObject中的函數。 從以上幾個類的功能來說,不難看出他們所作的事情,1、創建窗口;2、設置狀態;3、繪制; 因此整個的例子大體上描繪了OSG渲染的一個過程,而main函數中所做的就是創建窗口、設置狀態、繪制。打印出contexts數目,objects applied次數已經執行所用的實際。
作者:yungis 發表於2013/6/7 23:32:32
原文鏈接
閱讀:600 評論:0
查看評論
|
[原]關於例子 |
最近很久沒有寫文章了,很久沒有登錄csdn了。最初只是為了一邊研究一遍學osg而寫的一些體會,沒想到有這么多的志同道合的朋友們關注。此時此刻覺得有些感動,osg例子還需要繼續下去,專題還需要繼續下去。有精力的話,osgearth、osgocean、delta3d真的想一邊學習研究一邊寫下去。有那么多osgChina上的朋友支持,以后有新的例子會在osgChina上發表的,多謝支持!
作者:yungis 發表於2013/6/6 23:47:56
原文鏈接
閱讀:580 評論:1
查看評論
|
[原]osgmanipulator例子 |
這個例子演示了osg中拖拽器的使用,可以控制模型的移動、旋轉縮放。 createDemoScene函數,如果沒有加載模型,默認的創建幾個基本幾何體,bool fixedSizeInScreen參數決定拖拽器是否固定大小。這個函數里面的代碼很簡單,創建了幾個基 本幾何體,然后把他們包裝上不同的拖拽器,加入到場景中。 TabBoxDragger, TabPlaneDragger, TabBoxTrackballDragg, TrackballDragger,Translate1DDragger, Translate2DDragger, TranslateAxisDragger 一種有這么七種拖拽器,TabBoxDragger, 包圍盒,用於縮放和移動幾何體,TabPlaneDragger, 一 個平面,用於平面內縮放和移動幾何體,TabBoxTrackballDragg, 一個包圍盒和一個包圍球,用 於移動、縮放、選擇幾何體,TrackballDragger包圍球,用於旋轉幾何體, Translate1DDragger, Translate2DDragger, TranslateAxisDragger 一個、兩個、三個箭頭的拖拽 器,分別在不同的方向上移動幾何體。 我們進入addDraggerToScene函數,這個函數就是包裝拖拽器的地方,首先根據名稱創建拖拽器 createDragger 我們進入osgManipulator這個庫,看看他是怎么設計的,Dragger類繼承MatrixTransform拖拽器 的基類,在拖拽器中考慮到繼承關系,拖拽器可能會有父拖拽器, setActivationModKeyMask setActivationKeyEvent非常重要,設置按指定鍵的時候,鼠標才可 以拖動拖拽器。 traverse遞歸函數是場景中的每個節點都會調用的,因此在這個函數里,當是事件遍歷的時候調 用了內置的handle方法。實現拖拽動作。 這個思路又給我們一些啟示,與場景的交互,不一定要繼承EventHandler,通過traverse同樣可 以實現。這些需要深入理解在事件遍歷的時候osg都干了些什么。 addTransformUpdating這個方法,通過回調實現變換。 還有其他的一些設置,比如操作器是否可以,是否接受事件,創建拖拽器幾何體等等。 CompositeDragger類繼承Dragger,是組合拖拽器,多個拖拽器組合成一個拖拽器。 RotateCylinderDragger、RotateSphereDragger、Scale1DDragger、Scale2DDragger、 Translate1DDragger、Translate2DDragger都是繼承Dragger ScaleAxisDragger、TabBoxDragger、TabBoxTrackballDragger、TabPlaneDragger、 TabPlaneTrackballDragger、TrackballDragger、TranslateAxisDragger、 TranslatePlaneDragger都是繼承CompositeDragger 而對外暴露的操作器一般都是組合操作器。 Command創建了移動,縮放,旋轉的命令,在Dragger中使用。 回到例子中來,osgManipulator::Dragger* dragger = createDragger(name);根據指定的名稱 創建拖拽器,判斷是否縮放拖拽器,如果不縮放拖拽器,則通過DraggerContainer類,在遍歷的 時候計算矩陣保持拖拽器的固定大小。 dragger->addTransformUpdating(selection);設置更新矩陣,用於更新拖拽器自身的位置。 dragger->setActivationModKeyMask(osgGA::GUIEventAdapter::MODKEY_CTRL); dragger- >setActivationKeyEvent('a'); 設置了當按住ctrl+ a的時候,拖拽器有效。 前文分析的有些亂,下面做一個總結: 拖拽器實現指定模型的平移、縮放、選擇等操作,(拖拽器本身也是模型,根據不同拖拽方式, setupDefaultGeometry設置geometry),Dragger類是基類,CompositeDragger是組合拖拽器的 基類,Dragger派生出很多子類,都是單一的功能,比如只向右移動,而我們應用的拖拽器一般 都是組合拖拽器,比如向x,y,z三個方向移動,這就是三個Dragger的疊加,組合拖拽器就是這 些基本拖拽器的疊加。 拖拽器在操控指定模型的時候,通過DraggerCallback來更新實現變換。 dragger->addTransformUpdating(selection);就把模型的MatrixTransform給了拖拽器用於更新 。拖拽器又是怎么更新的呢?拖拽器又是怎么樣改變模型姿態的呢? 在Dragger遞歸的時候traverse,如果是事件遍歷,調用Dragger的handle,然后判斷鼠標的按下 、釋放、移動等各種狀態,求交運算, dragger->handle(_pointer, ea, aa);然后調用具體的 某個拖拽器的handle,通過Command和receive來最終實現拖拽效果。
作者:yungis 發表於2013/4/27 7:58:37
原文鏈接
閱讀:2025 評論:0
查看評論
|
[原]osglogo例子 |
在osg中osgGetVersion()獲取osg的版本信息。 本例子通過Geode和Geometry創建最基本的幾何體,實現logo的繪制,不進行詳細的研究。 里面的地球,通過ShapeDrawable紋理貼圖,MatrixTransform的setUpdateCallback(new osg::AnimationPathCallback實現自動的旋轉。 本例子MyBillboardTransform : public osg::PositionAttitudeTransform實現了朝向一直屏幕 的效果,這里需要比較一下MyBillboardTransform、Billboard、AutoTransform朝向屏幕的實現 方法。首先看MyBillboardTransform: 重寫computeLocalToWorldMatrix方法,計算視點坐標 bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const { osg::Quat billboardRotation; osgUtil::CullVisitor* cullvisitor = dynamic_cast<osgUtil::CullVisitor*>(nv); if (cullvisitor) { osg::Vec3 eyevector = cullvisitor->getEyeLocal()- _position; eyevector.normalize(); osg::Vec3 side = _axis^_normal; side.normalize(); float angle = atan2 (eyevector*_normal,eyevector*side); billboardRotation.makeRotate (osg::PI_2-angle,_axis); } matrix.preMultTranslate(_position); matrix.preMultRotate(billboardRotation); matrix.preMultRotate (_attitude); matrix.preMultTranslate(-_pivotPoint); return true; }實現節點一直朝向屏幕 看看Billboard Billboard是在CullVisitor void CullVisitor::apply(Billboard& node)的時候也是獲取視點 坐標,調用computeMatrix來實現的,根據不同的設置方法計算computeMatrix(Matrix& modelview, const Vec3& eye_local, const Vec3& pos_local) const中的modelview。 AutoTransform也是在AutoTransform::computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*)中計算computeMatrix()修改_cachedMatrix.makeRotate(_rotation); _cachedMatrix.postMultTranslate(_position); _cachedMatrix.preMultScale(_scale); _cachedMatrix.preMultTranslate(-_pivotPoint);這幾個影響節點編號的屬性來實現的。 總結起來,他們都是在剔除的過程中通過CullVisitor的apply方法,調用各自的方法來完成朝向 屏幕矩陣的計算。
作者:yungis 發表於2013/4/23 7:55:50
原文鏈接
閱讀:645 評論:0
查看評論
|
[原]osglogicop例子 |
該例子演示了opengl中的glLogicOp功能,指定不同的邏輯運算實現當前顏色和幀緩沖的顏色計 算。有以下幾種參數 GL_CLEAR 0 GL_SET 1 GL_COPY s GL_COPY_INVERTED ~s GL_NOOP d GL_INVERT ~d GL_AND s & d GL_NAND ~(s & d) GL_OR s | d GL_NOR ~(s | d) GL_XOR s ^ d GL_EQUIV ~(s ^ d) GL_AND_REVERSE s & ~d GL_AND_INVERTED ~s & d GL_OR_REVERSE s | ~d GL_OR_INVERTED ~s | d s代表當前顏色,d代表幀緩沖中的顏色。前面是glLogicOp中可以接受的參數,后面是運算結果 。在osg中對應LogicOp類,它繼承StateAttribute,屬於狀態屬性的一種。在類的內部定義了以 上參數的枚舉。 回到例子中,定義了 osg::LogicOp* logicOp = new osg::LogicOp (osg::LogicOp::OR_INVERTED);並且 stateset->setAttributeAndModes (logicOp,osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);啟用屬性和模式。 stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);設置繪制優先級。 setRenderingHint和setRenderBinDetails都可以設置節點繪制的順序,在osg中根據他們參數的 數值進行節點渲染順序的配置,達到可以控制節點渲染順序的功能。 接下來通過TechniqueEventHandler來控制當前logicOp 使用的邏輯運算符。
作者:yungis 發表於2013/4/22 7:36:58
原文鏈接
閱讀:371 評論:0
查看評論
|
[原]osglightpoint例子 |
該例子演示了光點的效果,主要應用osgSim庫中的LightPoint、LightPointNode、 SequenceGroup、BlinkSequence,osgSim庫屬於仿真庫,擴展庫。應用osg核心庫完成一些指定 的效果。因此研究這個例子只需要指定以上這幾個類的作用即可。 LightPoint是光點類,有如下屬性: bool _on; osg::Vec3 _position; osg::Vec4 _color; float _intensity; float _radius; osg::ref_ptr<Sector> _sector; osg::ref_ptr<BlinkSequence> _blinkSequence; BlendingMode _blendingMode; 是否打開、位置、顏色、強度、半徑、扇區、閃爍、模式 從以上的屬性可以指定,這個光點可以調整大小位置,可以運動可以變換顏色,閃爍效果。 而LightPointNode是光點節點,里面保存了一個光點列表typedef std::vector< LightPoint > LightPointList; SequenceGroup用於關聯一組序列,內部只有一個基本時刻double _baseTime; BlinkSequence閃爍序列,內部的屬性:double _pulsePeriod; double _phaseShift; PulseData _pulseData; osg::ref_ptr<SequenceGroup> _sequenceGroup;從中可以看出可以添加很 多脈沖,每個脈沖的間隔、停頓等。它屬於LightPoint光點的一個屬性,也就說一個光點可以以 SequenceGroup定義的基本時間為基本仿真時間,根據BlinkSequence中設置的變換顏色和光點強 度和脈沖。 明白了以上幾個類之間的關系,這個例子就很好理解了。 在createLightPointsDatabase函數中創建了很多光點,設定了位置和顏色的變換范圍,里面有 一個: lpn->setPointSprite設置了光點添加紋理使用模糊的效果,必須指定0紋理單元(后面研究實現 方法)。 CreateBlinkSequenceLightNode函數創建了閃爍的光點,設置序列組,添加脈沖,設置強度位置 等等。 我們詳細的研究一下LightPointNode,說是光點節點,但是它本身不發光,但可以通過其他方式 模擬出發光的效果。這個節點很特別,在osg中節點組成場景樹,通過剔除遍歷場景樹構建狀態 樹和渲染樹,如果讓我們自己實現這個LightPointNode節點,我們想到的方式可能是 LightPointNode : public osg:Geode讓他繼承geode,然后adddrawable把光點的drawable添加 進去進行渲染。 而實際中LightPointNode並沒有采用這種方法,而是繼承Node,並且沒有add任何的子節點。所 有的的功能都是在traverse遞歸的時候實現的。 這就涉及到了如何跳過場景樹去繪制節點,答案是在剔除的時候去手動構建狀態樹,我們進入代 碼看看是怎么樣手動構建的。 首先 osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);用於判斷只 有在剔除遍歷的時候才繼續運行下面的代碼, osg::Matrix matrix = *(cv->getModelViewMatrix()); osg::RefMatrix& projection = *(cv->getProjectionMatrix()); osgUtil::StateGraph* rg = cv- >getCurrentStateGraph(); if (rg->leaves_empty()) { // this is first leaf to be added to StateGraph // and therefore should not already know current render bin, // so need to add it. cv- >getCurrentRenderBin()->addStateGraph(rg); } 獲取模型視圖矩陣、獲取投影矩陣、獲取當前的渲染根節點。 typeid(*object)==typeid(LightPointDrawable) 用於判斷object是否是(LightPointDrawable)類型的,如果是返回true否則返回false。 接下來 drawable = _pointSprites ? new LightPointSpriteDrawable : new LightPointDrawable; 這里我們看到了_pointSprites ,這就是是否讓LightPointNode使用紋理,如果使用紋理則new LightPointSpriteDrawable否則new LightPointDrawable。並且把這個drawable設置成了當前的 userdata。 接下來把這個drawable收到的添加到rg->addLeaf(new osgUtil::RenderLeaf (drawable,&projection,NULL,FLT_MAX));渲染葉中,到目前為止需要注意,這個drawable中還 沒有任何內容,接下來就需要根據_lightPointList去向這個drawable添加繪制的內容,注意添 加addBlendedLightPoint和addAdditiveLightPoint。 現在我們進入LightPointDrawable中一看究竟,LightPointDrawable繼承Drawable,需實現 drawImplementation接口,關於drawImplementation我們會在不久的以后進行詳細的研究。 這里根據_sizedOpaqueLightPointList、_sizedBlendedLightPointList、 _sizedAdditiveLightPointList中的內容進行了繪制,在這里面看到了狀態的切換,看到了 opengl的代碼。 再補充一下,LightPointDrawable中沒有應用模糊紋理,因此state.applyTextureMode (0,GL_TEXTURE_1D,false); state.applyTextureMode(0,GL_TEXTURE_2D,false); 而看看LightPointSpriteDrawable,state.applyTextureMode(0,GL_TEXTURE_2D,true);這里應 用了紋理,這就是兩者差別的體現。 研究完了這一趟,似乎觸及到了osg中核心的一些東西。至於我們剛才提出的問題為什么沒有把 他設計成Geode,而是繼承Node,接下來大家一起思考。
作者:yungis 發表於2013/4/19 7:43:24
原文鏈接
閱讀:510 評論:0
查看評論
|
[原]osglight例子 |
先列上兩個鏈接介紹osg中的矩陣變換。 http://www.cnblogs.com/indif/archive/2011/05/13/2045106.html http://www.cppblog.com/acmiyou/archive/2009/08/24/94292.html opengl中矩陣是列主序,osg中是行主序。 個人覺得這樣從應用上去考慮原因,opengl是最低層低級的軟件和硬件的接口,考慮的是高效性 能,osg是高級三維引擎,考慮的是應用和便於理解。opengl中的矩陣使一個16大小的一維數組 ,因此在進行矩陣運算的時候只需要指針++就可以到下一個。 而實際的應用中,我們一般理解點是行主序的三個數, osg當中: newpos =oldpos * T *R //先執行平移 后執行旋轉 (全局坐標系) 因此執行以上的變換,先平移后旋轉,很容易理解。 在來說一下MatrixTransform 和PositionAttitudeTransform,一個是矩陣變換一個是位置姿態 ,MatrixTransform 是按着矩陣相乘的順序做變換,而PositionAttitudeTransform是按着SRT的 順序變換,所以對於PositionAttitudeTransform無論是先設置位置旋轉縮放還是后設置結果都 一樣。我們從源代碼中看個究竟。 對於MatrixTransform bool MatrixTransform::computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*) const { if (_referenceFrame==RELATIVE_RF) { matrix.preMult(_matrix); } else // absolute { matrix = _matrix; } return true; } 直接做了矩陣的左乘,即_matrix*matrix 而PositionAttitudeTransform bool PositionAttitudeTransform::computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*) const { if (_referenceFrame==RELATIVE_RF) { matrix.preMultTranslate(_position); matrix.preMultRotate(_attitude); matrix.preMultScale(_scale); matrix.preMultTranslate(-_pivotPoint); } else // absolute { matrix.makeRotate(_attitude); matrix.postMultTranslate(_position); matrix.preMultScale(_scale); matrix.preMultTranslate(-_pivotPoint); } return true; } 則與順序無關,完全是按着_scale*_attitude*_position*matrix 而_pivotPoint指定了變換軸,最終把節點移動到變換軸處。 關於RELATIVE_RF和ABSOLUTE_RF我們前面的例子介紹過。 我們回到例子中: createRoom函數中創建了一個正方體,里面有個 osg::PositionAttitudeTransform* pat = new osg::PositionAttitudeTransform(); pat添加了ModelTransformCallback根據仿真時間重新計算姿態。 pat->setPivotPoint (loaded_bs.center()); 有了上面的介紹我們就很容易理解了,設置節點的包圍球中心為軸心。 osg::StateSet* wall = new osg::StateSet; wall->setMode (GL_CULL_FACE,osg::StateAttribute::ON); 設置GL_CULL_FACE打開,即節點的正面被裁切,實現朝着觀察者的面不繪制的效果。 createWall繪制一面牆 osgUtil::SmoothingVisitor::smooth(*geom);自動計算了法向量。 createLights創建燈。 我們着重研究一下這個函數 LightSource繼承Group,是場景中的光源節點,保存了一個ref_ptr<Light> _light;Light是具體的光照類,內部保存了如下屬性: int _lightnum; // OpenGL light number Vec4 _ambient; // r, g, b, w Vec4 _diffuse; // r, g, b, w Vec4 _specular; // r, g, b, w Vec4 _position; // x, y, z, w Vec3 _direction; // x, y, z float _constant_attenuation; // constant float _linear_attenuation; // linear float _quadratic_attenuation; // quadratic float _spot_exponent; // exponent float _spot_cutoff; // spread 一個光源的基本屬性顏色衰減等,_lightnum是與opengl的光源id相對於,默認為0。 在createLights這個函數中創建了兩個光源,把一個點和一個光源添加到MatrixTransform中, 這樣模擬了點就是光源的效果,MatrixTransform中添加了AnimationPathCallback一個動畫, 光源AnimationPathCallback我們之前的例子中研究過,很按着指定的路徑運動。 最后一點 viewer.getCamera()->setCullingMode( viewer.getCamera()->getCullingMode() & ~osg::CullStack::SMALL_FEATURE_CULLING); 去除了細節裁剪,這樣在場景剔除的時候就不會用到SMALL_FEATURE_CULLING。
作者:yungis 發表於2013/4/17 7:54:12
原文鏈接
閱讀:615 評論:1
查看評論
|
[原]osglauncher例子 |
該例子通過讀取osg.conf文件,把一些圖片路徑和應用程序路徑讀取到了Xample里面。通過 setupGraph函數把每個圖片添加到窗體中,PickHandler繼承GUIEventHandler,獲取鼠標所選圖 片對應的應用程序名稱,同時更新_updateText(顯示圖片的名稱),單擊后運行響應的應用程 序。這里用了 system();指定指定的程序。
作者:yungis 發表於2013/4/12 7:37:23
原文鏈接
閱讀:343 評論:0
查看評論
|
[原]osgkeyboardmouse例子 |
本例子演示了拾取的功能。 PickHandler繼承GUIEventHandler ‘s’鍵通過CreateModelToSaveVisitor把選中的節點寫出。 virtual void apply(osg::Node& node) { osgFX::Scribe* scribe = dynamic_cast<osgFX::Scribe*>(&node); if (scribe) { for (unsigned int i=0; i<scribe->getNumChildren(); ++i) { _group->addChild(scribe->getChild(i)); } } else { traverse(node); } } ‘o’鍵寫出了整個場景。 ‘p’鍵切換拾取的方式。 在例子中用了兩種求交的方式:1、PolytopeIntersector;指定一個矩形區域求交,構造函數 PolytopeIntersector(CoordinateFrame cf, double xMin, double yMin, double xMax, double yMax);通過cf指定了一種坐標參考,后面的參數指定了一個矩形。 enum CoordinateFrame { WINDOW, PROJECTION, VIEW, MODEL }; 關於這幾種方式:MODEL方式表示使用世界坐標,傳入參數也就直接是世界坐標;WINDOW、 PROJECTION和VIEW都是傳入屏幕/投影窗口/視口坐標作為參數,並且設法在求交過程中將它們轉 換為世界坐標。如果希望使用WINDOW等方式,需要節點是相機節點。我們進入代碼中看看這幾種 方式的實現: polytopeintersector.cpp中, osg::Matrix matrix; switch (_coordinateFrame) { case(WINDOW): if (iv.getWindowMatrix()) matrix.preMult( *iv.getWindowMatrix() ); if (iv.getProjectionMatrix()) matrix.preMult( *iv.getProjectionMatrix() ); if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); break; case(PROJECTION): if (iv.getProjectionMatrix()) matrix.preMult( *iv.getProjectionMatrix() ); if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); break; case(VIEW): if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); break; case(MODEL): if (iv.getModelMatrix()) matrix = *iv.getModelMatrix(); break; } 無論是哪一種方式,最終都轉換到了世界坐標。 2、LineSegmentIntersector;使用構造函數LineSegmentIntersector(CoordinateFrame cf, double x, double y);指定一點求交。 所以為了更精確的球交,應使用osgUtil::Intersector::WINDOW窗口坐標,viewer->getCamera ()->accept(iv); toggleScribe函數就是使用osgFX::Scribe實現框體選中的效果。
作者:yungis 發表於2013/4/11 7:05:25
原文鏈接
閱讀:499 評論:0
查看評論
|
[原]osgkeyboard例子 |
本例子演示了鍵盤事件,比較簡單。 通過KeyboardModel類繪制出一個鍵盤,KeyboardEventHandler繼承GUIEventHandler,實現鍵盤 事件的處理。
作者:yungis 發表於2013/4/11 6:18:42
原文鏈接
閱讀:313 評論:0
查看評論
|
[原]osgkdtree例子 |
本例子演示了KDTree,實際上沒什么內容。我們就在這沒內容的幾行代碼中挖一挖。 關於KDTree的介紹http://www.cnblogs.com/eyeszjwang/articles/2429382.html,在這里可以 看看。我們不研究算法,只研究代碼和實現。 KDTree為場景的求交提供了一種更加有效率、更加精確的算法。 例子中只有一句和KDTree有關的osgDB::Registry::instance()->setBuildKdTreesHint (osgDB::ReaderWriter::Options::BUILD_KDTREES);在Registry中注冊構建KDTree。我們進入 Registry中,構造函數: _buildKdTreesHint = Options::NO_PREFERENCE; _kdTreeBuilder = new osg::KdTreeBuilder; const char* kdtree_str = getenv("OSG_BUILD_KDTREES"); if (kdtree_str) { bool switchOff = (strcmp(kdtree_str, "off")==0 || strcmp(kdtree_str, "OFF")==0 || strcmp(kdtree_str, "Off")==0 ); if (switchOff) _buildKdTreesHint = Options::DO_NOT_BUILD_KDTREES; else _buildKdTreesHint = Options::BUILD_KDTREES; } 從這里可以看出KdTreeBuilder是構建KDTree的地方,首先,KDTree沒有指定,讀取環境變量, 如果環境變量中沒有off字樣的就設置Options::BUILD_KDTREES;可見在osg默認是構建了KDTree 的。順着這些信息看看,KDTree是在什么地方構建的? 在DatabasePager中我們可以看到如下的代碼: _kdTreeBuilder = osgDB::Registry::instance()->getKdTreeBuilder()->clone(); virtual void apply(osg::Geode& geode) { StateToCompile::apply(geode); if (_kdTreeBuilder.valid()) { geode.accept(*_kdTreeBuilder); } } 他們都在FindCompileableGLObjectsVisitor這個類中,DatabasePager分頁數據庫,管理 PagedLOD和ProxyNode的,里面存放了數據請求列表、數據等待刪除列表、數據等待編譯列表、 數據等待融合場景列表、而這個類就是查找需要編譯的數據。(具體內容看《最長的一幀》) KDTree就是在這里構建的。 KdTreeBuilder是構建的關鍵類,不用說繼承自NodeVisitor,要遍歷場景的。里面只有void apply(osg::Geode& geode);因為它只對幾何體感興趣。 KDTree的構建把我們帶到了KDTree這個類中,具體的算法不做分析了,KDTree的用法在上次求交 的例子中有了應用,求交更加精確。 Registry是一個單例,在程序的運行中只有一個對象,因此這個的程序中又有一個 KdTreeBuilder。
作者:yungis 發表於2013/4/9 7:36:45
原文鏈接
閱讀:1030 評論:0
查看評論
|
[原]osgintersection例子 |
先說一下osgSim庫,它提供虛擬仿真效果的節點工具,用於特殊效果。 這個例子中涉及到了osgSim::LineOfSight,我們就來看看這個類是干什么,從字面上可知,它 是視線、瞄准線。 DatabaseCacheReadCallback這個類繼承ReadCallback,在相交的測試中,場景可能有PagedLOD ,而計算相交過程中,PagedLOD不是精度最高的節點(如地球),這樣計算的就不准確,這個 ReadCallback類就保證了在IntersectionVisitor::apply(osg::PagedLOD& plod)時候,加載最 高精度的PagedLOD,從而保證計算的精度。但加載節點是比較耗時的。而這個 DatabaseCacheReadCallback是一個緩存數據庫,把加載過的PagedLOD緩存下來,下次直接從緩 存中加載。readNodeFile是主要的函數。 LineOfSight類建立和地球的相交線。通過LOS結構存儲一個起點和一個終點,把和場景的交點保 存在Intersections中。在內部保存一個osgUtil::IntersectionVisitor _intersectionVisitor;進行相交測試。 computeIntersections是相交計算的主要函數,IntersectorGroup存放了一組相交的線段,之前 我們提到過,在osg中有多種相交的計算(線、面、體),線與場景相交最為常見。 接下來: _intersectionVisitor.reset(); _intersectionVisitor.setTraversalMask (traversalMask); _intersectionVisitor.setIntersector( intersectorGroup.get() ); 相交訪問器重置,設置掩碼,添加相交的數據Intersector,Intersector有四個子類,用於和場 景求交。 scene->accept(_intersectionVisitor); 通過這個函數遍歷場景計算相交的點。在IntersectionVisitor中,inline void intersect (osg::Drawable* drawable) { _intersectorStack.back()->intersect(*this, drawable); } 是具體的求交的方法,具體的算法隱藏在子類中,線段相交的算法在 LineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable)中,具體的實現算法我們不做研究,從中可以看到KdTree,這個類為場景的求交提供 了更加精確的工具,之后我們馬上就會研究這個東西。 接下來,就可以獲取相交的成果了, osgUtil::LineSegmentIntersector::Intersections& intersections = lsi- >getIntersections(); for (osgUtil::LineSegmentIntersector::Intersections::iterator itr = intersections.begin (); itr != intersections.end(); ++itr) { const osgUtil::LineSegmentIntersector::Intersection& intersection = *itr; if (intersection.matrix.valid()) intersectionsLOS.push_back( intersection.localIntersectionPoint * (*intersection.matrix) ); else intersectionsLOS.push_back( intersection.localIntersectionPoint ); } 從中獲取相交的點。 這里我們不妨思考一下,在osg中為什么有那么多的visitor和callback存在呢?無論什么功能都 使用的visitor,我想osg作為一種非常成熟的渲染引擎,必須從構架上清晰,這些visitor都是 osg的擴展功能,不能影響總體架構。更重要是是osg采用的是樹狀結構構建場景、進行渲染的, 通過這個visitor很容易實現遞歸遍歷場景,這就是訪問者模式應用之所在,而callback提供了 一種擴展的接口。而且在visitor過程中存在很多成對的東西,如:push/pop、在求交訪問器中 存在enter/leave,這就是訪問者進入-離開,沒有改變場景。訪問者模式的缺點也就清除了,他 必須重載所有的節點類,如果osg中有新的節點類型添加,改動會很大。 離題萬里了,回到例子中,看看HeightAboveTerrain,功能也類似,求的是和地形的交點,這個 地形就具有具體的空間參考了。 接下來,求出求交時間,打印交點。 ElevationSlice求的面與地形的交點。 else if中沒有應用osg封裝的類,直接使用LineSegmentIntersector求交,當然,這樣只會對當 前場景進行計算,如果有PagedLOD,則不會加載,然后打印出結果。
作者:yungis 發表於2013/4/8 7:55:42
原文鏈接
閱讀:1503 評論:0
查看評論
|
[原]osgimpostor例子 |
本例子演示了impostor代替節點的應用。 以下是轉自網上翻譯源碼的內容: Impostor是一種LOD組節點,它既允許通過子結點到視點的距離來選擇相應的子結點,又可以通 過到視點的距離來選擇圖片緩存。Impostor的原理是:通過緩存幾何體(realgeometry)的圖像 ,然后在之后的幀內使用該圖像代替該幾何體。這有點像Billboard,但是, 它是實時更新並與 視點的位置相關的。通過映射了該紋理的四邊形,可以降低場景的復雜度以提高性能。OSG中的 impostor並不是完全按照上述網址中的技術來實現的,但是這應該是個不錯的開始。OSG的 Impostor結點遠沒有那么復雜,因為使用時你並不需要重構(重新組織)你的整個場景。你所要 做的就是為Impostor結點的每一個子結點設置相應的LOD可見范圍值(visiblerange value), 並且設置一個Impostor閾值,來告訴渲染器(renderer)在什么距離以外應該使用Impostor的圖 像緩存。osg::CullVisitor會自動處理所有的渲染前期(pre-renderingstages)的設置,計算 出所需的ImpostorSprites(這個類封裝了圖像緩存與四邊形),並隨視點的變化更新它們。如 果你使用osg::SceneView/CullVisitor,所有為了支持Impostor的復雜過程都會被很好的隱藏。 關於Impostor還有很多改進計划: 1) 估計一個ImpostorSprite在多少幀內會被重用,如果被重用的次數不會多於一個最小閾值的 話,就不創建這個ImpostorSprite而是直接使用幾何體 2)與內存中的紋理共享數據 3)對ImpostorSprite使用簡單的3D幾何體而不是Billboard 4)減小ImpostorSprite的大小使之更適合內在的(underlying)幾何體 Impostor繼承自LOD,我們都知道LOD實現在指定范圍內顯示物體,Switch節點可以開關節點,這 些是怎么實現的呢,我們進入源碼看看究竟。 virtual void traverse(NodeVisitor& nv);每個類型的節點當訪問它的時候,都會進行遞歸調 用,而遞歸的關鍵就是traverse。 void Group::traverse(NodeVisitor& nv) { for(NodeList::iterator itr=_children.begin(); itr!=_children.end(); ++itr) { (*itr)->accept(nv); } } 這是Group的遞歸,直接遍歷所有的子節點。 再來看看LOD的遞歸調用, for(unsigned int i=0;i<numChildren;++i) { if (_rangeList[i].first<=required_range && required_range<_rangeList[i].second) { _children[i]->accept(nv); } } 是的,判斷了該節點是否在指定的視野內,如果不在就不進行遞歸調用,這樣在osg中無論是更 行回調、事件回調、裁切回調,包括自己實現的回調,都會進行判斷,不在視野內就忽略。 而在Impostor中的traverse呢,通過ImpostorSprite創建圖片代替,在createImpostorSprite這 個函數中實現具體的圖片創建過程,通過幀緩存對象,把節點選擇到紋理中。 回到例子中,CreateHouses()創建了一個房子模型,加入到nodes中,LayoutAsGrid()函數通過 代替節點加入400個模型, osgSim::Impostor * impostor = new osgSim::Impostor(); impostor- >setImpostorThreshold(static_cast<float> (Threshold)); impostor- >addChild(groups[i]); impostor->setRange(0, 0.0f, 1e7f); impostor->setCenter(groups[i]->getBound().center()); 設置代替節點的參數。 TestManipulator繼承CameraManipulator,測試的操作器。寫自己的操作器只需重寫幾個類就可 以實現, /** set the position of the matrix manipulator using a 4x4 Matrix.*/ virtual void setByMatrix(const osg::Matrixd& matrix); /** set the position of the matrix manipulator using a 4x4 Matrix.*/ virtual void setByInverseMatrix (const osg::Matrixd& matrix) { setByMatrix(osg::Matrixd::inverse(matrix)); /** get the position of the manipulator as 4x4 Matrix.*/ virtual osg::Matrixd getMatrix() const; /** get the position of the manipulator as a inverse matrix of the manipulator, typically used as a model view matrix.*/ virtual osg::Matrixd getInverseMatrix() const; 最重要的是getInverseMatrix這個函數,osg中每一幀的更新回調會調用操作器的這個函數賦值 給相機,實現相機的更新。 virtual void setNode(osg::Node*); /** Move the camera to the default position. May be ignored by manipulators if home functionality is not appropriate.*/ virtual void home (const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us); /** Start/restart the manipulator.*/ virtual void init(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us); /** handle events, return true if handled, false otherwise.*/ virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us); 這幾個函數在重寫的時候也經常用到,設置中心節點,初始位置、初始化,事件處理。
作者:yungis 發表於2013/4/2 7:17:31
原文鏈接
閱讀:672 評論:1
查看評論
|
[原]osgimagesequence例子 |
本例子演示了圖片的播放 createModel創建geometry,createState創建stateset。 ImageSequence繼承自ImageStream,ImageStream繼承自Image,實現圖像流的播放控制, ImageSequence可以實現作為紋理貼圖時紋理控制。有三種模式 enum Mode { PRE_LOAD_ALL_IMAGES, PAGE_AND_RETAIN_IMAGES, PAGE_AND_DISCARD_USED_IMAGES }; 全部提前加載、用到時候加載和用完后舍去。imageSequence->play();之后就可以按着設定的模 式播放圖片。 FindImageStreamsVisitor類把所有的ImageStream放置到_imageStreamList中,然后通過 MovieEventHandler進行暫停、播放、循環等設置。
作者:yungis 發表於2013/3/27 7:25:24
原文鏈接
閱讀:400 評論:1
查看評論
|
[原]osghud例子 |
本例子演示了HUD的功能,之前的很多例子都用到了HUD,而且實現HUD有很多的方式。其實HUD也 是一個節點,唯一的特別之處就是從一個指定的位置觀察這個節點,這個節點一直以平面的方式 投到創建的表面,不隨着場景和視點的變換而變換。 createHUD()這個函數: 第一步、創建個相機,它的自節點繪制到這個HUD中。 第二步、設置投影矩陣,這個就是投影到場景的屏幕上。 第三部、設置相對幀,setReferenceFrame(osg::Transform::ABSOLUTE_RF);camera- >setViewMatrix(osg::Matrix::identity());這個保證這個節點不隨着場景和視點的變換而變化 。 第四部、清除深度緩存camera->setClearMask(GL_DEPTH_BUFFER_BIT); 第五步、設置渲染順序camera->setRenderOrder(osg::Camera::POST_RENDER);這個保證了最后 渲染,HUD一直在場景的最外面。 第六步、camera->setAllowEventFocus(false);保證該HUD不接受事件。 之后在HUD上添加文字和畫板。 在main函數中顏色了添加HUD的幾種方式: 第一種、因為這里的HUD載體是Camera節點,所以 osg::Camera* hudCamera = createHUD(); // set up cameras to render on the first window available. hudCamera->setGraphicsContext(windows[0]); hudCamera->setViewport (0,0,windows[0]->getTraits()->width, windows[0]->getTraits()->height); viewer.addSlave(hudCamera, false); 把相機設置了響應的圖形上下文,作為一個附屬相機添加 到viewer中。 第二種、這里的相機有事一個節點, group->addChild(createHUD()); 作為一個節點添加中場景中。 這里還有兩個類: SnapImage* postDrawCallback = new SnapImage("PostDrawCallback.png"); viewer.getCamera()->setPostDrawCallback(postDrawCallback); viewer.addEventHandler(new SnapeImageHandler('p',postDrawCallback)); SnapImage* finalDrawCallback = new SnapImage("FinalDrawCallback.png"); viewer.getCamera()->setFinalDrawCallback(finalDrawCallback); viewer.addEventHandler(new SnapeImageHandler('f',finalDrawCallback)); 用於把HUD內容寫出來,這里需要說明的是setPreDrawCallback、setPostDrawCallback、 setFinalDrawCallback相機在繪制中有三次的回調,回之前,繪制后,最后,在 RenderStage::draw函數中被調用。
作者:yungis 發表於2013/3/25 7:29:24
原文鏈接
閱讀:831 評論:0
查看評論
|
[原]osghangglide例子 |
這個例子主要模擬了飛機視角的操作器,繪制了一些必要的場景。 從createModel開始,ClearNode是這樣的一個節點,清除顏色和深度緩沖區,並且設 置“RenderBin”為-1。(關於RenderBin之前的例子中有說明)通過setRequiresClear設置清除顏色是否可用。這個節點比場景中的其 他節點先繪制。在CullVisitor中的CullVisitor::apply(osg::ClearNode& node)使用,也就是 說每一幀都調用這個函數清空顏色和深度緩沖。 Transform是變換的基類,MoveEarthySkyWithEyePointTransform繼承Transform實現場景跟着鼠 標的變換。重寫了computeLocalToWorldMatrix和computeWorldToLocalMatrix,這里用了 getEyeLocal()這個函數獲取當前的視點坐標,進入CullStack這個函數,看看這里面有存儲了當 前場景很多數據, inline osg::Viewport* getViewport(); inline osg::RefMatrix* getModelViewMatrix(); inline osg::RefMatrix* getProjectionMatrix(); inline osg::Matrix getWindowMatrix(); inline const osg::RefMatrix* getMVPW(); inline const osg::Vec3& getEyeLocal() const { return _eyePointStack.back(); } inline const osg::Vec3& getViewPointLocal() const { return _viewPointStack.back(); } 模型矩陣、投影矩陣、MVPW矩陣等等。相機是CullStack的孫子節點,因此說相機也有這些方法 可用。 例子之后構建了一顆模型樹。 makeSky()繪制天空,RenderBin設置-2,makeBase()設置-1,makeTrees()繪制樹, makeTerrain()繪制地形,makeTank()繪制坦克。 最后viewer.setCameraManipulator(new GliderManipulator());設置了GliderManipulator這個 操作器,寫自己的操作器需要繼承CameraManipulator,主要重寫getInverseMatrix這個函數。 這個操作器中的其他函數就不做深入的研究了。
作者:yungis 發表於2013/3/25 7:02:49
原文鏈接
閱讀:493 評論:1
查看評論
|
[原]osggraphicscost例子 |
這個例子比較有用,平均了三維場景CPU和GPU的花費。 進入GraphicsCostEstimator這個類, CostPair estimateCompileCost(const osg::Geometry* geometry) const { return _geometryEstimator->estimateCompileCost(geometry); } CostPair estimateDrawCost (const osg::Geometry* geometry) const { return _geometryEstimator->estimateDrawCost (geometry); } CostPair estimateCompileCost(const osg::Texture* texture) const { return _textureEstimator->estimateCompileCost(texture); } CostPair estimateDrawCost(const osg::Texture* texture) const { return _textureEstimator- >estimateDrawCost(texture); } CostPair estimateCompileCost(const osg::Program* program) const { return _programEstimator->estimateCompileCost(program); } CostPair estimateDrawCost(const osg::Program* program) const { return _programEstimator->estimateDrawCost(program); } CostPair estimateCompileCost (const osg::Node* node) const; CostPair estimateDrawCost(const osg::Node* node) const; 對Geometry、Texture、Program和Node的編譯和繪制都做了評估。 typedef std::pair<double, double> CostPair; 代表CPU和GPU所花的時間。 GraphicsCostEstimator負責評估Geometry、Texture、Program、Node編譯和繪制所用的時間。 CollectCompileCosts這個類是計算時間的類,繼承自osg::NodeVisitor,先來回憶一下 osg::NodeVisitor,它是一個訪問者模式,節點accept它,它就可以通過apply函數實現相應的 功能。NodeCallback就是通過NodeVisitor實現,只是在沒一幀的更新回調中都調用了這個 accept遞歸遍歷。 我們回到這個例子,這個例子統計的時間並不是運行時統計的,而是事先定制好了一些基本的時 間,然后通過Geometry、Texture、Program、Node中的數據量。 看GeometryCostEstimator的setDefaults函數: void GeometryCostEstimator::setDefaults() { double transfer_bandwidth = 10000000000.0; // 1GB/sec double gpu_bandwidth = 50000000000.0; // 50 GB/second double min_time = 0.00001; // 10 nano seconds. _arrayCompileCost.set(min_time, 1.0/transfer_bandwidth, 256); // min time 1/10th of millisecond, min size 256 _primtiveSetCompileCost.set(min_time, 1.0/transfer_bandwidth, 256); // min time 1/10th of millisecond, min size 256 _arrayDrawCost.set(min_time, 1.0/gpu_bandwidth, 256); // min time 1/10th of millisecond, min size 256; _primtiveSetDrawCost.set(min_time, 1.0/gpu_bandwidth, 256); // min time 1/10th of millisecond, min size 256; _displayListCompileConstant = 0.0; _displayListCompileFactor = 10.0; } 通過這些基本的單位時間,計算總體的時間。
作者:yungis 發表於2013/3/24 11:23:19
原文鏈接
閱讀:391 評論:0
查看評論
|
[原]osggpx例子 |
首先來看Track這個類,維護了一個TrackSegment集合。 TrackSegment維護了一個TrackPoint集合。 TrackPoint有經緯高和時間組成,在每一刻能唯一確定位置。 readTrack這個函數讀取了一個gpx后綴的文件。 這個函數中涉及到了osg好些文件操作,osgDB::XmlNode是osg中對xml的處理,返回一個Track。 接下來看createTrackModel這個函數,根據Track繪制了很多線,值得注意的是,這里Track中存 儲是的經緯高,需要通過EllipsoidModel把它轉換到世界坐標,轉換函數 convertLatLongHeightToXYZ,把這些路徑繪制到了地球上。 computeAveragedSpeedTrackSegment、computeSmoothedTrackSegment這兩個函數也很好理解, 在地球上繪制兩點直接的線,可能出現不平滑,地球上弧型的,因此需要在兩點中進行平滑處理。第一個函數根據平均速度。 如果outputFilename不為空,會把這個Track寫出到指定文件中。 這個例子本身並不難,應用了osg中封裝的的xml處理接口,應用了EllipsoidModel這個類,這個 類在編寫數字地球的時候經常用到。
作者:yungis 發表於2013/3/22 6:50:36
原文鏈接
閱讀:530 評論:0
查看評論
|
[原]osggeometryshaders例子 |
SomePoints繼承Geometry,繪制了八個點,關閉了光照,設置點的大小為6. 然后應用的了shader,添加了"u_anim1"這個變量,並且添加了SineAnimation更新回調。 先來看createShader()這個函數,創建Program,添加了頂點着色器、片元着色器和幾何着色器。 幾何着色器介紹: Geometry Shader Tutorials:http://appsrv.cse.cuhk.edu.hk/~ymxie/Geometry_Shader/ Geometry Shader Concepts & Examples: http://www.cnblogs.com/Jedimaster/archive/2007/06/26/796107.html pgm->setParameter( GL_GEOMETRY_VERTICES_OUT_EXT, 4 ); 着色器輸出元素個數 pgm->setParameter( GL_GEOMETRY_INPUT_TYPE_EXT, GL_POINTS );色器輸入元素類型 pgm->setParameter( GL_GEOMETRY_OUTPUT_TYPE_EXT, GL_LINE_STRIP );着色器輸出元素類型 這是幾何着色器擴展支持,輸入的是點,輸出的是線。 在每個着色器中定義"#version 120\n" "#extension GL_EXT_geometry_shader4 : enable\n" 打開幾個着色器 static const char* vertSource = { "#version 120\n" "#extension GL_EXT_geometry_shader4 : enable\n" "uniform float u_anim1;\n" "varying vec4 v_color;\n" "void main(void)\n" "{\n" " v_color = gl_Vertex;\n" " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" "}\n" }; 把點的坐標軸當做顏色傳遞,計算點的位置。 static const char* geomSource = { "#version 120\n" "#extension GL_EXT_geometry_shader4 : enable\n" "uniform float u_anim1;\n" "varying in vec4 v_color[];\n" "varying out vec4 v_color_out;\n" "void main(void)\n" "{\n" " vec4 v = gl_PositionIn[0];\n" " v_color_out = v + v_color[0];\n" "\n" " gl_Position = v + vec4(u_anim1,0.,0.,0.); EmitVertex();\n" " gl_Position = v - vec4(u_anim1,0.,0.,0.); EmitVertex();\n" " EndPrimitive();\n" "\n" " gl_Position = v + vec4(0.,1.0-u_anim1,0.,0.); EmitVertex();\n" " gl_Position = v - vec4(0.,1.0-u_anim1,0.,0.); EmitVertex();\n" " EndPrimitive();\n" "}\n" }; 計算了一下顏色,每兩點作為一條線 static const char* fragSource = { "#version 120\n" "#extension GL_EXT_geometry_shader4 : enable\n" "uniform float u_anim1;\n" "varying vec4 v_color_out;\n" "void main(void)\n" "{\n" " gl_FragColor = v_color_out;\n" "}\n" }; 把最終的顏色寫入gl_framcolor中
作者:yungis 發表於2013/3/22 6:16:15
原文鏈接
閱讀:485 評論:0
查看評論
|