共用方式為


串流輸出階段使用者入門

本節說明如何搭配資料流程輸出階段使用幾何著色器。

編譯幾何著色器

此幾何著色器 (GS) 會計算每個三角形的一般臉部,並輸出位置、一般和紋理座標資料。

struct GSPS_INPUT
{
    float4 Pos : SV_POSITION;
    float3 Norm : TEXCOORD0;
    float2 Tex : TEXCOORD1;
};

[maxvertexcount(12)]
void GS( triangle GSPS_INPUT input[3], inout TriangleStream<GSPS_INPUT> TriStream )
{
    GSPS_INPUT output;
    
    //
    // Calculate the face normal
    //
    float3 faceEdgeA = input[1].Pos - input[0].Pos;
    float3 faceEdgeB = input[2].Pos - input[0].Pos;
    float3 faceNormal = normalize( cross(faceEdgeA, faceEdgeB) );
    float3 ExplodeAmt = faceNormal*Explode;
    
    //
    // Calculate the face center
    //
    float3 centerPos = (input[0].Pos.xyz + input[1].Pos.xyz + input[2].Pos.xyz)/3.0;
    float2 centerTex = (input[0].Tex + input[1].Tex + input[2].Tex)/3.0;
    centerPos += faceNormal*Explode;
    
    //
    // Output the pyramid
    //
    for( int i=0; i<3; i++ )
    {
        output.Pos = input[i].Pos + float4(ExplodeAmt,0);
        output.Pos = mul( output.Pos, View );
        output.Pos = mul( output.Pos, Projection );
        output.Norm = input[i].Norm;
        output.Tex = input[i].Tex;
        TriStream.Append( output );
        
        int iNext = (i+1)%3;
        output.Pos = input[iNext].Pos + float4(ExplodeAmt,0);
        output.Pos = mul( output.Pos, View );
        output.Pos = mul( output.Pos, Projection );
        output.Norm = input[iNext].Norm;
        output.Tex = input[iNext].Tex;
        TriStream.Append( output );
        
        output.Pos = float4(centerPos,1) + float4(ExplodeAmt,0);
        output.Pos = mul( output.Pos, View );
        output.Pos = mul( output.Pos, Projection );
        output.Norm = faceNormal;
        output.Tex = centerTex;
        TriStream.Append( output );
        
        TriStream.RestartStrip();
    }
    
    for( int i=2; i>=0; i-- )
    {
        output.Pos = input[i].Pos + float4(ExplodeAmt,0);
        output.Pos = mul( output.Pos, View );
        output.Pos = mul( output.Pos, Projection );
        output.Norm = -input[i].Norm;
        output.Tex = input[i].Tex;
        TriStream.Append( output );
    }
    TriStream.RestartStrip();
}

請記住該程式碼,請考慮幾何著色器看起來很像頂點或圖元著色器,但有下列例外狀況:函式傳回的類型、輸入參數宣告和內建函式。

項目 說明
函式傳回類型
函式傳回類型會執行一件事,宣告著色器可輸出的最大頂點數目。 在此情況下,
maxvertexcount(12)

定義輸出上限為 12 個頂點。

輸入參數宣告

此函式接受兩個輸入參數:

triangle GSPS_INPUT input[3] , inout TriangleStream<GSPS_INPUT> TriStream

第一個參數是由GSPS_INPUT結構定義的頂點陣列(在此案例中為 3)定義(將每個頂點資料定義為位置、一般和紋理座標)。 第一個參數也會使用三角形關鍵字,這表示輸入組合器階段必須將資料輸出至幾何著色器,做為其中一個三角形基本類型(三角形清單或三角形帶狀)。

第二個參數是由三角形Stream 類型所定義的三角形資料流程 < GSPS_INPUT > 。 這表示參數是三角形的陣列,每一個都由三個頂點組成(其中包含來自GSPS_INPUT成員的資料)。

使用三角形和三角形資料流程關鍵字來識別 GS 中的個別三角形或三角形資料流程。

內建函式

著色器函式中的程式程式碼使用 common-shader-core HLSL 內部函式,但最後兩行除外,這兩行會呼叫 Append 和 RestartStrip。 這些函式僅適用于幾何著色器。 Append 會通知幾何著色器將輸出附加至目前的等量;RestartStrip 會建立新的基本等量。 系統會在 GS 階段的每個調用中隱含建立新的等量。

著色器的其餘部分看起來非常類似頂點或圖元著色器。 幾何著色器會使用 結構來宣告輸入參數,並以SV_POSITION語意標記位置成員,以告訴硬體這是位置資料。 輸入結構會將其他兩個輸入參數識別為紋理座標(即使其中一個參數會包含臉部正常)。 如果您想要的話,可以針對臉部正常使用自己的自訂語意。

設計幾何著色器之後,請呼叫 D3DCompile 進行編譯,如下列程式碼範例所示。

DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
ID3DBlob** ppShader;

