|
Ogre:: MeshManager 基類存在著幾個基本幾何體的創建方法,包括:
createPlane // 創建平面 createCurvedIllusionPlane // 創建"看上去彎曲"的平面(天空盒和天空穹用的就是這種技術) createCurvedPlane // 創建真正彎曲的"平面" createBezierPatch // 創建貝塞爾曲面 createPrefabPlane // 創建預製平面
這一節是關於貝塞爾曲面 ( BezierPatch ) :
貝塞爾曲面是一種基於少量幾個控制點 ( ControlPoint ) 創建的一個連續的平滑曲面,不管這些控制點的位置如何變化,它總能通過貝塞爾算法自動調整整個曲面的曲率使它總是保持連續和平滑,這是一種非常優美的曲麵類型。同時,貝塞爾曲面還可以通過增加或減少細分層次 (SubdivisionLevel) 來使整個曲面趨向於更平滑更細緻,或是趨向於更"粗獷"。在上面的截圖中,你可以看到整個曲面被細分成大量的網格,從而使它的外觀顯得非常平滑,但是實際上,它只存在 9 個控制點。也就是說,我們只需要定義 9 個控制點的數據,就能夠自動生成這麼平滑、有著大量網格的曲面,這比我們一個頂點一個頂點一個網格一個網格地定義這個曲面模型,顯然要更省力、更省空間。這一點,很像平面設計中,位圖和矢量圖的區別——逐點定義與控制點定義的區別。
創建貝塞爾曲面需要以下步驟:
1. 定義一個控制點的頂點數據結構,這點很像 DirectX 裡定義靈活頂點格式 (FVF: Flexible Vertex Format) ,定義一個頂點類型的結構體: // 定義曲面控制點的頂點結構 struct PatchVertex { Real x, y, z; // 控制點的位置向量 Real nx, ny, nz; // 控制點的法線向量 Real u, v; // 控制點的材質坐標 };
2. 上面雖然定義了一個頂點結構體,但是 OGRE 並不知道這個結構體中的每一組數據各自代表著什麼,不知道每一組數據的用途,所以緊接著,我們需要創建一個頂點聲明 ( VertexDeclaration ) 來告訴 OGRE 每組數據的含義或用途,具體步驟如下:
(1) 使用 HardwareBufferManager:: createVertexDeclaration 方法創建頂點聲明: VertexDeclaration* patchDecl = HardwareBufferManager::getSingleton().createVertexDeclaration();
createVertexDeclaration (創建頂點聲明) 方法在頭文件 OgreHardwareBufferManager.h 中定義: VertexDeclaration * Ogre::HardwareBufferManager:: createVertexDeclaration ( void ) [virtual]
(2) 使用 VertexDeclaration:: addElement (添加元素) 方法來為第 1 步所創建的頂點數據結構體建立功用描述,逐個描述每一個數據的意義和用途: // 聲明頂點位置(三維向量) patchDecl->addElement(0, 0, VET_FLOAT3, VES_POSITION); // 聲明頂點法線(三維向量) patchDecl->addElement(0, sizeof(Real)*3, VET_FLOAT3, VES_NORMAL); // 聲明紋理坐標(二維向量) patchDecl->addElement(0, sizeof(Real)*6, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
VertexDeclaration:: addElement 方法在頭文件 OgreHardwareVertexBuffer.h 中定義:
const VertexElement & Ogre::VertexDeclaration::addElement ( unsigned short source, // (?) size_t offset, // 該元素在頂點緩存中的位置偏移 (bytes) VertexElementType theType, // 頂點元素類型 VertexElementSemantic semantic, // 頂點元素的意義或用途 unsigned short index = 0 // 可選索引,用於多端輸入元素例如紋理坐標 ) [virtual]
其中, VertexElementType (頂點元素類型) 在頭文件 OgreHardwareVertexBuffer.h 中定義: enum VertexElementType
{ VET_FLOAT1, VET_FLOAT2, VET_FLOAT3, VET_FLOAT4, VET_COLOUR, VET_SHORT1, VET_SHORT2, VET_SHORT3, VET_SHORT4, VET_UBYTE4 }; VET_FLOAT3 的意思是三維浮點數, VET_SHORT2 的意思是二維整數。
另一個, VertexElementSemantic (頂點元素意義) 也在頭文件 OgreHardwareVertexBuffer.h 中定義:
enum VertexElementSemantic { VES_POSITION = 1, // 位置:每個頂點要使用三個實數 (Real) 來表示 VES_BLEND_WEIGHTS = 2, // 混合權重 VES_BLEND_INDICES = 3, // 混合索引 VES_NORMAL = 4, // 法線:每個頂點的法線要使用三個實數 (Real) 來表示 VES_DIFFUSE = 5, // 散射光的顏色值 VES_SPECULAR = 6, // 反射光的顏色值 VES_TEXTURE_COORDINATES = 7, // 紋理坐標 VES_BINORMAL = 8, // 副法線 (如果法線是 Z 軸,副法線就是 Y 軸) VES_TANGENT = 9 // 切線 (如果法線是 Z 軸,切線就是 X 軸) };
3. 建立一個控制點數組用於儲存所有控制點的頂點信息,然後逐點填充頂點信息:
Real* patchCtlPoints = (Real*)( new PatchVertex[9] ); // 建立含有 9 個控制點的頂點緩存數組
PatchVertex *pVert = (PatchVertex*)patchCtlPoints; // 曲面頂點指針,指向曲面上的控制點
pVert->x = -500.0; pVert->y = 200.0; pVert->z = -500.0; // 定義控制點位置 pVert->nx = -0.5; pVert->ny = 0.5; pVert->nz = 0.0; // 定義控制點法線 pVert->u = 0.0; pVert->v = 0.0; // 定義控制點紋理坐標 pVert++; pVert->x = 0.0; pVert->y = 500.0; pVert->z = -750.0; pVert->nx = 0.0; pVert->ny = 0.5; pVert->nz = 0.0; pVert->u = 0.5; pVert->v = 0.0; pVert++; // ... ...
4. 使用 MeshManager:: createBezierPatch (創建貝塞爾曲面) 方法,從已定義的控制點頂點緩存創建曲面: patch = MeshManager::getSingleton().createBezierPatch( "Bezier1", patchCtlPoints, patchDecl, 3, 3, 5, 5, PatchSurface::VS_BOTH ); MeshManager:: createBezierPatch 方法在頭文件 OgreMeshManager.h 中定義:
PatchMesh * Ogre::MeshManager::createBezierPatch ( const String & name, // 曲面名稱 void * controlPointBuffer, // 控制點緩存 VertexDeclaration * declaration, // 頂點聲明 size_t width, // 曲面寬度(控制點行數) size_t height, // 曲面高度(控制點列數) size_t uMaxSubdivisionLevel = PatchSurface::AUTO_LEVEL, // U 向最大細分層次 size_t vMaxSubdivisionLevel = PatchSurface::AUTO_LEVEL, // V 向最大細分層次 PatchSurface::VisibleSide visibleSide = PatchSurface::VS_FRONT, // 曲面可見側 HardwareBuffer::Usage vbUsage = HardwareBuffer::HBU_STATIC_WRITE_ONLY, // 硬件頂點緩存功用 HardwareBuffer::Usage ibUsage = HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, // 硬件索引緩存功用 bool vbUseShadow = true, // 是否使用頂點陰影 bool ibUseShadow = true // 是否使用索引陰影 )
5. 使用 PatchSurface:: setSubdivisionFactor (設置細分係數) 方法設置貝塞爾曲面的細分層次: patch->setSubdivision(0.0f);
PatchSurface:: setSubdivisionFactor 方法在頭文件 OgrePatchSurface.h 中定義: void Ogre: atchSurface:: setSubdivisionFactor ( Real factor )
6. 創建一個基於這個貝塞爾曲面的實體並綁定到場景節點:
patchEntity = mSceneMgr->createEntity("Entity1", "Bezier1"); mSceneMgr->getRootSceneNode()->attachObject(patchEntity);
查看 OgrePatchSurface.h 了解關於貝塞爾曲面的更多信息。
本節示例代碼:
點擊下載此文件
|