鑲嵌階段
Direct3D 11 執行時間支援三個新的階段,可實作鑲嵌式,將低詳細資料細分介面轉換成 GPU 上的較高詳細資料基本類型。 鑲嵌並排顯示高位表面 (或將其分裂) 成為適合轉譯的結構。
藉由在硬體中實作鑲嵌,圖形管線可以評估較低細節的 (較少的多邊形數) 模型並以更高細節呈現。 雖然軟體鑲嵌是可做到的,但硬體實作的鑲嵌會產生不可思議的視覺細節數量 (包括位移對應的支援),而不需要新增模型大小的視覺細節和造成運作癱瘓的更新頻率。
鑲嵌權益
鑲嵌:
- 節省許多記憶體和頻寬,這可讓應用程式從低解析度模型轉譯更詳細的表面。 Direct3D 11 管線中實作的鑲嵌技術也支援位移對應,這會產生令人讚歎的表面詳細資料量。
- 支援可調整的轉譯技術,例如可即時計算的連續或檢視相依層級詳細資料。
- 藉由以較低的頻率執行昂貴的計算來改善效能, (在較低詳細資料模型上執行計算) 。 這可能包括將混合形狀或變形目標 (morph target) 用於寫實動畫的混合計算,或用於撞擊偵測或軟體動力 (soft body dynamics) 的物理計算。
Direct3D 11 管線會在硬體中實作鑲嵌,以將工作從 CPU 卸載至 GPU。 如果應用程式實作大量變形目標和/或更加複雜的皮膚形變 (skinning)/變形模型,這可能會導致非常大的效能改進。 若要存取新的鑲嵌功能,您必須瞭解一些新的管線階段。
新的管線階段
鑲嵌使用 GPU,從四邊形塊面 (quad patch)、三角形塊面 (triangle patch) 或等高線 (isoline) 建構而來的表面計算更詳細的表面。 為了近似高位表面,每個塊面細分成三角形、點或使用鑲嵌因數的線。 Direct3D 11 管線會使用三個新的管線階段來實作鑲嵌:
- 殼層著色器階段 - 可程式化著色器階段,其會產生幾何修補 (和修補常數,) 對應至每個輸入修補程式 (四角形、三角形或線條) 。
- 鑲嵌器階段 - 固定函式管線階段,可建立代表幾何修補程式的網域取樣模式,並產生一組較小的物件, (連接這些樣本的三角形、點或線條) 。
- 網域著色器階段 - 可程式化著色器階段,可計算對應至每個定義域範例的頂點位置。
下圖醒目提示 Direct3D 11 管線的新階段。
下圖顯示鑲嵌階段的進展。 從低細節的細分表面開始進展。 進展接下來會使用對應幾何塊面、網域樣本,和連接這些樣本的三角形,反白顯示輸入塊面。 進展最後會反白顯示對應於這些樣本的頂點。
Hull-Shader階段
殼層著色器 -- 每個修補程式叫用一次 -- 會將定義低序表面的輸入控制點轉換成構成修補程式的控制點。 它也會進行一些修補程式計算,以提供鑲嵌階段和網域階段的資料。 在最簡單的黑色方塊層級,殼面著色器階段看起來會像下圖所示。
殼層著色器是使用 HLSL 函式實作,並具有下列屬性:
- 著色器輸入介於 1 到 32 個控制點之間。
- 著色器輸出介於 1 到 32 個控制點之間,無論鑲嵌係數的數目為何。 輪廓著色器的控制點輸出可以由網域著色器階段取用。 網域著色器可以使用修補程式常數資料;定義域著色器和鑲嵌階段可以使用鑲嵌因數。
- 鑲嵌係數決定每個塊面要細分成多少數目。
- 著色器會宣告鑲嵌器階段所需的狀態。 這些資訊包括控制點數目、塊面的類型,以及鑲嵌時分割使用的類型。 這項資訊會顯示為宣告,通常是在著色器程式碼的前方。
- 如果殼層著色器階段將任何邊緣鑲嵌因數設定為 = 0 或 NaN,將會擷取修補程式。 如此一來,曲面細分器階段就不一定會執行,網域著色器將不會執行,而該塊面也不會產生任何可見的輸出。
在更深入的層級,殼層著色器實際上會以兩個階段運作:控制點階段和修補程式常數階段,硬體會平行執行。 HLSL 編譯器會擷取輪廓著色器中的平行處理原則,並將它編碼成驅動硬體的位元組程式碼。
- 控制點階段會針對每個控制點執行一次,讀取塊面的控制點,以及產生一個輸出控制點 (以 ControlPointID 識別)。
- 塊面常數階段會針對每個塊面執行一次,以產生邊緣鑲嵌係數,和其他每個塊面常數。 在內部,許多塊面常數階段可能同時執行。 塊面常數階段對於所有輸入和輸出控制點有唯讀存取權。
以下是殼層著色器的範例:
[patchsize(12)]
[patchconstantfunc(MyPatchConstantFunc)]
MyOutPoint main(uint Id : SV_ControlPointID,
InputPatch<MyInPoint, 12> InPts)
{
MyOutPoint result;
...
result = TransformControlPoint( InPts[Id] );
return result;
}
如需建立殼層著色器的範例,請參閱 如何:建立殼層著色器。
鑲嵌器階段
鑲嵌器是透過將殼層著色器系結至管線來初始化的固定函式階段, (請參閱 如何:初始化鑲嵌式階段) 。 曲面細分器階段的目的是將網域 (四邊形、三角形或線) 細分成很多較小的物件 (三角形、點或線)。 曲面細分器在標準化 (零到一) 座標系統中並排顯示標準網域。 例如,四邊形網域被鑲嵌為單位正方形。
使用從輪廓著色器階段傳入的鑲嵌因數 (這指定網域被鑲嵌的細微程度) 和分割類型 (指定用於切割塊面的演算法),曲面細分器每個塊面運作一次。 曲面細分器輸出 uv (和選擇性 w) 座標及表面拓撲至網域著色器階段。
在內部,鑲嵌器會以兩個階段運作:
- 第一相位處理鑲嵌因數、修正進位問題、處理非常小因數、降低並結合因數,使用 32 位元浮點算術。
- 第二個相位根據所選分割的類型產生點或拓撲清單。 這是曲面細分器階段的核心工作,並使用 16 位元分數搭配固定點算術。 固定點算術允許硬體加速,同時維持可接受的精確度。 例如,假設有 64 公尺寬塊面,這個精確度可以 2 公釐解析度放置點。
分割類型 | 範圍 |
---|---|
fractional_odd | [1...63] |
fractional_even | TessFactor 範圍:[2..64] |
整數 | TessFactor 範圍:[1..64] |
pow2 | TessFactor 範圍:[1..64] |
Domain-Shader階段
定義域著色器會計算輸出修補程式中子點的頂點位置。 網域著色器會依鑲嵌器階段輸出點執行一次,且具有鑲嵌器階段輸出 UV 座標、殼面著色器輸出修補程式和殼面著色器輸出修補程式常數的唯讀存取權,如下圖所示。
定義域著色器的屬性包括:
- 每個輸出座標從鑲嵌式階段叫用定義域著色器一次。
- 定義域著色器會從殼層著色器階段取用輸出控制點。
- 定義域著色器會輸出頂點的位置。
- 輸入是殼面著色器輸出,包括控制點、修補常數資料和鑲嵌因數。 鑲嵌因數可以包含固定函式鑲嵌器所使用的值,以及以整數鑲嵌四捨五入之前 (的原始值,例如) ,這可促進地理型態。
定義域著色器完成後,鑲嵌完成,管線資料會繼續到下一個管線階段, (幾何著色器、圖元著色器等) 。 預期相鄰基本類型 (例如每個三角形 6 個頂點) 在鑲嵌為使用中時無效 (這樣會導致未定義的行為,偵錯層將會抱怨此行為)。
以下是網域著色器的範例:
void main( out MyDSOutput result,
float2 myInputUV : SV_DomainPoint,
MyDSInput DSInputs,
OutputPatch<MyOutPoint, 12> ControlPts,
MyTessFactors tessFactors)
{
...
result.Position = EvaluateSurfaceUV(ControlPoints, myInputUV);
}
初始化鑲嵌階段的 API
鑲嵌是使用兩個新的可程式化著色器階段來實作:殼層著色器和領域著色器。 這些新的著色器階段是以著色器模型 5 中定義的 HLSL 程式碼進行程式設計。 新的著色器目標為:hs_5_0和ds_5_0。 如同所有可程式化著色器階段,當著色器使用 DSSetShader 和 HSSetShader等 API 系結至管線時,硬體的程式碼會從傳遞至執行時間的已編譯著色器擷取。 但首先,必須使用 CreateHullShader 和 CreateDomainShader等 API 來建立著色器。
藉由建立輪廓著色器並將它繫結至輪廓著色器階段 (這會自動設定曲面細分器階段),來啟用鑲嵌。 若要從鑲嵌塊面產生最終頂點位置,您也需要建立網域著色器並將其繫結至網域著色器階段。 一旦啟用鑲嵌,輸入組合器階段的資料輸入必須是修補資料。 也就是說,輸入組合器拓撲必須是從IASetPrimitiveTopology設定D3D11_PRIMITIVE_TOPOLOGY的修補程式常數拓撲。
若要停用鑲嵌,將輪廓著色器和網域著色器設定為 NULL。 幾何著色器階段和資料流程輸出階段都無法讀取殼層著色器輸出控制點或修補資料。
輸入組合器階段的新拓撲,這是此列舉的擴充功能。
enum D3D11_PRIMITIVE_TOPOLOGY
當然,新的可程式化著色器階段需要設定其他狀態,才能將常數緩衝區、樣本和著色器資源系結至適當的管線階段。 這些新的 ID3D11Device 方法會實作以設定此狀態。
作法:
檔也包含初始化鑲嵌階段的範例。
項目 | 描述 |
---|---|
如何:建立殼層著色器 |
建立殼層著色器。 |
如何:設計殼層著色器 |
設計殼層著色器。 |
如何:初始化鑲嵌器階段 |
初始化鑲嵌階段。 |
如何:建立網域著色器 |
建立網域著色器。 |
如何:設計定義域著色器 |
建立網域著色器。 |