D3DCompile( pSrcData, sizeof( pSrcData ), 
  "Tutorial13.fx", NULL, NULL, "GS", "gs_4_0", 
  dwShaderFlags, 0, &ppShader, NULL );

就像頂點和圖元著色器一樣,您需要著色器旗標來告訴編譯器如何編譯著色器(針對偵錯、針對速度優化等等)、進入點函式,以及著色器模型來驗證。 此範例會使用 GS 函式,建立從 Tutorial13.fx 檔案建置的幾何著色器。 著色器會針對著色器模型 4.0 進行編譯。

使用資料流程輸出建立 Geometry-Shader 物件

一旦您知道要從幾何串流資料,而且您已成功編譯著色器,下一個步驟就是呼叫 ID3D11Device::CreateGeometryShaderWithStreamOutput 來建立幾何著色器物件。

但首先,您必須宣告資料流程輸出 (SO) 階段輸入簽章。 此簽章會比對或驗證物件建立時 GS 輸出和 SO 輸入。 下列程式碼是 SO 宣告的範例。

D3D11_SO_DECLARATION_ENTRY pDecl[] =
{
    // semantic name, semantic index, start component, component count, output slot
    { "SV_POSITION", 0, 0, 4, 0 },   // output all components of position
    { "TEXCOORD0", 0, 0, 3, 0 },     // output the first 3 of the normal
    { "TEXCOORD1", 0, 0, 2, 0 },     // output the first 2 texture coordinates
};

D3D11Device->CreateGeometryShaderWithStreamOut( pShaderBytecode, ShaderBytecodesize, pDecl, 
    sizeof(pDecl), NULL, 0, 0, NULL, &pStreamOutGS );

此函式會採用數個參數,包括:

  • 已編譯幾何著色器的指標(如果沒有幾何著色器,則為頂點著色器,且資料會直接從頂點著色器串流處理)。 如需如何取得此指標的詳細資訊,請參閱 取得已編譯著色器的 指標。
  • 宣告陣列的指標,描述資料流程輸出階段的輸入資料。 (請參閱 D3D11_SO_DECLARATION_ENTRY.)您最多可以提供 64 個宣告,每個不同類型的專案都可以從 SO 階段輸出。 宣告專案的陣列描述資料配置,而不論只有單一緩衝區或多個緩衝區是否要系結至資料流程輸出。
  • SO 階段所寫的專案數目。
  • 所建立之 geometry 著色器物件的指標(請參閱 ID3D11GeometryShader )。

在此情況下,緩衝區步幅為 Null、要傳送至點陣化程式的資料流程索引為 0,而類別連結介面為 Null。

資料流程輸出宣告會定義資料寫入緩衝區資源的方式。 您可以視需要新增至輸出宣告的元件數量。 使用 SO 階段來寫入單一緩衝區資源或許多緩衝區資源。 對於單一緩衝區,SO 階段可以為每個頂點寫入許多不同的元素。 對於多個緩衝區,SO 階段只能將每個頂點資料的單一元素寫入每個緩衝區。

若要在不使用幾何著色器的情況下使用 SO 階段,請呼叫 ID3D11Device::CreateGeometryShaderWithStreamOutput ,並將指標傳遞至 pShaderBytecode 參數。

設定輸出目標

最後一個步驟是設定 SO 階段緩衝區。 資料可以串流處理至記憶體中的一或多個緩衝區,以供稍後使用。 下列程式碼示範如何建立可用於頂點資料的單一緩衝區,以及 SO 階段將資料串流至 。

ID3D11Buffer *m_pBuffer;
int m_nBufferSize = 1000000;

D3D11_BUFFER_DESC bufferDesc =
{
    m_nBufferSize,
    D3D11_USAGE_DEFAULT,
    D3D11_BIND_STREAM_OUTPUT,
    0,
    0,
    0
};
D3D11Device->CreateBuffer( &bufferDesc, NULL, &m_pBuffer );

呼叫 ID3D11Device::CreateBuffer 來建立緩衝區。 此範例說明預設使用方式,這是 CPU 預期會相當頻繁更新的緩衝區資源。 系結旗標會識別資源可以系結至的管線階段。 SO 階段使用的任何資源也必須使用系結旗標來建立D3D10_BIND_STREAM_OUTPUT。

成功建立緩衝區之後,請呼叫 ID3D11DeviceCoNtext::SOSetTargets ,將它設定為目前的裝置:

UINT offset[1] = 0;
D3D11Device->SOSetTargets( 1, &m_pBuffer, offset );

此呼叫會接受緩衝區數目、緩衝區指標,以及位移陣列(每個緩衝區的位移,指出開始寫入資料的位置)。 呼叫繪製函式時,資料會寫入這些串流輸出緩衝區。 內部變數會追蹤開始將資料寫入串流輸出緩衝區的位置,而且該變數會繼續遞增,直到 再次呼叫 SOSetTargets 並指定新的位移值為止。

寫入目標緩衝區的所有資料都會是 32 位值。

資料流程輸出階段