共用方式為


移植 GLSL

重要 API

一旦您完成了建立和設定緩衝區和著色器物件的程式碼,就可以將這些著色器內的程式碼從 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;

語意可以在著色器的主體 (主要) 方法上宣告。 像素著色器,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 矩陣,以及兩個 4 座標向量。 這兩個向量包含頂點位置及其色彩。 著色器將位置向量轉換為透視座標,並將其指派給 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 語意進行了專門標記:位置和色彩。 由於我們的輸入配置會指出這兩個頂點值的特定排列方式,因此您會建立結構來保存它們,並將其宣告為著色器主體函式 (主要) 上輸入參數的類型。 (您也可以將它們指定為兩個個別參數,但這可能會變得麻煩。) 您也會指定這個階段的輸出類型,其中包含插補位置和色彩,並將其宣告為頂點著色器主體函式的傳回值。

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

移植著色器物件

移植頂點緩衝區和資料

繪製到螢幕