天天看點

DirectX11筆記(十二)--Direct3D渲染8--EFFECTS概述Effect FilesCompiling Shaders建立 Effect示例

  • 概述
  • Effect Files
  • Compiling Shaders
  • 建立 Effect
  • 示例

概述

  Effect Framework 是一個工具代碼的集合, 他提供了一個架構用于組織 shader 和渲染狀态, 并由他們共同實作某種效果.

  在 DX11 中使用 Effect 需要包含 d3dx11Effect.h 頭檔案, 并連結 D3DX11Effects.lib 和 D3DX11EffectsD.lib 庫. 頭檔案在 DirectX SDK\Samples\C++\Effects11\Inc 目錄下, 兩個需要使用的庫需要建構 Effects11 自行生成.

Effect Files

  .fx 檔案和 .cpp 檔案 .h 檔案一樣, 也是普通的文本檔案. 他存儲着之前我們見到的 shader 程式.

  在 fx 檔案中多出來的是 technique 和 pass. 一個 effect 至少包含一個 technique, 而一個 technique 至少包含一個pass. 每個 pass 至少包含一個 VS, [GS, tessellation 可選], 一個 PS ( 可選但是一般都會有 ), [渲染狀态 可選]. 每個 technique 至少有一個 pass 用來實作特定的渲染效果.

  下面是一個完整的 Effect Files例子.

cbuffer cbPerObject
{
    float4x4 gWorldViewProj;
};
struct VertexIn
{
    float3 Pos : POSITION;
    float4 Color : COLOR;
};
struct VertexOut
{
    float4 PosH : SV_POSITION;
    float4 Color : COLOR;
};
VertexOut VS(VertexIn vin)
{
    VertexOut vout;
    // Transform to homogeneous clip space.
    vout.PosH = mul(float4(vin.Pos, ), gWorldViewProj);
    // Just pass vertex color into the pixel shader.
    vout.Color = vin.Color;
    return vout;
}
float4 PS(VertexOut pin) : SV_Target
{
    return pin.Color;
}
technique11 ColorTech
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_0, VS() ) );
        SetPixelShader( CompileShader( ps_5_0, PS() ) );
    }
}
           

  對于渲染狀态, 我們也可以在 fx 檔案中直接設定, 當有一些特别需求的時候這個特性是友善的, 但是當狀态很多時我們還是應該在應用層面上進行管理, 這樣才便于對複雜的渲染狀态進行切換.

  下面是一個直接設定 Rasterizer State 的示例.

RasterizerState WireframeRS
{
    FillMode = Wireframe;
    CullMode = Back;
    FrontCounterClockwise = false;
    // Default values used for any properties we do not set.
};
technique11 ColorTech
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_5_, VS() ) );
        SetPixelShader( CompileShader( ps_5_, PS() ) );
        SetRasterizerState(WireframeRS);
    }
}
           

Compiling Shaders

  實作某種效果的第一步便是将之前 .fx 檔案中存儲的 shader 程式進行編譯. 我們需要用到 DX11 中的 D3DX11CompileFromFile 方法.

HRESULT D3DX11CompileFromFile(
    LPCTSTR pSrcFile,
    CONST D3D10_SHADER_MACRO *pDefines,
    LPD3D10INCLUDE pInclude,
    LPCSTR pFunctionName,
    LPCSTR pProfile,
    UINT Flags1,
    UINT Flags2,
    ID3DX11ThreadPump *pPump,
    ID3D10Blob **ppShader,
    ID3D10Blob **ppErrorMsgs,
    HRESULT *pHResult);
           
  1. pSrcFile: .fx 檔案的名字.
  2. pFunctionName: 這是 shader 的入口函數名, 但是這隻在單獨編譯 shader 時有用, 在使用 Effect 架構的時候傳空就可以了, 這個入口函數已經在 technique 的 pass 中聲明好了.
  3. pProfile: 指明 shader 的版本.
  4. Flags1: 表示我們将如何編譯 shader, 他有若幹個有效值, 我們會用到兩個, D3D10_SHADER_DEBUG 和 D3D10_SHADER_SKIP_OPTIMIZATION ( 隻在 debug 時有效 )
  5. ppShader: 函數傳回的一個 ID3D10Blob 的指針, 他存儲着編譯出來的 shader.
  6. ppErrorMsgs: 函數傳回的一個 ID3D10Blob 的指針, 他存儲着編譯時的報錯資訊.
  7. 其他的屬性都是跟進階的用法, 我們在學習過程中不需要使用, 設定為預設值即可.

  其中 ID3D10Blob 表示的其實就是一個記憶體塊, 他隻有 GetBufferPointer 和 GetBufferSize 兩個方法用來操作這塊記憶體.

建立 Effect

  在編譯完 shader 之後我們需要使用 D3DX11CreateEffectFromMemory 方法來建立 effect.

HRESULT D3DX11CreateEffectFromMemory(
    void *pData,
    SIZE_T DataLength,
    UINT FXFlags,
    ID3D11Device *pDevice,
    ID3DX11Effect **ppEffect);
           
  1. pData: .fx 檔案的内容.
  2. DataLength: .fx 檔案的長度.
  3. FXFlags: 與之前編譯 shader 時的 Flags2 對應.
  4. pDevice: 渲染裝置指針.
  5. ppEffect: 傳回的 Effect 指針.

示例

DWORD shaderFlags = ;

#if defined(DEBUG) || defined(_DEBUG)

shaderFlags |= D3D10_SHADER_DEBUG;
shaderFlags |= D3D10_SHADER_SKIP_OPTIMIZATION;

#endif

ID3D10Blob* compiledShader = ;
ID3D10Blob* compilationMsgs = ;
HRESULT hr = D3DX11CompileFromFile(L"color.fx", ,
    , , "fx_5_0", shaderFlags,
    , , &compiledShader, &compilationMsgs, );

// compilationMsgs can store errors or warnings.
if(compilationMsgs != )
{
    MessageBoxA(, (char*)compilationMsgs->GetBufferPointer(), , );
    ReleaseCOM(compilationMsgs);
}

// Even if there are no compilationMsgs,
// check to make sure there were no other errors.
if(FAILED(hr))
{
    DXTrace(__FILE__, (DWORD)__LINE__, hr,
L"D3DX11CompileFromFile", true);
}
ID3DX11Effect* mFX;
HR(D3DX11CreateEffectFromMemory(
    compiledShader->GetBufferPointer(),
    compiledShader->GetBufferSize(),
    , md3dDevice, &mFX));

// Done with compiled shader.
ReleaseCOM(compiledShader);
           

繼續閱讀