天天看點

Ogre内部渲染流程分析系列

關于 OGRE 中的 Renderable  

要了解OGRE引擎,就要了解其中占很重要位置的 Renderable接口,今天先将一部分我分析的内容貼出來。

以下是 Ogre 的代碼中的詳細說明:

Renderable是OGRE中所有可渲染對象的抽象接口

這個接口抽象出了在渲染管線中的被分組的離散的可渲染對象基本的方法。

此接口的實作類必須是基于單一的材質、單一的世界矩陣(或者是一組通過權重混合的世界矩陣),以及單一的渲染操作。

通過這個說明,應該能明确的是,Renderable 封裝了3D世界中被渲染對象的基本屬性和資料,這包括:渲染操作,材質屬性,光照資訊、變換矩陣(四元組)、LOD資訊、渲染方式等資訊。這些資訊在渲染循環中被取出,并應用在圖形渲染管線中。其中需要注意的是RenderOperation(渲染操作)對象,它封裝了圖形硬體的頂點資料和渲染的圖元類型,在最終的渲染操作裡使用這些資料來進行圖元渲染,值得注意的是 RenderOpration 中的儲存的頂點資訊的類VertexData中是抽象的,它包含了一組硬體頂點緩存資料對象-HardwareVertexBuffer,這個類是從 HardwareBuffer 中繼承過來的,這個類包括了 hardware buffer中的抽象操作方法,這裡使用了模闆方法和抽象工廠等設計模式,每個具體的渲染系統可以實作自己的硬體緩存資料,當然,這當中也一定有HardwareBufferManager,而且具體的渲染系統也要實作這個類,來建立具體的渲染系統相關的資料緩存。

先說明OGRE内部重要的幾個對象:

1.       RenderSystem,此抽象類定義出 3D 渲染系統的基本功能,同時實作了一些通用的方法。各個不同的渲染平台實作此類,OGRE 内部互動由此抽象類負責,進而實作了渲染平台無關性。應用一般不會與此對象直接進行互動,在OGRE内部的其他重要對象,如SceneManager與它進行互動,整個過程是透明的。

2.       SceneManager,組織場景中的對象并将對象送入渲染系統中渲染。這個類定義了場景管理器的基本功能,應用用戶端根據自己需要重新實作場景的組織功能。這個對象掌控了所有的可渲染對象。

3.       RenderTarget , 定義:接受渲染操作結果的畫布。此抽象類定義了基本的渲染目标屬性和操作的功能。渲染目标可以是視窗、螢幕、或者離屏表面,如:渲染到一張紋理圖等等。每個具體的渲染引擎需要實作自己的RenderTarget,如:D3D9RenderWindow,D3D9RenderTexture 等。這個抽象類包含了一個到多個的 ViewPort 對象,在渲染時會跌代更新每個ViewPort。

4.       ViewPort,定義:一塊渲染目标區域。 

說明:視口是相機和渲染表面的交集,并把這個結果放在整個渲染表面或者表面的一部分。每個視口都有一個相機作為源,一個目标作為目标。一個相機隻有一個視口,但一個渲染目标可以有多個視口。視口有 z 序屬性,如果渲染目标有多個視口,要對視口進行 z 排序.

5.       Camera,這個就不需要解釋了吧,需要注意的是它與ViewPort 和SceneManager之間的關系。

6.       SceneNode,這個類從Node繼承過來,除了自身是一個樹形結構之外,它還可以附加多個可移動對象(MoveableObject),這樣他可以與世界中的所有可移動對象(比如實體對象)關聯起來。

7.       Entity,定義了一個離散的、基于 mesh 的可移動對象的執行個體。

OGRE 通常将可渲染對象分為2組,一是在世界中移動的離散的極其相關小對象。一種是大規模的雜亂的通常組成靜态場景的對象。

Mesh 和 SubMesh 處理那些在離散的可移動對象中使用的圖元的定義。Entity 在世界中是真正的基于這種圖元的對象的執行個體,是以對于一個汽車來說它就是一個獨立的網格集合,但是在世界中可以有多個基于相同網格集合的實體,這些實體可以改變網格的外在表現,例如通過改變材質屬性(這樣你就可以在相同的圖中繼資料上用不同的紋理來擁有不用的小汽車),為了這個目标,因為 Mesh 被分成多個 SubMesh,是以實體類是一個分組的類(與Mesh類很相似)并且相關的獨立的個體改變的細節資訊被儲存在 SubEntity 類中。這是1:1的關系,Entity 與 SubEntity及其關聯的 Mesh 和 SubMesh。

實體和子實體都不會被直接的建立出來,用 SceneManager 的 createEntity (傳遞一個模型的名字)方法來建立他們。

實體是被關聯他們的場景節點對象包含在場景中的,使用 attachEntity方法關聯,參照 SceneNode 類的說明或取完整的資訊。

8.      RenderQueue,定義了渲染隊列,此隊列中包含了按照材質排序的可渲染對象,這樣會使渲染狀态的切換最少,它包含了一組RenderQueueGroup對象

9.       RenderQueueGroup,渲染隊列組,按照渲染的優先級别排列的渲染對象清單。

10.   RenderPriorityGroup,渲染優先級分組,包含的所有的渲染對象都具有相同的優先級。分出透明對象和非透明對象及其它渲染方式對象,使渲染狀态切換最小。

