Direct3D效果框架

一、概述

        一種繪製效果通常由以下幾部分構成:一個頂點着色器、一個像素着色器、一個需要設置的設備狀態列表、一條或多條繪製路徑。我們希望採用一種低效運行機制針對不同級別的圖形硬件的繪製效果(即,在現有硬件條件下,物盡其用,實現與理想效果儘可能接近的效果)。顯然,所有的繪製任務都是與某一種效果相關。所以,將這些任務封裝到一個單元中是比較符合邏輯的。

     Direct3D效果框架(effects framework)爲上述的任務封裝提供了一種機制,該機制能夠將與繪製效果相關的任務封裝到一個效果文件(effect file)中。在效果文件中實現各種效果有諸多優點。其中之一是無需重新編譯應用程序的源代碼便可改變某種效果的實現。這樣就使得效果的更新過程,無論是修正 bug、簡單的效果增強或利用最新的 3D 硬件性能都變得更容易。其次,它把與效果相關的所有部件都封裝到了一個文件中,這就程序的維護帶來了極大的便利。

二、手法與路徑

     一個效果文件中包含了一種或多種手法(technique)。手法是繪製某些特效的特定方法。即效果文件爲繪製同樣的特效提供了一種或多種不同的方式。由於一些硬件可能不支持某種效果的具體實現,所以,很有必要針對不同級別的硬件實現同樣效果的不同版本。

     每種手法都包含了一條或多條繪製路徑(rendering pass)。繪製路徑封裝了設備狀態、採樣器以及(或)用於爲該條特定繪製路徑繪製幾何體的着色器。使用多條路徑的原因是由於想要實現某些特效,必須對每條路徑,以不同的繪製狀態和着色器將同一幾何體進行多次繪製。

     效果並不侷限於在可編程流水線中使用,例如,效果也可用於固定功能流水線中對設備狀態(如光照、材質和紋理等)進行控制。

三、效果文件中的設備狀態

        通常,要想正確實現某種效果,我們必須對設備狀態(例如繪製狀態、紋理狀態、材質、光照、紋理等)進行設置。爲了支持將某一完整的效果封裝在一個效果文件中的這種能力,效果框架允許我們在效果文件中對設備狀態進行設置。設備狀態的設置應位於某一繪製路徑的代碼中,語法如下所示:

     State = Value;

四、效果文件的使用步驟

1、創建效果

     HRESULT   D3DXCreateEffectFromFileA(
       LPDIRECT3DDEVICE9               pDevice,
       LPCSTR                          pSrcFile,
       CONST D3DXMACRO*                pDefines,
       LPD3DXINCLUDE                   pInclude,
       DWORD                           Flags,
       LPD3DXEFFECTPOOL                pPool,
       LPD3DXEFFECT*                   ppEffect,
       LPD3DXBUFFER*                   ppCompilationErrors);

2、效果句柄的獲取

   使用某種手法的第一步是獲取該手法的D3DXHANDLE句柄,獲取方法如下:

   D3DXHANDLE ID3DXEffect ::GetTechniqueByName(LPCSTR  pName);

3、效果的激活

  一旦獲取了所要採取的手法的句柄,接下來我們必須激活該手法。方法如下:

  HRESULT  ID3DXEffect ::SetTechnique(D3DXHANDLE  hTechnique);

4、效果的啓用

    爲了使用某種效果繪製幾何體,我們必須將所有的繪製函數調用都寫在函數ID3DXEffect::Begin 和ID3DXEffect::End之間。這兩個函數實質上分別起到了啓用(enable)和禁用(disable)的功能。

    HRESULT  ID3DXEffect::Begin ( UINT*  pPasses, DWORD  Flags);

   ●pPasses   返回當前處於活動狀態的手法中的路徑數目。
   ●Flags     該參數可取自下列任何標記:
       ◆Zero(0)  指示效果要保存當前設備狀態和着色器狀態,並在效果完成後(調用IDEDXEffect::End 函數後)恢復這些狀態。
       ◆D3DXFX_DONOTSAVESTATE   指示效果不保存也不恢復設備狀態(着色器狀態除外)。
       ◆D3DXFX_DONOTSAVESHADERSTATE 指示效果不保存也不必恢復着色器狀態。

5、當前繪製路徑的設置

     在我們使用一種效果繪製任何幾何體之前,我們必須指定所要使用的繪製路徑。指定方法爲:在繪製幾何體之前,應首先調用 ID3DXEffect::BeginPass 方法,該方法接受一個標識了當前活動路徑的參數,幾何體繪製完畢後,還必須調用 ID3DXEffect::EndPass 方法來終止當前活動路徑。即 ID3DXEffect::BeginPass 方法和 ID3DXEffect::EndPass 方法必須成對出現,完成實際繪製的代碼應該放在這兩個函數之間,而且這兩個函數必須位於函數對  ID3DXEffect::Begin 和 ID3DXEffect::End 之間。

6、效果的終止

  最終,當在每條路徑中繪製完幾何體後,我們應調用函數  ID3DXEffect::End 來禁用或終止該效果。

五、源代碼

1、效果文件

// Globals
matrix ViewProjMatrix;

// Structures
struct VS_INPUT
{
    vector position  : POSITION;
    vector color : COLOR;
};

struct VS_OUTPUT
{
    vector position : POSITION;
    vector diffuse  : COLOR;
};

struct PS_INPUT
{
    vector color : COLOR;
};

struct PS_OUTPUT
{
    vector diffuse  : COLOR;
};

VS_OUTPUT vshader(VS_INPUT input)
{
    VS_OUTPUT output = (VS_OUTPUT)0;

    output.position = mul(input.position, ViewProjMatrix);
    output.diffuse = input.color;

    return output;
}

PS_OUTPUT pshader(PS_INPUT input)
{
    // zero out members of output
    PS_OUTPUT output = (PS_OUTPUT)0;

    output.diffuse = input.color;

    return output;
}

sampler ShadeSampler = sampler_state
{
    MinFilter = POINT;
    MagFilter = POINT;
    MipFilter = NONE;
};

technique MEFFECT
{
    pass P0
    {
        vertexShader = compile vs_1_1 vshader();
        pixelShader = compile ps_2_0 pshader();

        Sampler[0] = (ShadeSampler);
    }
}

2、程序代碼

#include <Windows.h>
#include <mmsystem.h>
#include <d3dx9.h>
#pragma warning( disable : 4996 ) // disable deprecated warning 
#include <strsafe.h>
#pragma warning( default : 4996 )
#include <d3dx9math.h>

LPDIRECT3D9             g_pD3D = NULL; 
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; 
LPDIRECT3DVERTEXDECLARATION9 VertexDecl = NULL;
ID3DXEffect* m_Effect    = NULL;
D3DXHANDLE m_TechHandle      = NULL;
D3DXHANDLE ViewProjMatrixHandle = NULL;

struct CUSTOMVERTEX
{
    FLOAT x, y, z;
    DWORD color;
};

bool Effect()
{
    ID3DXBuffer* errorBuffer = 0;
    HRESULT hr = D3DXCreateEffectFromFile(
        g_pd3dDevice,           // associated device
        "shade.txt", // effect filename
        0,                // no preprocessor definitions
        0,                // no ID3DXInclude interface
        D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, // compile flags
        0,                // don't share parameters
        &m_Effect,      // return effect
        &errorBuffer);    // return error messages

    // output any error messages
    if( errorBuffer )
    {
        ::MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);
        errorBuffer->Release();
    }

    if(FAILED(hr))
    {
        ::MessageBox(0, "D3DXCreateEffectFromFile() - FAILED", 0, 0);
        return false;
    }

    return true;
}

bool VertexBuffer()
{
    if(g_pVB)
        return true;

    g_pd3dDevice->CreateVertexBuffer(
        3 * sizeof(CUSTOMVERTEX), 
        0,
        0,
        D3DPOOL_MANAGED,
        &g_pVB,
        0);

    CUSTOMVERTEX* v;
    g_pVB->Lock(0, 0, (void**)&v, 0);

    v[0].x = -1, v[0].y = -1, v[0].z = 0, v[0].color = D3DCOLOR_XRGB(255, 0, 0);
    v[1].x = 0, v[1].y = 1, v[1].z = 0, v[1].color = D3DCOLOR_XRGB(0, 255, 0);
    v[2].x = 1, v[2].y = -1, v[2].z = 0, v[2].color = D3DCOLOR_XRGB(0, 0, 255);

    g_pVB->Unlock();
    return true;
}

