osg實例介紹


 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:perator () (osg::GraphicsContext* context)
{  
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  查看評論


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM