共用方式為


移植 GLSL

重要的應用程式介面

一旦您完成將用于建立和配置緩衝區和著色器對象的程式碼轉移後,就可以開始將這些著色器內的程式碼從 OpenGL ES 2.0 的 GL 著色器語言(GLSL)移植到 Direct3D 11 的高階著色器語言(HLSL)。

在OpenGL ES 2.0中,著色器會使用 gl_Positiongl_FragColorgl_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

移植著色器物件

轉移頂點緩衝區和資料

繪製至螢幕