具體流程如下:

首先Ogre引擎在啟動時會根據配置建立一個合适的場景管理器(SceneManager),SceneManager會自動建立一個根節點對象(SceneNode),有了這個root node 我們就可以在這個 root node下建立場景節點并将3D渲染實體附加到節點上。應用程式可以在任意節點下建立子節點,建立之後将3D渲染實體附加到此節點上。在SceneNode内部,儲存着一個MoveableObject清單,由于Entity是從MoveableObject繼承過來,是以可以把Entity附着在SceneNode上,同時,Entity内部包含一個SubEntity的清單,而SubEntity是從Renderable繼承過來,這樣在場景更新時,首先調用SceneNode的 _addToRenderQueue 方法,這個方法内部疊代MoveableObject清單的每一項,調用MoveableObject的_updateRenderQueue抽象方法,每個從MoveableObject繼承的類都要實作此方法,比如Entity,在Entity的這個方法内部,疊代SubEntity清單的每一項(SubEnbtity從Renderable繼承),将每個SubEntity送入渲染隊列中去,這樣就完成了渲染隊列的更新工作。以上說明隻是很粗略的描述,具體還有許多細節沒有說明,比如進行可視判斷,是否透明物體,是否為骨骼節點等等,但主要的流程是這樣的。下一部份我将會說明加入渲染隊列之後的内部流程。

好久沒更新這個系列了,今天在同同僚的讨論中說到了渲染對象排序的問題,正好自己的引擎也快做到這部分了,晚上回家看了一下 Ogre 的代碼,整體如下:

先貼上一張 RenderQueue 的類和資料類型關系圖:

Ogre内部渲染流程分析系列

資料類型說明:

1. RenderableList:

   原型:typedef std::vector<Renderable*> RenderableList;

   描述:可渲染對象清單。

2. TransparentRenderablePassList:

   原型: typedef std::vector<RenderablePass> TransparentRenderablePassList;

   描述:透明的渲染對象清單。

3. RenderableSolidPassMap:

   原型: typedef std::map<Pass*, RenderableList*, SolidQueueItemLess> SolidRenderablePassMap;

   描述:以Pass分組的非透明可渲染對象清單,每個Pass對應一個到多個可渲染對象,也就是說将相同渲染狀态的對象作為一組進行渲染,減少渲染管線的切換操作,提高渲染性能。

4. RenderPriorityGroupMap:

   原型: typedef std::map<ushort, RenderPriorityGroup*, std::less<ushort> > PriorityMap;

   描述:以優先級分組的可渲染對象隊列的清單,以優先級作為清單中每一項的關鍵字。

5. RenderQueueGroupMap:

   原型: typedef std::map< RenderQueueGroupID, RenderQueueGroup* > RenderQueueGroupMap;

   描述:以渲染分組ID分組的渲染隊列的清單,以渲染分組ID作為清單中每一項的關鍵字。所謂渲染分組标示(RenderQueueGroupID)就是标示粗粒度分組,比如2D背景一定會先渲染,天空會次之,2DUI可能會最後渲染,Ogre中已經定義好了一系列的粗粒度分組号,具體參考枚舉類型RenderQueueGroupID的定義說明,大部分渲染對象使用的是RENDER_QUEUE_MAIN,這也是預設的渲染粒度。

對象說明:

1. Pass:

   描述:從頂點到像素的一次生成過程,包含渲染狀态的設定參數,比如光照參數、紋理階段設定、Alpha 混合操作、深度緩沖、霧、裁減方式、填充模式等等,也包含了可程式設計管線PS\VS的相關設定。

2. Renderable:

   描述:請參考我的《關于 OGRE 中的 Renderable 》的文章。

3. RenderQueue:

   描述:定義了渲染隊列,此隊列中包含了按照渲染分組ID排序的可渲染對象清單,也就是上面的 RenderQueueGroupMap 類型。這裡會進行最粗粒度的排序,按照2D背景、天空、場景對象、2DUI等進行排序。SceneManager 中包含此對象。

4. RenderQueueGroup:

   描述:渲染隊列組,按照渲染對象的渲染優先級别排列的渲染對象清單,此類中擁有一個上面的 RenderPriorityGroupMap 類型成員。

5. RenderPriorityGroup:

   描述:渲染優先級組,包含的所有的渲染對象都具有相同的優先級。分出透明對象和非透明對象及其它渲染方式對象,使渲染狀态切換最小。其中的渲染對象烈表是以 Pass 分組的,對于半透明物體,每個對象對應一個 Pass。

渲染流程:

每桢更新渲染隊列,首先清除 SceneManager 中的 RenderQueue,然後在具體的場景管理器(BSP\OCTREE)中剔除不可見物體,将可見物體按照最粗粒度的劃分加入到 RenderQueue 中,RenderQueue 将對象傳遞到 RenderQueueGroup 中按照并按照指定的優先級加入到 RenderPriorityGroup 中的 SolidRenderablePassMap(非透明) 或者 TransparentRenderablePassList (透明)中,在 SolidRenderablePassMap 中還要按照渲染狀态排序,也就是 Pass 排序,将相同 Pass 的對象儲存在一個清單中。這樣,更新渲染隊列的工作就完成了,在渲染時按照已經排好的順序進行繪制就可以了。

繼續閱讀