LINK:
http://cg.cnblogs.com/default.aspx?page=6&paging=1 http://bbs.vrchina.net/viewthread.php?tid=3472osgFX - 開發者簡明手冊
Marco Jez
2003年9月
osgFX是一個OpenSceneGraph的附加庫,是一個用于實現一致、完備、可重用的特殊效果的構架工具,其效果可以添加到OSG的節點中。它同時還包含了一系列預定義好的特殊效果。
osgFX概述
所謂“特效”指的是裝載于單個對象中的一系列可視的屬性和行為。要實現一個真正可用的特效,相應的特效類應當具備一個公有的接口,以修改各種配置和微調量。
特效也可以被理解成是提出問題(對象應當是什么樣子)與解決問題(應當設置哪些屬性和其它調節量)之間的“橋梁”。從C++代碼來看,特效具現了osgFX::Effect類的實例?;蛘哒f,是這個類的派生類的實例,因為osgFX::Effect直接派生自osg::Node,因此它是抽象類。
對于OSG而言,特效就是一個Node節點。它與其它節點類的特性完全相同,因此可以關聯到場景圖形中的任意位置。
特效功能圖如圖1所示。
Effect類是一個多子節點的組節點。它使用addChild()方法和其它節點關聯。
在特效類中設置的可視屬性將被關聯到它的子節點上,與此相類似,Transform節點也會將坐標變換的信息應用到其子節點上。Effect中的各種屬性不會在其子節點以外生效。
如果用戶想要將某一種特效應用到自己的圖形子樹上,那么需要遵循下面的步驟:
1、創建所需特效的實例,例如,osgFX::Scribe;
2、必要的話,使用特效類的方法設置特效屬性;
3、調用Effect::addChild()方法,將圖形子樹與特效節點相關聯;
4、將特效節點與場景圖形關聯。
下面的例子中使用了刻線(scribe)特效:
osg::ref_ptr<osg::Node> my_node = osgDB::readNodeFile(“cow.osg”);
osg::ref_ptr<osgFX::Scribe> scribe_fx = new osgFX::Scribe;
scribe_fx->addChild(my_node.get());
scribe_fx->setEnabled(true);
root->addChild(scribe_fx.get());
代碼執行的結果如圖2所示。
深入學習:技法和通道
技法就是實現特效的某一種可能方法。
由于圖形硬件設備種類繁多,OpenGL也在不斷擴展,因此不太可能用一種通用的方法來實現復雜的效果:針對不同的硬件和OpenGL環境,用戶需要采用不同的實現手段來實現某個特效。
一種特效的產生往往可以采用一種或幾種技法,每一種技法都采用不同的方式來嘗試實現相同的效果。
缺省情況下,Effect類使用私有的StateAttribute對象來實時演算和驗證各種技法,并選擇最好的一種。
特效的開發者可以自行定義各種技法的優先級,從而要求OSG首先驗證用戶所選的技法。
Effect類會選擇在實時的所有活動渲染設備中,可通過驗證的優先級最高的技法,以為己用。
如果需要的話,用戶可以在任何時刻重載這一缺省特性。
Effect類的技法功能圖表如圖3所示。
多通道渲染的意思是,每次都使用不同的可視屬性,多次繪制同一對象后,合并所有通道獲得的最終圖像。
某些技法可能需要不止一個通道來實現所需的輸出結果。
技法類為每個渲染通道都創建一個StateSet對象,然后交由osgFX管理多通道的渲染工作。
Effect類的通道功能圖表如圖4所示。
擴展osgFX
創建一個新的特效的基本步驟如下。
1、特效都是從osgFX::Effect派生而來的,因此用戶可以自由創建自己的派生類,例如命名它為TestFx。
2、具現抽象方法,例如effectName(),effectDescription()等,可能需要用到META_Effect宏。
3、向系統注冊新的特效類,即創建一個Registry::Proxy的靜態實例:
osgFX::Registry::Proxy proxy(new TestFx);
4、具現保護成員中的抽象方法define_techniques(),以便創建所需的特效技法。
為了實現某個技法,用戶需要編寫一個繼承自osgFX::Technique的類;且這個類應當是私有的。
在用戶特效類的define_techniques()方法中,創建上述用戶技法類的實例,并使用Effect::addTechnique()按照優先級降序的順序將其添加到特效類中。
為新建的技法提供一個驗證手段。最簡單(但不是最靈活的)的方法是重載Technique::getRequiredExtensions()方法,并指定這個技法所需的OpenGL擴展函數。
具現Technique::define_passes()方法,以便創建渲染通道。
渲染通道的內部實現,是將其作為一個Group對象與一個StateSet相關聯。特效類的子節點在運行時將自動被添加到通道節點上。
技法類的define_passes()方法為每個渲染通道創建了一個StateSet對象,并調用Technique::addPass()將其添加到技法類中。通道節點將自動生成并連接到渲染狀態之上。
以下為創建一個特效類所需的基本代碼:
Class TestFX (public)
{
……
META_Effect(……);
bool define_techniques()
{
addTechnique(new FirstTechnique);
// 也可以繼續添加別的技法實例。
}
……
}
Class FirstTechnique (private)
{
……
void getRequiredExtensions(……) const
{
// 指定所需的GL擴展功能。
}
void define_passes()
{
osg::ref_ptr<osg::StateSet> ss1 = new osg::StateSet;
// 添加渲染屬性到ss1之后……
addPass(ss1.get());
osg::ref_ptr<osg::StateSet> ss2 = new osg::StateSet;
// 添加渲染屬性到ss2之后……
addPass(ss2.get());
}
……
}
總結:
1、繼承osgFX::Effect并創建特效類(例如TestFx),為其添加名字和描述信息,并使用注冊代理(registry proxy)注冊到系統中;
2、為用戶所需的每個技法創建私有類,并定義它們的驗證手段;
3、在TestFx::define_techniques()中創建一個技法類的實例,并調用addTechnique()將其添加到特效中;
4、在每個技法類的define_passes()方法中,創建一個或多個StateSet對象(每個渲染通道創建一個),并調用addPass()將其添加到技法中。例子程序
osgfxbrowser的效果如圖5~8所示。對于目前已提供的特效,簡介如下:
刻線(Scribe)
這是一個雙通道的特效;第一個通道以通常的方式渲染圖形,而第二個通道使用線框模式,用戶設置好光照和材質之后,即可使用指定的顏色進行渲染。這個特效中使用了PolygonOffset渲染屬性類來避免多邊形斑駁(Z-fighting)的現象,它所需的OpenGL版本至少為1.1。各向異性光照(Anisotropic Lighting)
這種特效使用單一通道,它使用了一種各向異性的光照來替代OpenGL的標準光照模型。幾何體頂點的顏色在這里不是直接進行計算的,而是紋理映射到用戶指定的光照圖板的結果。這里需要使用頂點著色器(vertex program)來計算紋理坐標S和T的值:S = N · H;T = N · L。(其中的數學運算為點乘)這里N表示頂點的法線,L表示光到頂點的向量,H表示中間向量。這種特效很好地演示了State::getInitialViewMatrix()方法的使用,它可以直接獲取視口的初始矩陣并實現直接與視口相關的特效,而不需要任何假借的工作。
該特效需要ARB_vertex_program擴展的支持。
卡通渲染(Cartoon)
這種特效實現了一種名為卡通著色(Cel-Shading)的技法,從而產生一種卡通式的(非真實感的)的渲染效果。它需要兩個通道支持;第一個用于繪制實體表面,第二個用于繪制輪廓線。該特效需要使用頂點著色器來設置紋理坐標,以便在運行時生成的紋理單元0上實現一種尖銳的光照效果。
該特效需要ARB_vertex_program擴展或者OpenGL著色語言的支持。
基于立方映射圖的鏡面高光(Cubemap-based Specular Highlights)
這種特效在片斷層級(fragment level)上(而不是OpenGL通常的頂點層級)應用了鏡面高光,它使用了立方映射圖和反射紋理生成(reflective texgen)的技術。首先要計算出紋理矩陣以實現立方映射圖的自動旋轉;這樣無論從觀察的方向和光照位置上來說,鏡面光的效果都將是始終不變的。用戶可以選擇使用何種光照來計算紋理矩陣。
該特效需要GL_ARB_texture_env_add擴展以及任意一種立方映射圖擴展(GL_EXT_texture_cube_map,GL_ARB_texture_cube_map,或者OpenGL 1.3)的支持。
凹凸貼圖(Bump Mapping)
這種特效可以創建一種凹凸不平的表面效果。其子節點必須使用兩種紋理,其一是漫反射顏色,另一個是法線貼圖(可以使用nVIDIA的法線貼圖生成器或者其它工具,根據高度圖自動生成)。此外,還需要創建正切空間(tangent-space)的基向量并將其關聯到每個Geometry幾何體上;這一步驟可以調用BumpMapping::prepareChildren()方法來迅速完成。注意Geometry對象的漫反射顏色和法線貼圖紋理都必須提前定義好對應的UV貼圖。
該特效推薦使用一種運用了ARB頂點和片斷著色器的技法,另外還定義了一種不使用片斷著色器的技法。后者無法處理環境和鏡面組件的運算,因此在運行時很受限制。