Gamebryo—Material System

Material System

一、 簡介

GB的材質系統是一種基於NiMesh的渲染狀態創建相應NiShader實例的機制。開發者經常需要爲多個對象進行同種特效處理,以及當單個NiShader無法滿足繪製需求時,與其讓一個美術爲不同幾何體提供不同的NiShader,不如使用單個NiMaterial,它可以在運行時爲每一個幾何體提供合適的NiShader。

一個簡單材質可以查詢mesh從而決定它是否進行蒙皮(Skinned)處理。它可以選擇不同的蒙皮(被NiShader定義,並從shader library中加載)。一些複雜的材質,可以動態生成着色程序,這些着色程序既可以被添加也可以被減少。在添加系統中可以使用各種高級着色語言程序段,並把他們練到一起從而組成一個完整的着色程序。在減少系統中可以使用預編譯處理器命令(compile-time preprocessor commands)進入一個着色程序並刪除相應的片段。

NiMaterial VS NiShader

一個NiShader包含了一個幾何體繪製時的所有渲染狀態。它可以掃描多個render pass從而描述幾何體在不同情況下如何被繪製。一個NiShader可以被多個幾何體共享。

可以使用NSF或FX Shader來實現NiShader,這些shader可以被用來創建各種特效,但在特定情況下,只有一個被激活。

一個NiMaterial負責根據不同情況決定使用那一個NiShader,以及當NiShader不存在時可以創建。NiMaterial會根據NiMesh以及它的屬性,以及當前硬件、用戶設定來做出正確的決定。

總之,NiMaterial描述瞭如何進行使用特效,而 NiShader實現具體的特效。

二、 架構

1. NiMaterial

爲開發者提供了一種方法,使得它可以控制特定的渲染對象使用那個NiShader。應用程序在使用材質系統時,首先會詢問先前的shader是否繼續有效(IsShaderCurrent),如果無效或先前沒有shader則會調用GetCurrentShader,即提供一個可用的Material。

clip_image002

NiFragmentMaterial:負責添加高級着色語言系統的基類

NiSingleShaderMaterial:在材質框架中引入NiShader基類。

2. NiFragmentMaterial

該類是處理shader fragment system(着色器程序段)的基類,通常該系統使用hlsl或cg函數去定義一個完整的着色程序,這些函數的輸入和輸出可以被被連接在一起,從而完成一個完整的着色程序。這些程序段的連接關係形成了一個“shader tree”。

NiFragmentMaterial封裝了GB中實現一個shader-tree的框架,這條管線裏生成一個編譯好的shader需要經過如下步驟:

第一步:生成幾何體的材質描述符。該過程生成一個NiMaterialDescriptor對象,它時一個128位,描述了幾何體附屬於shader-tree的狀態信息。GenerateDescriptor封裝了這一過程。

第二步:查詢NiShader緩衝區決定該材質配置是否已經被處理。如果沒則使用GenerateShader,如果處理過了只要重新使用即可。

第三步:搜索失敗shader列表,判斷該材質配置是否被當前硬件支持,如果否,則返回NULL,此時渲染器會使用內部error shader。

第四步:把材質描述符分解成一個或多個NiGPUProgrammDescriptors。它是一個128位,包含了pass生成所有正確NiGPUProgram的條件。GenerateShaderDescArray封裝了這一過程。

第五步:爲當前渲染器創建合適的NiShader子類。

第六步:爲該shader指定packing requirements。

第七步:遍歷材質實例中的每一個NiGPUProgramDescriptors,生成相應的render pass對象。

(1) 決定如何和先前的pass進行混合(SetAlphaOverride)

(2) 位該pass生成GPU程序(GenerateShaderProgram)

A: 生成頂點着色器程序(GenerateVertexShaderProgram)

B: 生成像素着色器程序(GeneratePixelShaderProgram)

C:爲每一個生成的程序創建NiShaderConstantMap,同時添加所有變量(AddResourceToShaderConstantMap)。

D:如果發生錯誤,則返回錯誤信息。

第八步:如果成功,則初始化新的shader並返回。否則處理回到控制。

2.1 創建一個shader tree

The Pipeline