bool VertexDeclaration()
{
    if(VertexDecl)
        return true;

    D3DVERTEXELEMENT9 decl[] = 
    {
        {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
        {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
        D3DDECL_END()
    };
    g_pd3dDevice->CreateVertexDeclaration(decl, &VertexDecl);
    g_pd3dDevice->SetVertexDeclaration(VertexDecl);

    return true;
}

bool GetHandles()
{
    if(m_TechHandle)
        return true;

    m_TechHandle = m_Effect->GetTechniqueByName("MEFFECT");
    ViewProjMatrixHandle = m_Effect->GetParameterByName(0, "ViewProjMatrix");

    return true;
}

HRESULT InitD3D(HWND hWnd)
{
    if (NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
        return E_FAIL;

    // Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
    // Create the D3DDevice
    if (FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
        &d3dpp, &g_pd3dDevice)))
    {
        return E_FAIL;
    }
    return S_OK;
}

VOID SetupMatrices()
{
    D3DXVECTOR3 vEyePt(0.0f, 0.0f, -5);
    D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);
    D3DXMATRIXA16 matView;
    D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);

    //D3DXMatrixPerspectiveFovLH()函數中的最遠、最近距離爲相對於視點的距離(即vEyePt中的距離)
    D3DXMATRIXA16 matProj;
    D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 200.0f);

    D3DXMATRIX ViewProjMatrix = matView * matProj;
    m_Effect->SetMatrix(ViewProjMatrixHandle, &ViewProjMatrix);
}

VOID Cleanup()
{
    if (g_pVB != NULL)
        g_pVB->Release();

    if (g_pd3dDevice != NULL)
        g_pd3dDevice->Release();

    if (g_pD3D != NULL)
        g_pD3D->Release();

    if (VertexDecl != NULL)
        VertexDecl->Release();

    if (m_Effect != NULL)
        m_Effect->Release();

}

int Render()
{
    g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0);

    if (SUCCEEDED(g_pd3dDevice->BeginScene()))
    {
        m_Effect->SetTechnique( m_TechHandle );

        UINT numPasses = 0;
        m_Effect->Begin(&numPasses, 0);

        for(int i = 0; i < numPasses; i++)
        {
            m_Effect->BeginPass(i);

            g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));

            g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
            g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
            g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
            g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,1);

            m_Effect->EndPass();
        }

        m_Effect->End();

        g_pd3dDevice->EndScene();
    }
    g_pd3dDevice->Present(NULL, NULL, NULL, NULL);

    return 0;
}

LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY:
        Cleanup();
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

void InitShader()
{
    VertexBuffer();
    VertexDeclaration();
    Effect();
    GetHandles();
    SetupMatrices();
}

INT WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, INT)
{
    UNREFERENCED_PARAMETER(hInst);

    // Register the window class
    WNDCLASSEX wc =
    {
        sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
        GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
        "D3D Tutorial", NULL
    };
    RegisterClassEx(&wc);

    // Create the application's window
    HWND hWnd = CreateWindow("D3D Tutorial", "D3D: Effect with shader",
        WS_OVERLAPPEDWINDOW, 100, 100, 700, 700,
        NULL, NULL, wc.hInstance, NULL);

    if (SUCCEEDED(InitD3D(hWnd)))
    {
            ShowWindow(hWnd, SW_SHOWDEFAULT);
            UpdateWindow(hWnd);

            InitShader();

            MSG msg;
            ZeroMemory(&msg, sizeof(msg));
            while (msg.message != WM_QUIT)
            {
                if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
                else
                    Render();
            }
    }

    UnregisterClass("D3D Tutorial", wc.hInstance);
    return 0;
}

3、運行效果


作者:Spring_24
來源:CSDN
原文:https://blog.csdn.net/Spring_24/article/details/78273187
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章