重要的應用程式介面
一旦您完成將用于建立和配置緩衝區和著色器對象的程式碼轉移後,就可以開始將這些著色器內的程式碼從 OpenGL ES 2.0 的 GL 著色器語言(GLSL)移植到 Direct3D 11 的高階著色器語言(HLSL)。
在OpenGL ES 2.0中,著色器會使用 gl_Position、 gl_FragColor 或 gl_FragData[n] 等內建來傳回執行後的數據(其中 n 是特定轉譯目標的索引)。 在 Direct3D 中,沒有特定的固有函数,著色器會將數據作為其各自 main() 函式的返回型別。
您想要在著色器階段之間插補的數據,例如頂點位置或一般,是透過使用 不同 宣告來處理。 不過,Direct3D 沒有此宣告;相反地,您想要在著色器階段之間傳遞的任何數據都必須以 HLSL 語意標示。 選擇的特定語意表示資料的目的,且 為 。 例如,您會宣告要在片段著色器之間插補的頂點數據,如下所示:
float4 vertPos : POSITION;
或
float4 vertColor : COLOR;
其中 POSITION 是用來指出頂點位置數據的語意。 POSITION 也是特殊案例,因為插補之後,圖元著色器無法存取它。 因此,您必須使用 SV_POSITION 指定圖元著色器的輸入,且插補頂點數據會放在該變數中。
float4 position : SV_POSITION;
語意可以在著色器的主體(main) 方法上宣告。 針對圖元著色器,SV_TARGET[n],表示在方法主體中需要一個渲染目標。 (SV_TARGET 沒有數值後綴時,預設為渲染目標索引 0。)
另請注意,必須有頂點著色器,才能輸出SV_POSITION系統值語意。 此語意會將頂點位置數據解析為座標值,其中 x 介於 -1 與 1 之間,y 介於 -1 和 1 之間,z 除以原始同質座標 w 值 (z/w),而 w 則為 1 除以原始 w 值 (1/w)。 圖元著色器使用 SV_POSITION 系統值語義來取得畫面上的圖元位置,其中 x 介於 0 到轉譯目標寬度之間,y 介於 0 到轉譯目標高度之間(每個位置偏移 0.5)。 功能等級 9_x 像素著色器無法讀取 SV_POSITION 值。
常數緩衝區必須使用 cbuffer 宣告,並與查閱的特定的起始暫存器相關聯。
Direct3D 11:HLSL 常數緩衝區宣告
cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix mvp;
};
在這裡,常數緩衝區會使用緩存器 b0 來保存已封裝的緩衝區。 所有暫存器都以 b# 形式參考。 如需常數緩衝區、緩存器和數據封裝 HLSL 實作的詳細資訊,請參閱 著色器常數 (HLSL) 。
操作說明
步驟 1:移植頂點著色器
在我們的簡單 OpenGL ES 2.0 範例中,頂點著色器有三個輸入:一個常數的 model-view-projection 4x4 矩陣,以及兩個四座標向量。 這兩個向量包含頂點位置及其色彩。 著色器會將位置向量轉換為透視座標,並將其指派給用於點陣化的 gl_Position 內建變數。 頂點色彩也會複製到一個可變數,以便在光柵化過程中進行插值。
OpenGL ES 2.0:立方體物件的頂點著色器(GLSL)
uniform mat4 u_mvpMatrix;
attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 destColor;
void main()
{
gl_Position = u_mvpMatrix * a_position;
destColor = a_color;
}
現在,在 Direct3D 中,固定的 model-view-projection 矩陣包含在以註冊 b0 打包的常數緩衝區中,而頂點位置和顏色則以適當的 HLSL 語意 POSITION 和 COLOR 特別標示。 由於我們的輸入配置會指出這兩個頂點值的特定排列方式,因此您會建立結構來保存它們,並將它宣告為著色器主體函式上輸入參數的類型(main)。 (您也可以將它們指定為兩個單獨的參數,但這可能會變得繁瑣。)您還會指定這個階段的輸出類型,其中包含插值位置和顏色,並將其宣告為頂點著色器函式體的返回值。
Direct3D 11:立方體物件的頂點著色器(HLSL)
cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix mvp;
};
// Per-vertex data used as input to the vertex shader.
struct VertexShaderInput
{
float3 pos : POSITION;
float3 color : COLOR;
};
// Per-vertex color data passed through the pixel shader.
struct PixelShaderInput
{
float3 pos : SV_POSITION;
float3 color : COLOR;
};
PixelShaderInput main(VertexShaderInput input)
{
PixelShaderInput output;
float4 pos = float4(input.pos, 1.0f); // add the w-coordinate
pos = mul(mvp, projection);
output.pos = pos;
output.color = input.color;
return output;
}
輸出數據類型 PixelShaderInput 會在點陣化期間填入,並提供給片段(圖元)著色器。
步驟 2:移植片段著色器
GLSL 中的範例片段著色器非常簡單:將插補的色彩值提供給內建函數 gl_FragColor。 OpenGL ES 2.0 會將它寫入預設轉譯目標。
OpenGL ES 2.0:立方體物件的片元著色器(GLSL)
varying vec4 destColor;
void main()
{
gl_FragColor = destColor;
}
Direct3D 幾乎一樣簡單。 唯一顯著差異在於像素著色器的內部函式必須返回一個值。 由於色彩是 4 座標 (RGBA) 浮點數,因此您會將 float4 表示為傳回型別,然後將預設轉譯目標指定為SV_TARGET系統值語意。
Direct3D 11:立方體物件的像素著色器(HLSL)
struct PixelShaderInput
{
float4 pos : SV_POSITION;
float3 color : COLOR;
};
float4 main(PixelShaderInput input) : SV_TARGET
{
return float4(input.color, 1.0f);
}
像素位置的顏色會寫入渲染目標。 現在,讓我們看看如何在 將該渲染目標的內容顯示於螢幕上!
上一個步驟
後續步驟
備註
瞭解 HLSL 語意和常數緩衝區的打包方式,能顯著地減少偵錯的麻煩,並有助於提供優化機會。 如果您有機會閱讀 變數語法 (HLSL)、 Direct3D 11 中的緩衝區簡介,以及如何 :建立常數緩衝區。 不過,如果沒有的話,這裡有一些關於語意和常數緩衝區的入門提示要記住:
- 請務必仔細檢查轉譯器的 Direct3D 組態程式代碼,以確定常數緩衝區的結構符合 HLSL 中的 cbuffer 結構宣告,而且元件純量類型符合這兩個宣告。
- 在轉譯器的C++程序代碼中,在常數緩衝區宣告中使用 DirectXMath 類型,以確保適當的數據封裝。
- 有效率地使用常數緩衝區的最佳方式是根據其更新頻率,將著色器變數組織成常數緩衝區。 例如,如果您有每個畫面一次更新一次的統一數據,以及只有在相機移動時才會更新的其他統一數據,請考慮將該數據分成兩個不同的常數緩衝區。
- 您忘記應用或錯誤應用的語意將是最早導致著色器編譯(FXC)錯誤的原因。 請仔細檢查它們! 文件可能會令人感到困惑,因為許多較舊的頁面和範例參考在 Direct3D 11 之前的不同 HLSL 語義版本。
- 確保您知道每個著色器所針對的特定 Direct3D 功能級別。 功能層級 9_* 的語意與 11_1 的語意不同。
- SV_POSITION語意會將關聯的插補後位置數據解析為座標值,其中 x 介於 0 與轉譯目標寬度之間,y 介於 0 與轉譯目標高度之間,z 除以原始同質座標 w 值 (z/w),而 w 是 1 除以原始 w 值 (1/w)。
相關主題
如何:將簡單的 OpenGL ES 2.0 轉譯器移植到 Direct3D 11