在上述管線中,會生成一個shade tree並且編譯每一個NiGPUProgram。在GB中,shade tree被封裝到一個NiMaterialConfigurator對象中。它的子類將查找NiGPUProgramDescriptor中的標識位,從而決定那些統一常量將被關聯的對應的樹節點上。統一常量被封裝在NiMaterialResource中,而樹的節點被封裝在NiMaterialNode。對應節點輸入、輸出資源之間以及與其它節點之間的連接,和統一常量一起被封裝在NiMaterialResourceBinding中。一旦所有節點之間的連接被建立並且添加到樹中,此時NiMaterialConfigurator中Evaluate函數將被調用並生成NiGPUProgram。

NiMaterialFragmentNodes

在需要創建shade tree時,必須創建節點,這些節點擁有一些代碼片段。這些節點被稱作NiMaterialFragmentNodes。一個指定節點包含一組代碼片段,這些代碼片段會和不同着色語言、不同硬件模型、不同平臺進行通信。如,一個支持低級別shader mode顯卡會使用較簡單的光照計算但是會更快。而高級顯卡中,會使用更新的指令以及更復雜的算法。所有的節點實現必須遵循同一輸入、輸出資源。Shade tree在所有節點的輸入得到滿足後建立。通常情況下節點片段會定義默認的輸入資源值。

NiMaterialNodeLibraries

NiMaterialNodes可以通過NiMaterialNodeLibrary對象添加到應用程序中。這些對象包含了一組材質節點,這些節點可以被添加到一個shade tree中。這樣實現了shade tree的完全數據驅動。有兩種方法可以生成這些庫—解析一個XML文件,或者把XML文件轉換爲C++類從而實現和應用程序進行連接。後一種方法在NiStandardMaterial中被使用,NiStandardMaterial是NiFragmentMaterial的子類,它實現了GB默認的渲染管線。在NiMain\StandardMaterialNodeLibrary中一個XML文件包含了材質中使用的所有片段。無論這些片段是被改變、添加、刪除一組文件將調用DeveloperTool\NiMaterialNodeXMLLibraryParse執行,從而創建C++類來代表這個庫。作爲選擇,應用程序可以使用NiMaterialNodeXMLLibraryReader來解析這個XML庫。

NiMaterialResources

NiMaterialResources可以是多種數據類型,bool、uint、floar、point2s、point3s、point4s、matrix4s、colors、textures。如前所述,每一個節點會擁有一組輸入、輸出資源。其它資源可以來自於以下:

l 常量。

l 預定義。該類型是GB提供的一個預定義類型。

l 屬性。該值是被掛載在對應幾何體上,它是per-object的。

l 全局。他是應用程序註冊的,如燈光相關、每一天的時間。

l 對象。它是場景中的一個對象,如燈光、紋理特效。

2.2 回調控制

偶爾,一個NiFragmentMaterial會創建shader失敗。這種情況經常由於編譯GPU程序失敗。在這種情況下,材質會重新創建NiGPUProgramDescriptors(第四步)此時會進行簡單處理,並試圖再建立shader。材質也許會簡單使用descriptors把一個特效分解成多個passes,或者減少特定的光照或紋理。

材質會提供相應的回調功能。這些回調函數會使用如下簽名:

clip_image004

當回調函數被調用,它將被傳入所有的NiMaterialDescriptor,它描述了所有的特效。同時將獲得一個ReturnCode,該報告描述了先前爲什麼失敗、失敗pass的標識、RenderPassDescriptor(詳細描述了該pass)對象數組。獲得這些信息,回調函數可以標識問題的地方、以及校正信息。

3. NiMaterialInstance

該類允許一個材質被掛載到一個幾何體上,它負責管理材質爲渲染器生成一個新shader的方式和時間。該過程是通過保存最近、最合適的shader到指定材質來實現的。

4. NiMaterialLibrary

材質庫是一種將新材質加入到GB材質系統和美術管線中的途徑。一個新材質庫包含一些列材質描述符(material descriptors)以及根據需要生成材質的能力。

DLL-Based Application Usage

如何使用材質庫決定於材質庫的使用類型,

LIB-Based Application Usage

Adding Material In Art

5. NiSingleShaderMaterial

該類是一種在應用程序中向幾何體添加NiShader快速方法,首選生成NiSingleShaderMaterials的方法是NiSingleShaderMaterialLibrary,它通過在NiShaderFactory中搜索所有的NiShaderLibrary來完成的。

NiSingleShaderMaterial的GetCurrentShader方法。

6. NiStandardMaterial

