1、場景基本繪圖類
??在 OSG 中創建幾何體的方法比較簡單,通常有 3 種處理幾何體的手段:
- 使用松散封裝的OpenGL 繪圖基元;
- 使用 OSG 中的基本幾何體;
- 從文件中導入場景模型。
??使用松散封裝的OpenGL 繪圖基元繪制幾何體具有很強的靈活性,但工作量通常非常大,當面對大型場景時,繪制幾何體將是一項非常艱巨而富有挑戰的工作,因此,通常還是采用讀入外部模型的方法。
1.1 向量與數組類
??在 OSG 中定義了大量的類來保存數據,數據通常是以向量的形式來表示的,向量數據主要包括頂點坐標、紋理坐標、顏色和法線等。例如,定義 osg::Vec2 來保存紋理坐標;定義 osg::Vec3 來保存頂點坐標和法線坐標;定義 osg::Vec4 保存顏色的 RGBA 值。osg::Vec2、osg::Vec3 和 osg::Vec4 是分別用來保存向量的二維數組、三維數組和四維數組,這些類不僅能夠保存各種數據,還提供了向量的基本運算機制,如加、減、乘、除四則元算、點積和單位化等相關的操作。
??在 OSG 中還定義了模板數組用來保存對象,例如,可以用頂點索引對象(osg::DrawElementsUInt)來保存頂點索引,用顏色索引(osg::TemplateIndexeArray)來保存顏色。但最常用的還是保存向量數據,如 osg::Vec3Array 來保存眾多頂點坐標、osg::Vec2Array 保存紋理坐標等,這些模板數組都繼承自 std::Vector,因此,它們具有向量的基本操作方法,例如,可以利用 push_back()添加一個元素,可以利用pop_back()刪除一個元素,同樣也可以使用 clear()刪除所有的元素。
1.2 Drawable 類
??Drawable 類是一個純基類,無法實例化。作為可繪制對象基類的 osg::Drawable 類,它派生了很多類,它的繼承關系圖如圖 4-1 所示。
??從圖 4-1 可以看出,由 osg::Drawable 派生的類有 9 個,分別是 osg::DrawPixels、osg::Geometry、osg::ShapeDrawable、osgParticle::ParticleSystem、osgParticle::PrecipitationEffect::PrecipitationDrawable、osgShadow::OccluderGeometry、osgShadow::ShadowVolumeGeometry、osgSim::ImpostorSprite 和 osgText::TextBase,其中,從 OSG 核心庫派生出了 3 個類,分別是 osg::DrawPiexels 類(主要封裝了 OpenGL中 glDrawPixels()的功能)、osg::Geometry 類(繪制幾何體的類,應用比較靈活)和 osg::ShapeDrawable類(主要封裝了一些已經定義好的幾何體,不需要設置坐標即可直接調用,如長方體、正方體、球體
等)。其他的類中,有兩個派生自粒子系統庫,有兩個派生自陰影庫,還有兩個分別派生自 osgSim 庫和 osgText 文字庫。
1.3 PrimitiveSet 類
??osg::PrimitiveSet 類繼承自 osg::Object 虛基類,但它不具備一般場景中的特性。osg::PrimitiveSet 類的繼承關系圖如圖 4-2 所示。
??該類主要松散封裝了 OpenGL 的繪圖基元,通過指定繪圖基元來指定幾何體頂點將采用哪一種或幾種基元繪制。常用的繪圖基元包括如下幾種:
POINTS = GL_POINTS //繪制點
LINES = GL_LINES //繪制線
LINE_STRIP = GL_LINE_STRIP //繪制多段線
LINE_LOOP = GL_LINE_LOOP //繪制封閉線
TRIANGLES = GL_TRIANGLES //繪制一系列的三角形(不共用頂點)
TRIANGLE_STRIP = GL_TRIANGLE_STRIP //繪制一系列三角形(共用后面的兩個頂點)
TRIANGLE_FAN = GL_TRIANGLE_FAN //繪制一系列三角形,頂點順序與上一條語句繪制的三角形不同
QUADS = GL_QUADS //繪制四邊形
QUAD_STRIP = GL_QUAD_STRIP //繪制一系列四邊形
POLYGON = GL_POLYGON //繪制多邊形
從 osg::PrimitiveSet 類的繼承關系圖可以看出,它的派生類主要有如下 3 個:
- osg::DrawArrays 類。繼承自 osg::PrimitiveSet,它封裝了glDrawArrays()頂點數組繪圖命令,用于指定頂點和繪圖基元。
- osg::DrawElements 類。它又派生出 3 個子類,分別是 osg::DrawElementsUByte、osg::DrawElementsUShort和osg::DrawElementsUInt,封裝了 glDrawElements()的指令,可以起索引的作用,在后面的示例中會用到。
- osg::DrawArrayLengths 類。它的主要作用是多次繪制,即多次調用glDrawArrays(),且每次均使用不同的長度和索引范圍,在繪制過程中用得不是很多。
DrawArrays 的基本用法如下:
osg::DrawArrays::DrawArrays( GLenum mode, GLint first,GLsizei count );
/*參數說明:第一個參數是指定的繪圖基元,即前面所列舉的常見繪圖基元;第二個參數是指繪制幾何體的第一個
頂點數在指定頂點的位置數;第三個參數是使用的頂點的總數*/
??還有一點值得注意的是,雖然 osg::PrimitiveSet 類提供與 OpenGL 一樣的頂點機制,但是在內部渲染上還是有一定區別的。根據渲染環境的不同,渲染的方式也是不一樣的,可能會采用頂點、頂點數組、顯示列表或者 glBegin()/glEnd()來渲染幾何體,繼承自 Drawable 類的對象(如 Geometry)在默認條件下將使用顯示列表。其中,osg::Drawable::setUseDisplayList(false)用于手動禁止使用顯示列表。還有一種比較特殊的情況,如果設置BIND_PER_PRIMITIVE 綁定方式,那么OSG將采用glBegin()/glEnd()函數進行渲染。因為在設置使用綁定方式為 BIND_PER_PRIMITIVE 后,它就為每個獨立的幾何圖元設置一種綁定屬性。
2、基本幾何體的繪制
??OSG 創建的場景和對象是由簡單的圖元(我們把構成 3D 對象的構件稱為圖元)按照一定的方式排列和組合而成的,OSG 中的所有圖元都是一維或二維對象,包括單個的點、直線和復雜的多邊形。
2.1 幾何體類 osg::Geometry
??它的主要作用是對指定繪制幾何體的頂點數及對數據的解析,主要提供了如下 3大類方法:
1)指定向量數據。就是以前所涉及的頂點數據、紋理坐標及顏色等一系列向量數據,可以通過下面的幾個函數來實現:
void setVertexArray(Array*array) //設置頂點數組
void setVertexData(const ArrayData&arrayData) //設置頂點數組數據
void setVertexIndices(IndexArray*array) //設置頂點索引數組
void setNormalArray(Array*array) //設置法線數組
void setNormalData(const ArrayData&arrayData) //設置法線數組數據
void setNormalIndices(IndexArray*array) //設置法線索引數組
void setColorArray(Array*array) //設置顏色數組
void setColorData(const ArrayData&arrayData) //設置顏色數組數據
void setColorIndices(IndexArray*array) //設置顏色索引數組
void setTexCoordArray(unsigned int unit,Array*)
//設置紋理坐標數組,第一個參數是紋理單元,第二個是紋理坐標數組
void setTexCoordData(unsigned int index, const ArrayData &arrayData)
//設置紋理坐標數組數據,第一個參數是紋理單元,第二個是紋理坐標數組數據
void setTexCoordIndices(unsigned int unit, IndexArray *)
//設置紋理坐標索引數組,第一個參數是紋理單元,第二個是紋理索引坐標數組
2)設置綁定方式。數據綁定主要有兩項,即法線及顏色,可以通過下面的兩個函數來實現:
void setNormalBinding(AttributeBinding ab) //設置法線綁定方式
void setColorBinding(AttributeBinding ab) //設置顏色綁定方式
綁定方式主要有下面幾種:
BIND_OFF //不啟用綁定
BIND_OVERALL //綁定全部的頂點
BIND_PER_PRIMITIVE_SET //單個繪圖基元綁定
BIND_PER_PRIMITIVE //單個獨立的繪圖基元綁定
BIND_PER_VERTEX //單個頂點綁定
3)數據解析。當在指定了各種向量數據和綁定方式之后,采用何種方式來渲染幾何體就是最為關鍵的。不同的方式下,渲染出來的圖形是不一樣的,即使效果一樣,可能面數或內部機制等也是有區別的。數據解析主要通過如下函數來指定:
bool addPrimitiveSet(PrimitiveSet*primitiveset)
/*參數說明:osg::PrimitiveSet 是無法初始化的虛基類,因此這里主要是調用它的子類來指定數據渲染,最常用的就是
前面介紹的 osg::DrawArrays,用法比較簡單,初始化一個對象實例,參數說明見前面 osg::DrawArrays 類*/
通過前面的講述可知,繪制并渲染幾何體主要有如下 3 大步驟:
1)創建各種向量數據,如頂點、紋理坐標、顏色和法線等。需要注意的是,添加頂點數據時主要按照逆時針順序添加,以確保背面剔除(backface culling)的正確(后面還會有介紹)。
2)實例化一個幾何體對象(osg::Geometry),設置頂點坐標數組、紋理坐標數組、顏色數組、法線數組、綁定方式及數據解析。
3)加入葉節點繪制并渲染。
2.2 示例
2.3 示例源碼
#include <osgViewer/Viewer>#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>#include <osgDB/ReadFile>
#include <osgDB/WriteFile>#include <osgUtil/Optimizer>#include <osgViewer/ViewerEventHandlers> //事件監聽
#include <osgGA/StateSetManipulator> //事件響應類,對渲染狀態進行控制#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")//創建一個四邊形節點
osg::ref_ptr<osg::Node> createQuad()
{//創建一個葉節點對象osg::ref_ptr<osg::Geode> geode = new osg::Geode();//創建一個幾何體對象osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();//創建頂點數組osg::ref_ptr<osg::Vec3Array> aryVertex = new osg::Vec3Array();//添加數據aryVertex->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));aryVertex->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));aryVertex->push_back(osg::Vec3(1.0f, 0.0f, 1.0f));aryVertex->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));aryVertex->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));//設置頂點數據geom->setVertexArray(aryVertex.get());//創建四邊形頂點索引數組,指定繪圖基元為四邊形,注意添加順序osg::ref_ptr<osg::DrawElementsUInt> quad = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0);//添加數據quad->push_back(0);quad->push_back(1);quad->push_back(2);quad->push_back(3);//添加到幾何體geom->addPrimitiveSet(quad.get());//創建三角形頂點索引數組,指定繪圖基元為三角形,注意添加順序osg::ref_ptr<osg::DrawElementsUInt> triangle = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, 0);//添加數據triangle->push_back(4);triangle->push_back(0);triangle->push_back(3);//添加到幾何體geom->addPrimitiveSet(triangle.get());//創建顏色數組osg::ref_ptr<osg::Vec4Array> vecColor = new osg::Vec4Array();//添加數據vecColor->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));vecColor->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));vecColor->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));vecColor->push_back(osg::Vec4(1.0f, 1.0f, 0.0f, 1.0f));vecColor->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));//設置顏色數組geom->setColorArray(vecColor.get());//創建顏色索引數組//osg::TemplateIndexArray<unsigned int ,osg::Array::UIntArrayType,4,4>* colorIndex = new osg::TemplateIndexArray<unsigned int ,osg::Array::UIntArrayType,4,4>();//添加數據,注意添加數據順序與頂點一一對應//colorIndex->push_back(0);//colorIndex->push_back(1);//colorIndex->push_back(2);//colorIndex->push_back(3);//colorIndex->push_back(2);//設置顏色索引數組//geom->setColorIndices(colorIndex);//設置顏色的綁定方式為單個頂點geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);//創建法線數組osg::ref_ptr<osg::Vec3Array> vecNormal = new osg::Vec3Array();//添加法線vecNormal->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));//設置法線數組geom->setNormalArray(vecNormal.get());//設置法線的綁定方式為全部頂點geom->setNormalBinding(osg::Geometry::BIND_OVERALL);//添加到葉節點geode->addDrawable(geom.get());return geode.get();
}int main()
{//創建Viewer對象,場景瀏覽器osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();osg::ref_ptr<osg::Group> root = new osg::Group();//添加到場景root->addChild(createQuad());//優化場景數據osgUtil::Optimizer optimizer;optimizer.optimize(root.get());viewer->setSceneData(root.get());//切換網格模式,方便比較viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));viewer->addEventHandler(new osgViewer::StatsHandler());//實現狀態信息統計viewer->addEventHandler(new osgViewer::WindowSizeHandler());viewer->setUpViewInWindow(400,400,1000,800);viewer->run();return 0;
}
3、OSG預定義幾何體
3.1 osg::Shape 類
??osg::Shape 類直接繼承自 osg::Object 基類,繼承關系圖如圖 4-6 所示。
??osg::Shape 類是各種內嵌幾何體的基類,它不但可用于剔除和碰撞檢測,還可用于生成預定義的幾何體對象。常用的內嵌幾何體包括如下幾種:
osg::Box //正方體
osg::Capsule //太空艙
osg::Cone //椎體
osg::Cylinder //柱體
osg::HeightField //高度圖
osg::InfinitePlane //無限平面
osg::Sphere //球體
osg::TriangleMesh //三角片
3.2 osg::ShapeDrawable 類
??在 OSG 中內嵌預定義的幾何體,如果渲染這些內嵌的幾何體,就必須將其與 osg::Drawable 關聯。實際應用中,可以使用 osg::Drawable 類的派生類 osg::ShapeDrawable來完成這個功能。osg::ShapeDrawable 類在前面已經講到,它派生自osg::Drawable 類。由于它繼承自 osg::Drawable 類,所以它的實例需要被添加到葉節點中才能被實例繪制。
在 osg::ShapeDrawable 類的構造函數中提供了關聯 osg::Shape 的方法:
ShapeDrawable(Shape*shape, TessellationHints *hints=0)
//第一個參數為 shape,第二個參數默認下不細化
3.3 網格化類
??網格化類(osg::TessellationHints)直接繼承自 osg::Object 基類。osg::TessellationHints 類的主要作用是設置預定義幾何體對象的精細程度,精細程度越高,表示其細分越詳細,但對于不同的預定義幾何體對象它的作用是不一樣的,例如:
Box(四棱柱):網格化類對于四棱柱沒有意義。Capsule(太空艙):太空艙分 3 個部分,上下半球部分和圓柱側面部分,默認圓柱側面被細分。Cone(圓錐):直接細分。Cylinder(柱體):直接細分。Sphere(球):直接細分。
目前,osg::TessellationHints 類并不完整,部分類成員函數還沒有實現,具體可以參看源碼。在內嵌幾何體對象中,默認的情況下,網格化類的精細度為 0,表示預定義的幾何體此時按照原頂點默認繪制,不做任何細化處理。
3.4 示例
3.5 示例源碼
#include <windows.h>#include <osgViewer/Viewer>
#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/Switch>
#include <osg/Billboard>
#include <osg/Texture2D>
#include <osg/Image>
#include <osg/Vec3>
#include <osg/Vec2>
#include <osg/PositionAttitudeTransform>
#include <osg/MatrixTransform>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgUtil/Optimizer>
#include <osg/PagedLOD>
#include <osgSim/Impostor>
#include <osgViewer/ViewerEventHandlers> //事件監聽
#include <osgGA/StateSetManipulator> //事件響應類,對渲染狀態進行控制
#include <osgUtil/Simplifier> //簡化幾何體
#include <osg/OccluderNode>
#include <osg/StateSet>
#include <osg/ConvexPlanarOccluder>
#include <osg/BoundingBox>
#include <osg/BoundingSphere>
#include <osgUtil/Optimizer>
#include <iostream>
#include <osg/ShapeDrawable>#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")
#pragma comment(lib, "osgSimd.lib")
#pragma comment(lib, "osgFXd.lib")//繪制多個預定義的幾何體
osg::ref_ptr<osg::Geode> createShape()
{//創建一個葉節點osg::ref_ptr<osg::Geode> geode = new osg::Geode();//設置半徑和高度float radius = 0.8f;float height = 1.0f;//創建精細度對象,精細度越高,細分就越多osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints;//設置精細度為 0.5fhints->setDetailRatio(0.5f);//添加一個球體,第一個參數是預定義幾何體對象,第二個是精細度,默認為 0geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f, 0.0f, 0.0f), radius), hints.get()));//添加一個正方體geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(2.0f, 0.0f, 0.0f), 2 * radius), hints.get()));//添加一個圓錐geode->addDrawable(new osg::ShapeDrawable(new osg::Cone(osg::Vec3(4.0f, 0.0f, 0.0f), radius, height), hints.get()));//添加一個圓柱體geode->addDrawable(new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(6.0f, 0.0f, 0.0f), radius, height),hints.get()));//添加一個太空艙geode->addDrawable(new osg::ShapeDrawable(new osg::Capsule(osg::Vec3(8.0f, 0.0f, 0.0f), radius, height),hints.get()));return geode.get();
}int main()
{//創建Viewer對象,場景瀏覽器osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();osg::ref_ptr<osg::Group> root = new osg::Group();//添加到場景root->addChild(createShape());//優化場景數據osgUtil::Optimizer optimizer;optimizer.optimize(root.get());viewer->setSceneData(root.get());//切換網格模式,方便比較viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));viewer->addEventHandler(new osgViewer::StatsHandler());//實現狀態信息統計viewer->addEventHandler(new osgViewer::WindowSizeHandler());viewer->setUpViewInWindow(400,400,1000,800);viewer->run();return 0;
}
4、多邊形分格化
4.1 定義
??如果讀者對 OpenGL 有一定了解的話,應該知道 OpenGL 為了快速渲染多邊形,只能直接顯示簡單的凸多邊形。所謂簡單的凸多邊形,就是多邊形上任意兩點的連線上的點依屬于該多邊形。對凹多邊形或者自交叉多邊形的渲染結果將不確定。下面列舉一些需要分格化的多邊形,如圖 4-10 所示。
??為了正確顯示凹多邊形或者自交叉多邊形,就必須把它們分解為簡單的凸多邊形,這種做法就稱為多邊形的分格化。OSG 是對底層 OpenGL API 的封裝,所以它同樣只能直接顯示簡單的凸多邊形,對于凹多邊形或者自交叉多邊形,渲染也是不確定的。
??在 OSG 中提供了一個多邊形分格化的類 osgUtil::Tessellator,它繼承自 osg::Referenced 類,繼承關系圖如圖 4-11 所示。
在 OSG 中進行多邊形分格化渲染需要如下 3 個步驟:
(1)創建多邊形分格化對象。
(2)設置分格化對象的類型,通常有下面 3 種類型:
TESS_TYPE_GEOMETRY, //分格化幾何體
TESS_TYPE_DRAWABLE, //分格化幾何體中的 Drawable(如多邊形、三角形、四邊形等)
TESS_TYPE_POLYGONS //只分格化幾何體中的多邊形
(3)根據計算的環繞數指定相應的環繞規則。
1.環繞數
在《OpenGL 編程指南》第 5 版中曾指出“對于一條簡單的輪廓線,每個點的環繞數就是環繞這個點的所有輪廓線的代數和(用一個有符號的整數表示,求和規則是:逆時針環繞的輪廓線為正,順時針環繞的輪廓線為負)。這個過程把一個有符號的整數數值與平面上的每個頂點相關聯。注意,對于區域中的所有點,它們的環繞數都是相同的”。圖 4-12 為輪廓線與環繞數的計算方法,讀者可以通過此圖理解環繞數及如何計算環繞數。
2.環繞規則
如果一個區域的環繞數屬于環繞規則所選擇的類型,那么它就是它的內部區域。通常,環繞規則把具有奇數和非零環繞數的區域定義為內部區域。環繞規則主要是針對環繞數來確定的。
幾種常用的環繞規則如下:
TESS_WINDING_ODD=GLU_TESS_WINDING_ODD //環繞數為奇數
TESS_WINDING_NONZERO=GLU_TESS_WINDING_NONZERO //環繞數為非零數
TESS_WINDING_POSITIVE=GLU_TESS_WINDING_POSITIVE //環繞數為正數
TESS_WINDING_NEGATIVE=GLU_TESS_WINDING_NEGATIVE //環繞數為負數
TESS_WINDING_ABS_GEQ_TWO=GLU_TESS_WINDING_ABS_GEQ_TWO //環繞數為絕對值大于或等于 2
4.2 示例
4.3 示例源碼
#include <windows.h>#include <osgViewer/Viewer>
#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/Switch>
#include <osg/Billboard>
#include <osg/Texture2D>
#include <osg/Image>
#include <osg/Vec3>
#include <osg/Vec2>
#include <osg/PositionAttitudeTransform>
#include <osg/MatrixTransform>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgUtil/Optimizer>
#include <osg/PagedLOD>
#include <osgSim/Impostor>
#include <osgViewer/ViewerEventHandlers> //事件監聽
#include <osgGA/StateSetManipulator> //事件響應類,對渲染狀態進行控制
#include <osgUtil/Simplifier> //簡化幾何體
#include <osg/OccluderNode>
#include <osg/StateSet>
#include <osg/ConvexPlanarOccluder>
#include <osg/BoundingBox>
#include <osg/BoundingSphere>
#include <osgUtil/Optimizer>
#include <iostream>
#include <osg/ShapeDrawable>
#include <osgUtil/Tessellator>#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")
#pragma comment(lib, "osgSimd.lib")
#pragma comment(lib, "osgFXd.lib")//使用分格化繪制凹多邊形
osg::ref_ptr<osg::Geode> tesslatorGeometry()
{osg::ref_ptr<osg::Geode> geode = new osg::Geode();osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();geode->addDrawable(geom.get());//以下是一些頂點數據//墻const float wall[5][3] ={ { 2200.0f, 0.0f, 1130.0f },{ 2600.0f, 0.0f, 1130.0f },{ 2600.0f, 0.0f, 1340.0f },{ 2400.0f, 0.0f, 1440.0f },{ 2200.0f, 0.0f, 1340.0f } };//門const float door[4][3] ={ { 2360.0f, 0.0f, 1130.0f },{ 2440.0f, 0.0f, 1130.0f },{ 2440.0f, 0.0f, 1230.0f },{ 2360.0f, 0.0f, 1230.0f } };//四扇窗戶const float windows[16][3] ={ { 2240.0f, 0.0f, 1180.0f },{ 2330.0f, 0.0f,1180.0f },{ 2330.0f, 0.0f, 1220.0f },{ 2240.0f, 0.0f, 1220.0f },{ 2460.0f, 0.0f, 1180.0f },{ 2560.0f, 0.0f, 1180.0f },{ 2560.0f, 0.0f, 1220.0f },{ 2460.0f, 0.0f, 1220.0f },{ 2240.0f, 0.0f, 1280.0f },{ 2330.0f, 0.0f, 1280.0f },{ 2330.0f, 0.0f, 1320.0f },{ 2240.0f, 0.0f, 1320.0f },{ 2460.0f, 0.0f, 1280.0f },{ 2560.0f, 0.0f, 1280.0f },{ 2560.0f, 0.0f, 1320.0f },{ 2460.0f, 0.0f, 1320.0f } };//設置頂點數據osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array();geom->setVertexArray(coords.get());//設置法線osg::ref_ptr<osg::Vec3Array> normal = new osg::Vec3Array();normal->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));geom->setNormalArray(normal.get());geom->setNormalBinding(osg::Geometry::BIND_OVERALL);//添加墻for (int i = 0; i < 5; i++){coords->push_back(osg::Vec3(wall[i][0], wall[i][1], wall[i][2]));}geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POLYGON, 0, 5));//添加門for (int i = 0; i < 4; i++){coords->push_back(osg::Vec3(door[i][0], door[i][1], door[i][2]));}//添加窗for (int i = 0; i < 16; i++){coords->push_back(osg::Vec3(windows[i][0], windows[i][1], windows[i][2]));}geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 5, 20));//創建分格化對象osg::ref_ptr<osgUtil::Tessellator> tscx = new osgUtil::Tessellator();//設置分格類型為幾何體tscx->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);//設置只顯示輪廓線為 false,這里還需要填充tscx->setBoundaryOnly(false);//設置環繞規則tscx->setWindingType(osgUtil::Tessellator::TESS_WINDING_ODD);//使用分格化tscx->retessellatePolygons(*(geom.get()));return geode.get();
}int main()
{//創建Viewer對象,場景瀏覽器osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();osg::ref_ptr<osg::Group> root = new osg::Group();//添加到場景root->addChild(tesslatorGeometry());//優化場景數據osgUtil::Optimizer optimizer;optimizer.optimize(root.get());viewer->setSceneData(root.get());//切換網格模式,方便比較viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));viewer->addEventHandler(new osgViewer::StatsHandler());//實現狀態信息統計viewer->addEventHandler(new osgViewer::WindowSizeHandler());viewer->setUpViewInWindow(400,400,1000,800);viewer->run();return 0;
}