[osg]osgcallback各種回調使用的例子介紹
觀察MyReadFileCallback結構體的內容,可以發現它繼承自osgDB::Registry::ReadFileCallback,並重載了一個函數readNode,分析源代碼可知,該函數在osgDB::readNodeFile函數中被調用,即,在加載模型文件時,即會調用 MyReadFileCallback結構體所重載的readNode函數並執行相應的內容。示例程序中該函數的內容如下:
class MyReadFileCallback : public osgDB::Registry::ReadFileCallback
{
public:
virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options)
{
std::cout<<"before readNode"<<std::endl;
// note when calling the Registry to do the read you have to call readNodeImplementation NOT readNode, as this will
// cause on infinite recusive loop.
osgDB::ReaderWriter::ReadResult result = osgDB::Registry::instance()->readNodeImplementation(fileName,options);
std::cout<<"after readNode"<<std::endl;
return result;
}
};
其中較為重要的是readNodeImplementation一行,這是模型文件讀取的實際執行函數,如果在回調中對於這一語句的使用有錯,那麽模型無論怎樣都不能被加載。
InsertCallbacksVisitor的內容比較復雜,它繼承自osg::NodeVisitor,屬於用戶自定義的節點訪問器。換句話說,當執行到:
InsertCallbacksVisitor icv;
rootnode->accept(icv);
節點訪問器將從根節點rootnode開始,遍歷所有的子節點並執行相應的操作。
節點訪問器InsertCallbacksVisitor的構造函數中,可以傳遞一個遍歷方式的枚舉量TraversalMode ,它的取值意義如下:
TRAVERSE_NONE:僅僅傳遞到當前節點,然後停止傳遞;
TRAVERSE_PARENTS:傳遞給當前節點及其父節點,註意,如果當前節點有不止一個父節點,那麽訪問器將列舉出所有的傳遞路線,其中可能有多個重復出現的節點;
TRAVERSE_ALL_CHILDREN:傳遞給當前節點及其所有子節點,同樣,對於多個子節點的情況,訪問器將列舉所有的傳遞路線;
TRAVERSE_ACTIVE_CHILDREN:傳遞給當前節點及所有被激活的子節點,例如遇到LOD節點和Switch節點時,將不會傳遞給當前無法顯示的子節點。
在節點訪問器中,使用apply函數來實現對各種類型的節點的訪問。當遍歷過程中遇到與某個重載的apply的輸入參數相符合的節點時,將執行這一 apply函數的內容。示例代碼中重載了Node,Geode和Transform節點的訪問函數。在Geode節點的訪問函數中,實現了對場景圖形結構中每個節點的回調指定:
// 指定Geode節點的更新回調。
geode.setUpdateCallback(new UpdateCallback());
// 指定Geode節點中所有關聯幾何體(Drawables)的繪制回調,揀選回調和更新回調。
for(unsigned int i=0;i<geode.getNumDrawables();++i)
{
geode.getDrawable(i)->setUpdateCallback(new DrawableUpdateCallback());
geode.getDrawable(i)->setCullCallback(new DrawableCullCallback());
geode.getDrawable(i)->setDrawCallback(new DrawableDrawCallback());
}
在Geode之外的其它節點的apply函數中,往往包含有下面的語句:
traverse(node);
這表示對場景圖形節點的遍歷將繼續進行。換句話說,如果某種類型的節點的apply函數中不包含這一語句,那麽場景圖形遍歷到這一類型的節點時,當前遍歷的路線將自動結束,以下的子節點均被忽略。而對Geode節點來說,因為不存在子節點,因此也不必添加這一語句。
使用節點訪問器為場景圖形節點或幾何體添加的回調主要有以下幾種:
幾何體繪制遍歷(DrawableDrawCallback):重載函數drawImplementation,當幾何體進行繪制時,函數的內容被調用,註意需要添加Drawable::drawImplementation函數以實現幾何體的實際繪制,否則將無法畫出當前的幾何形狀。可以參閱 include/osg/Drawable,draw函數中的調用過程。
幾何體揀選遍歷(DrawableCullCallback):重載函數cull,當幾何體進行揀選優化時,函數的內容被調用。可以參閱src/osgUtil/CullVisitor,apply(Geode&)函數中的調用過程。
幾何體更新遍歷(DrawableUpdateCallback):重載函數update,當幾何體更新時,函數的內容被調用。可以參閱include/osgUtil/UpdateVisitor,handle_geode_callbacks函數中的調用過程。
揀選遍歷(CullCallBack):重載操作符operator(),當場景執行揀選優化時,operator()的內容被調用,註意需要添加 traverse函數以實現節點的繼續遍歷。可以參閱include/osgUtil /CullVisitor,handle_cull_callbacks_and_traverse函數中的調用過程。
更新遍歷(UpdateCallBack):重載操作符operator(),當場景更新時,operator()的內容被調用,註意需要添加 traverse函數以實現節點的繼續遍歷。可以參閱src/osg/StateSet.cpp,runUpdateCallbacks函數中的調用過程。
最後,觀察CameraUpdateCallback和CameraEventCallback結構體的內容,可以發現它們均繼承自 osg::NodeCallback,並重載了操作符operator(),當執行攝像機更新或者事件回調時,operator()的內容將被調用,添加 traverse函數可以實現節點的繼續遍歷。
此外,還可以使用Node::setEventCallback來設置節點的事件回調,其輸入參數為繼承自osg::NodeCallback的用戶類,且需要重載操作符operator()以實現回調過程的處理。
綜上,可以得出回調的編寫方法:
1、編寫用戶結構體,繼承OSG中相應的虛函數結構體,如osg::NodeCallBack;
2、重載回調執行函數,根據回調種類的不同,執行函數的名稱也不同,可以參考osgcallback中的設置;
3、註意在回調執行的過程中,有一些必要的系統操作需要交由用戶來完成,例如readNodeImplementation,Drawable::drawImplementation,traverse等,否則系統本身的渲染工作可能會不正常。
編譯運行osgcallback之後,可以看到控制臺不斷輸出各種回調的執行結果,用戶可以根據自己的需要在不同的時間段進入不同的回調來完成所需的工作。
[osg]osgcallback各種回調使用的例子介紹