比較 OpenGL ES 2.0 著色器流程與 Direct3D
重要 API
- Input-Assembler 階段
- 頂點著色器階段
- 畫素著色器舞台
在概念上,Direct3D 11 著色器流程與 OpenGL ES 2.0 中的流程非常相似。 然而,就 API 設計而言,用於建立和管理著色器階段的主要元件是兩個主要介面 ID3D11Device1 和 ID3D11DeviceContext1 的一部分。 本主題嘗試將常見的 OpenGL ES 2.0 著色器流程 API 模式對應至這些介面中的 Direct3D 11 對等專案。
檢視 Direct3D 11 著色器流程
著色器物件是使用 ID3D11Device1 介面上的方法建立的,例如 ID3D11Device1::CreateVertexShader 和 ID3D11Device1::CreatePixelShader。
Direct3D 11 圖形流程由 ID3D11DeviceContext 1 介面的執行個體管理,並具備下列階段:
- Input-Assembler 階段。 輸入組裝器級向流程提供資料 (三角形、線和點)。 支援此階段的 ID3D11DeviceContext1 方法以 IA 為字首。
- 頂點著色器階段:頂點著色器階段處理頂點,通常執行變換、蒙皮和照明等操作。 頂點著色器一律會取一個輸入頂點,並產生一個輸出頂點。 支援此階段的 ID3D11DeviceContext1 方法以 VS 為字首。
- Stream-Output Stage:串流輸出階段會將原始資料從流程串流到記憶體,並傳送至點陣化程式。 資料可以串流輸出和/或傳送到點陣化程式。 流出到儲存器的資料可以作為輸入資料再循環回流程或從 CPU 讀回。 支援此階段的 ID3D11DeviceContext1 方法以 SO 為字首。
- 點陣化程式舞台:點陣化程式會裁剪原件、準備畫素著色器的原件,以及決定如何叫用畫素著色器。 您可以停用點陣化,方法是通知流程沒有畫素著色器 (使用 ID3D11DeviceContext::PSSetShader,將畫素著色器舞台設定為 NULL),以及停用深度與樣板測試 (在 D3D11_DEPTH_STENCIL_DESC 中將 DepthEnable 與 StencilEnable 設定為 FALSE)。 停用時,光柵化相關的流程計數器將不會更新。
- Pixel-Shader Stage - 像素著色器階段會接收原始專案的內插資料,並產生每個畫素的資料 (例如顏色)。 支援此階段的 ID3D11DeviceContext1 方法以 PS 為字首。
- Output-Merger Stage:輸出合併階段將各種型別的輸出資料 (畫素著色器值、深度和模板資訊) 與渲染目標和深度/模板緩衝區的內容合併,以生成最終流程結果。 支援此階段的 ID3D11DeviceContext1 方法以 OM 為字首。
(也有幾何著色器、外殼著色器、鑲嵌器和領域著色器的階段,但由於它們在 OpenGL ES 2.0 中沒有類似物件,因此我們不在此討論。) 如需這些階段的完整方法清單,請參閱 ID3D11DeviceContext and ID3D11DeviceContext1 參考頁面。 ID3D11DeviceContext1,為 Direct3D 11 擴充 ID3D11DeviceContext。
建立著色器
在 Direct3D 中,在編譯和載入著色器資源之前,不會建立著色器資源;相反,當載入 HLSLis 時,會建立資源。 因此,沒有與 glCreateShader 直接類似的函式,後者會建立特定型別 (例如 GL_VERTEX_SHADER 或 GL_FRAGMENT_SHADER) 的初始化著色器資源。 相反,著色器是在載入 HLSL 後建立的,載入諸如 ID3D11Device1::CreateVertexShader、ID3D11Device1::CreatePixelShader 等特定函式,這些函式將型別和編譯的 HLSL 作為參數。
OpenGL ES 2.0 | Direct3D 11 |
---|---|
glCreateShader | 在成功載入編譯的著色器物件,並傳遞為緩衝區後,呼叫 ID3D11Device1::CreateVertexShader 和 ID3D11Device1::CreatePixelShader。 |
編譯著色器
Direct3D 著色器必須在 Universal Windows Platform (UWP) 應用程式中預先編譯為已編譯的著色器物件 (.cso) 檔案,並使用其中一個 Windows 執行階段檔案 API 載入。 (桌面應用程式可以在執行階段從文字檔或字串編譯著色器。) CSO檔案是從屬於Microsoft Visual Studio專案的任何.hlsl檔案建置的,且保留相同的名稱,但只具有.cso檔案副檔名。 運貨時,請將它們包含在包裝中!
OpenGL ES 2.0 | Direct3D 11 |
---|---|
glCompileShader | N/A。 在 Visual Studio 中將著色器編譯為 .cso 檔案,並將它們包含在套件中。 |
將 glGetShaderiv 用於編譯狀態 | N/A。 如果編譯中有錯誤,請參閱 Visual Studio 的 FX 編譯器 (FXC) 的編譯輸出。 如果編譯成功,則會建立對應的 CSO 檔案。 |
載入著色器
如建立著色器一節所述,當對應的 CSO 檔案載入緩衝區並傳遞至下表中的其中一個方法時,Direct3D 11 會建立著色器。
OpenGL ES 2.0 | Direct3D 11 |
---|---|
ShaderSource | 成功載入編譯的著色器物件後,呼叫 ID3D11Device1::CreateVertexShader 和 ID3D11Device1::CreatePixelShader。 |
設定流程
OpenGL ES 2.0 有著色器程式物件,其中包含多個用於執行的著色器。 個別著色器會附加至著色器程式物件。 不過,在 Direct3D 11 中,您會直接使用轉譯前後關聯 (ID3D11DeviceContext1),並在它上建立著色器。
OpenGL ES 2.0 | Direct3D 11 |
---|---|
glCreateProgram | N/A。 Direct3D 11 不使用著色器程式物件抽象。 |
glLinkProgram | N/A。 Direct3D 11 不使用著色器程式物件抽象。 |
glUseProgram | N/A。 Direct3D 11 不使用著色器程式物件抽象。 |
glGetProgramiv | 使用您建立給 ID3D11DeviceContext1 的參照。 |
使用靜態 D3D11CreateDevice 方法建立 ID3D11DeviceContext1 和 ID3D11Device1 的執行個體。
Microsoft::WRL::ComPtr<ID3D11Device1> m_d3dDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext1> m_d3dContext;
// ...
D3D11CreateDevice(
nullptr, // Specify nullptr to use the default adapter.
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
creationFlags, // Set set debug and Direct2D compatibility flags.
featureLevels, // List of feature levels this app can support.
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for UWP apps.
&device, // Returns the Direct3D device created.
&m_featureLevel, // Returns feature level of device created.
&m_d3dContext // Returns the device's immediate context.
);
設定視角
在 Direct3D 11 中設定視角與在 OpenGL ES 2.0 中設定視角的方式非常相似。 在 Direct3D 11 中,呼叫 ID3D11DeviceContext::RSSetViewports (具有設定的 CD3D11_VIEWPORT)。
Direct3D 11:設定視角。
CD3D11_VIEWPORT viewport(
0.0f,
0.0f,
m_d3dRenderTargetSize.Width,
m_d3dRenderTargetSize.Height
);
m_d3dContext->RSSetViewports(1, &viewport);
OpenGL ES 2.0 | Direct3D 11 |
---|---|
glViewport | CD3D11_VIEWPORT、ID3D11DeviceContext::RSSetViewports |
設定頂點著色器
在 Direct3D 11 中配置頂點著色器會在載入著色器時完成。 使用 ID3D11DeviceContext1::VSSetConstantBuffers1,將校服傳遞為常數緩衝區。
OpenGL ES 2.0 | Direct3D 11 |
---|---|
glAttachShader | ID3D11Device1::CreateVertexShader |
glGetShaderiv、glGetShaderSource | ID3D11DeviceContext1::VSGetShader |
glGetUniformfv、glGetUniformiv | ID3D11DeviceContext1::VSGetConstantBuffers1。 |
設定畫素著色器
在 Direct3D 11 中設定畫素著色器會在載入著色器時完成。 使用 ID3D11DeviceContext1::PSSetConstantBuffers1 將校服傳遞為常數緩衝區。
OpenGL ES 2.0 | Direct3D 11 |
---|---|
glAttachShader | ID3D11Device1::CreatePixelShader |
glGetShaderiv、glGetShaderSource | ID3D11DeviceContext1::PSGetShader |
glGetUniformfv、glGetUniformiv | ID3D11DeviceContext1::PSGetConstantBuffers1。 |
正在產生最終結果
當流程完成時,將著色器階段的結果繪製到後緩衝區。 在 Direct3D 11 中,就像使用 Open GL ES 2.0 一樣,這牽涉到呼叫繪製命令,將結果輸出為後台緩衝區中的色彩對應,然後將該返回緩衝區傳送至顯示器。
OpenGL ES 2.0 | Direct3D 11 |
---|---|
glDrawElements | ID3D11DeviceContext1::Draw、ID3D11DeviceContext1::DrawIndexed (或 ID3D11DeviceContext1 上的其他 Draw* 方法)。 |
eglSwapBuffers | IDXGISwapChain1::Present1 |
將 GLSL 移轉至 HLSL
GLSL 和 HLSL 除複雜的型別支援和語法一些整體的語法之外,並沒有很大的不同。 許多開發者發現兩者之間連線最容易的是將常見的 OpenGL ES 2.0 指令和定義混疊到他們的 HLSL 等價物上。 請備註,Direct3D 使用 Shader Model 版本來表示圖形介面所支援的 HLSL 功能集;OpenGL 對 HLSL 有不同的版本規格。 下表試圖根據另一個版本為您提供有關為 Direct3D 11和 OpenGL ES 2.0 定義的著色器語言功能集的一些大致概念。
著色器語言 | GLSL 功能版本 | Direct3D 著色器模型 |
---|---|---|
Direct3D 11 HLSL | ~4.30。 | SM 5.0 |
適用於 OpenGL ES 2.0 的 GLSL ES | 1.40。 舊的 OpenGL ES 2.0 的 GLSL ES 實現可以使用 1.10 到 1.30。 使用 glGetString (GL_SHADING_LANGUAGE_VERSION) 或 glGetString (SHADING_LANGUAGE_VERSION) 檢查原始程式碼以判定它。 | ~SM 2.0 |
如需有關兩種著色器語言之間差異的詳細資訊,以及一般語法對應,請閱讀 GLSL-to-HLSL reference。
將 OpenGL 內部函式移植到 HLSL 語義
Direct3D 11 HLSL 語義是字串,類似於統一或屬性名稱,用來識別在應用程式與著色器程式之間傳遞的值。 雖然它們可以是任何可能的字串,但最佳做法是使用表示用途的字串,如 POSITION 或 COLOR。 當您建構常數緩衝區或緩衝區輸入配置時,可以指定這些語意。 您也可以將 0 到 7 之間的數字附加到語義,以便使用單獨的暫存器來表示類似的值。 例如:COLOR0、COLOR1、COLOR2...
前置為 SV_ 的語義是由著色器程式寫入的系統值語義;您的應用程式本身 (在 CPU 上執行)無法修改它們。 通常,這些值包含來自圖形流程中另一個著色器階段的輸入或輸出,或完全由 GPU 生成的值。
此外,SV_ 語義在用於指定著色器階段的輸入或輸出時具有不同的行為。 例如,SV_POSITION (輸出) 包含頂點著色器階段期間轉換的頂點資料,而 SV_POSITION (輸入) 包含點陣化期間內插的畫素位置值。
以下是一些常見的 OpenGL ES 2.0 著色器內建對應:
OpenGL 系統值 | 使用此 HLSL 語義 |
---|---|
gl_Position | 頂點緩衝區資料的 POSITION (n)。 SV_POSITION 會提供畫素位置給畫素著色器,且無法由應用程式寫入。 |
gl_Normal | NORMAL (n),表示由頂點緩衝區提供的法向資料。 |
gl_TexCoord[n] | 紋理 UV 的 TEXCOORD (n) (某些 OpenGL 文件中的 ST) 座標資料提供給著色器。 |
gl_FragColor | 提供給著色器的 RGBA 色彩資料的 COLOR (n)。 請備註,在協調資料時,會一併處理它;語義只是協助您識別它是色彩資料。 |
gl_FragData[n] | SV_Target[n],用於從畫素著色器寫入到目標紋理或其他畫素緩衝區。 |
您為語義編寫程式碼的方法與在 OpenGL ES 2.0 中使用內部函式的方法不同。 在 OpenGL 中,您可以直接存取許多內建函式,而不需任何組態或宣告;在 Direct3D 中,您必須在特定常數緩衝區中宣告欄位,才能使用特定的語義,或宣告它是著色器 main () 方法的傳回值。
以下是常數緩衝區定義中使用的語意範例:
struct VertexShaderInput
{
float3 pos : POSITION;
float3 color : COLOR0;
};
// The position is interpolated to the pixel value by the system. The per-vertex color data is also interpolated and passed through the pixel shader.
struct PixelShaderInput
{
float4 pos : SV_POSITION;
float3 color : COLOR0;
};
這個程式碼定義一對簡單的常數緩衝區
下面是一個用來定義片段著色器所傳回值的語意範例:
// A pass-through for the (interpolated) color data.
float4 main(PixelShaderInput input) : SV_TARGET
{
return float4(input.color,1.0f);
}
在這種情況下,SV_TARGET 是在著色器完成執行時寫入畫素顏色 (定義為具有四個浮點值的向量) 的渲染目標位置。
如需在 Direct3D 中使用語意的詳細資訊,請閱讀 HLSL Semantics。