該類實現了GB默認的渲染管線(tdefault Gamebryo rendering pipeline),同時它也包含了一些相關的設置,這些設置使材質和GB的legacy pipeline更爲相似。

NiStandardMaterial擁有一定數量的回調函數,這些回調函數都有默認的實現。按順序有如下幾步:

A:SplitPerPixelLights

該方法會把失敗pass中的per-pixel燈光一分爲二,分別放到兩個pass中,這樣生成了一個新的pass。一旦失敗該函數會一直遞歸知道每個pass只含有個燈光。

B:SplitPerVertexLights

與A原理類似。

C:SplitTextureMaps

該方法同樣把一個失敗的pass分成兩個pass。在第一個pass中會和光照一起處理base、dark、detail、projected light、shadow貼圖。而第二個pass會處理glow、environment貼圖。該方法最多執行一次,不會遞歸執行。

7. NiGPUProgrammCache System

該系統設計的目的使包含那些先前被材質系統編譯好的NiGPUProgramms。在一個材質系統中經常含有一些需要重用那些先前編譯的GPU程序段的NiShader。由於GPU程序的編譯是一非常耗費的操作。該cache可以存儲那些先前的編譯結果。一旦程序段被編譯,它將被插入到該cache中,同時也可以選擇被保存到磁盤中。

該類的兩個重要接口是FindCachedProgram和GenerateProgram。前者用於搜索一個指定名字的程序段。該方法返回兩個對象,即找到的GPU程序段,以及一些列被該程序段使用的資源。GenerateProgram可以完成編譯一個使用高級着色語言實現的程序。

每一個種渲染器會實現自身的程序cache類,DX9-NiD3DGPUProgramCache,它可以遍歷HLSL程序。如果引用程序不想手動創建程序caches,可以使用NiRenderer:SetDefaultProgramCache方法,獲得正確的NiGPUProgramCache,然後再把它設給指定的NiFragmentMaterial。

應用程序可以擁有多個caches。

三、 使用

1. NiMaterial Usage

Resolving Material At Runtime:在加載時,一個美術資源引用了一個材質,此時會檢查材質緩衝區(NiMaterial:GetMaterial)。如果該材質不存在,則查詢材質庫(NiMaterialLibrary::CreateMaterial)。如果還是沒有找到,此時渲染器會使用默認的纔是繪製對象。

Adding Custom Parameters To Art

2. 使用材質

可以通過NiMaterialInstance來向指定渲染對象添加材質。這允許多個渲染對象共享一個NiMaterial實例。NiMaterialInstance包含:一個自身材質的引用、最近材質使用的NiShader、一個標誌(判斷當前cached shader是否爲最新)、uint類型數(標識使用該shader的時間)。

GB支持同一渲染對象擁有多個材質,但特定時刻只能有一個活動材質。這樣可以創建出更多的特效。

渲染對象擁有一些處理材質的方法:

ApplyMaterial添加材質。

SetActiveMaterial激活材質。

ApplyAndSetActiveMaterial,添加並激活材質。

3. Gamebryo Legacy Pipeline

GB保留Legacy Pipeline有兩個原因:某些硬件不支持標準材質;保持與老版本引擎的兼容。所有的渲染器都支持Legacy Pipeline。

clip_image006

4. Gamebryo Standard Material

(1)標準材質的特徵

clip_image008

clip_image010

5. Renderer Interaction With Material

當繪製一個物體時,首先需要通過NiRenderObject::GetShaderFromMaterial函數來獲得一個活動材質的實例—NiMaterialInstance。此時材質實例將查詢NiShader用於渲染對象。

NiMaterialInstance

材質實例提供shader時,首先要做的是查詢cached shader是否存在。材質實例保存了一個shader指針,從而防止將來被重新使用。

默認材質

如果當前的渲染對象沒有材質處於活動狀態,此時渲染器會爲該渲染對象設置一個默認的材質。

Error Shader

如果渲染對象的當前活動材質不能提供一個可用的Shader,此時渲染器會使用一個Error Shader來繪製物體。

四、 使用擴展

GB的材質系統使用的可擴展設計,所以用戶可以根據需要來擴展該材質系統。

用例1:使用標準Shaders

通常情況下,用戶要使用簡單的預定義shader程序-FX、NSF、或者其它NiShader。此時,用戶使用的材質必須繼承於NiMaterial。

用例2:擴展標準材質

用例3:創建子材質系統

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章