共用方式為


比較 OpenGL ES 2.0 著色器流程與 Direct3D

重要 API

在概念上,Direct3D 11 著色器流程與 OpenGL ES 2.0 中的流程非常相似。 然而,就 API 設計而言,用於建立和管理著色器階段的主要元件是兩個主要介面 ID3D11Device1ID3D11DeviceContext1 的一部分。 本主題嘗試將常見的 OpenGL ES 2.0 著色器流程 API 模式對應至這些介面中的 Direct3D 11 對等專案。

檢視 Direct3D 11 著色器流程

著色器物件是使用 ID3D11Device1 面上建立的,例如 ID3D11Device1::CreateVertexShader ID3D11Device1::CreatePixelShader。

Direct3D 11 圖形流程由 ID3D11DeviceContext 1 介面的執行個體管理,並具備下列階段:

(也有幾何著色器、外殼著色器、鑲嵌器和領域著色器的階段,但由於它們在 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_VIEWPORTID3D11DeviceContext::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。