像素着色器入門

一、像素着色器簡介

        像素着色器是在對每個像素進行光柵化處理期間運行在圖形卡GPU上的一段程序。(不同於頂點着色器,Direct3D不會以軟件運算方式來模擬像素着色器。)像素着色器實質上是取代固定功能流水線中的多重紋理(multitexturing)環節,而且賦予了我們直接操縱單個像素以及訪問每個像素的紋理座標的能力。這種對像素和紋理座標直接訪問的能力使得我們能夠獲得各種各樣的特殊效果,例如多重紋理、景深(depth of field)、雲彩模擬、火焰模擬以及比較複雜的陰影技術。

二、像素着色器的輸入和輸出

      像素着色器的輸入包括每個像素的顏色和紋理座標,輸出爲計算所得的每個像素的顏色值。

      每個像素的紋理座標其實就是指定了紋理中將被映射到當前像素的紋理元的座標(u , v)。在進入像素着色器之前,Direct3D先根據頂點顏色和頂點紋理座標計算出每個像素的顏色和紋理座標。輸入像素着色器的顏色和紋理座標對的個數由頂點着色器輸出的顏色和紋理座標對的個數決定。例如,如果一個頂點着色器輸出 2 種顏色和 3 個紋理座標對,則Direct3D將計算出每個像素的 2 種顏色值和 3 個紋理座標對,並將這些輸出結果輸入像素着色器。我們需藉助語義語法來將輸入的顏色和紋理座標映射爲像素着色器程序中的變量。對於上述例子,我們可以寫作:

       struct PS_INPUT
       {
            vector c0 : COLOR0;
            vector c1 : COLOR1;
            float2  t0  : TEXCOORD0;
            float2  t1  : TEXCOORD1;
            float3  t2  : TEXCOORD2;
      }

      struct PS_OUTPUT
      {
            vector finalPixelColor : COLOR0;
     }   

三、使用像素着色器的步驟

   (1)編寫像素着色器程序
 (2)編譯像素着色器程序。
 (3)創建一個LPDIRECT3DPIXELSHADER9接口對象,以表示經過編譯的着色器代碼的像素着色器。
 (4)用SetPixelShader方法啓用像素着色器。
 (5)調用像素着色器的Release方法釋放着色器。

  接下來詳細介紹每一步的具體操作:

1、編寫像素着色器程序

// Globals
sampler EarthTex;
sampler GalaxyTex;

// Structures
struct PS_INPUT
{
    float2 earth     : TEXCOORD0;
    float2 galaxy    : TEXCOORD1;
};

struct PS_OUTPUT
{
    vector diffuse : COLOR0;
};

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

    // sample appropriate textures
    vector b = tex2D(EarthTex,      input.earth);
    vector s = tex2D(GalaxyTex, input.galaxy);

    // combine texel colors
    vector c = b * s;

    // increase the intensity of the pixel slightly
    c += 0.1f;

    // save the resulting pixel color
    output.diffuse = c;

    return output;
}

   在PS_INPUT結構體中說明輸入像素着色器程序的數據格式,在PS_OUTPUT中說明像素着色器輸出的數據格式,在Main方法中說明對像素進行的具體操作。

2、編譯像素着色器程序

    ID3DXBuffer* shader = 0;
    ID3DXBuffer* errorBuffer = 0;

    //對着色器程序進行編譯
    HRESULT hr = D3DXCompileShaderFromFile(
        L"ps_multitex.txt",
        0, 0,
        "Main",
        "ps_1_1",
        D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, 
        &shader,
        &errorBuffer,
        &MultiCT);

3、獲得指向IDirect3DPixelShader9接口的指針

    HRESULT hr = g_pd3dDevice->CreatePixelShader(
        (DWORD*)shader->GetBufferPointer(),
        &MultiPS);

4、啓用像素着色器

g_pd3dDevice->SetPixelShader(MultiPS);

5、釋放資源
調用Release()方法釋放。

四、程序源碼

 程序簡要說明:對一個矩形進行多重紋理貼圖

 像素着色器程序:

// Globals
sampler EarthTex;
sampler GalaxyTex;

// Structures
struct PS_INPUT
{
    float2 earth      : TEXCOORD0;
    float2 galaxy    : TEXCOORD1;
};

struct PS_OUTPUT
{
    vector diffuse : COLOR0;
};

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

    // sample appropriate textures
    vector b = tex2D(EarthTex,      input.earth);
    vector s = tex2D(GalaxyTex, input.galaxy);

    // combine texel colors
    vector c = b * s;

    // increase the intensity of the pixel slightly
    c += 0.1f;

    // save the resulting pixel color
    output.diffuse = c;

    return output;
}

 程序源碼:

#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;
LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
LPDIRECT3DTEXTURE9  earthtexture = NULL;
LPDIRECT3DTEXTURE9  galaxytexture = NULL;

LPDIRECT3DPIXELSHADER9 MultiPS = 0;
LPD3DXCONSTANTTABLE MultiCT = 0;

D3DXHANDLE EatrhHandle = 0;
D3DXHANDLE GalaxyHandle = 0;

D3DXCONSTANT_DESC earthDesc;
D3DXCONSTANT_DESC galaxyDesc;

struct CUSTOMVERTEX
{
    FLOAT x, y, z;
    FLOAT u0,v0;
    FLOAT u1,v1;
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEX2)

HRESULT InitD3D(HWND hWnd)
{
    // Create the D3D object.
    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 CreateShader()
{
    ID3DXBuffer* shader = 0;
    ID3DXBuffer* errorBuffer = 0;

    //對着色器程序進行編譯
    HRESULT hr = D3DXCompileShaderFromFile(
        L"ps_multitex.txt",
        0, 0,
        "Main",
        "ps_1_1",
        D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, 
        &shader,
        &errorBuffer,
        &MultiCT);

    //創建像素着色器
    hr = g_pd3dDevice->CreatePixelShader(
        (DWORD*)shader->GetBufferPointer(),
        &MultiPS);

    shader->Release();
}

void GetHandles()
{
    EatrhHandle = MultiCT->GetConstantByName(0, "EarthTex");
    GalaxyHandle = MultiCT->GetConstantByName(0, "GalaxyTex");

    UINT count;
    MultiCT->GetConstantDesc(EatrhHandle, &earthDesc, &count);
    MultiCT->GetConstantDesc(GalaxyHandle, &galaxyDesc, &count);

    MultiCT->SetDefaults(g_pd3dDevice);
}

bool CreateTecture()
{
    if(FAILED(D3DXCreateTextureFromFile(g_pd3dDevice,L"galaxy.jpg",&galaxytexture)))
        return false;

    if(FAILED(D3DXCreateTextureFromFile(g_pd3dDevice,L"earth.jpg",&earthtexture)))
        return false;

    return true;
}

HRESULT CreateBuffer()
{
    CUSTOMVERTEX vertices[] =
    {
        {  -10.0f, -10.0f, 0.0f, 0,1,0,1},
        {  -10.0f, 10.0f, 0.0f, 0,0,0,0 },
        {  10.0f, 10.0f, 0.0f, 1,0,1,0},
        {  10.0f, -10.0f, 0.0f, 1,1,1,1},
    };

    // 創建頂點緩存
    if (FAILED(g_pd3dDevice->CreateVertexBuffer(sizeof(vertices),
        0, D3DFVF_CUSTOMVERTEX,
        D3DPOOL_DEFAULT, &g_pVB, NULL)))
    {
        return E_FAIL;
    }

    VOID* pVertices;
    if (FAILED(g_pVB->Lock(0, sizeof(vertices), (void**)&pVertices, 0)))
        return E_FAIL;
    memcpy(pVertices, (void*)vertices, sizeof(vertices));
    g_pVB->Unlock();

    // 創建索引緩存
    WORD indices[] = {0,1,2,0,2,3};

    if( FAILED( g_pd3dDevice->CreateIndexBuffer( sizeof(indices),
                                                  0, D3DFMT_INDEX16,
                                                  D3DPOOL_DEFAULT, &g_pIB, NULL ) ) )
    {
        return E_FAIL;
    }

    VOID* pIndices = NULL;
    if(FAILED(g_pIB->Lock(0, sizeof(indices), (void**)&pIndices,0)))
        return E_FAIL;
    memcpy(pIndices,(VOID*)indices, sizeof(indices));
    g_pIB->Unlock();

    return S_OK;
}

VOID SetupMatrices()
{
    D3DXVECTOR3 position( 0, 0, -20);
    D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
    D3DXMATRIX V;
    D3DXMatrixLookAtLH(&V, &position, &target, &up);
    g_pd3dDevice->SetTransform(D3DTS_VIEW, &V);

    //D3DXMatrixPerspectiveFovLH()函數中的最遠、最近距離爲相對於視點的距離(即vEyePt中的距離)
    D3DXMATRIXA16 matProj;
    D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4, 1.0f, 1.0f, 1000.0f);
    g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj);
}

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

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

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

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

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

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

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

    if(MultiCT != NULL)
        MultiCT->Release();
}

VOID Render()
{
    CreateShader();
    GetHandles();
    CreateTecture();

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

    // Begin the scene
    if (SUCCEEDED(g_pd3dDevice->BeginScene()))
    {
        SetupMatrices();

        g_pd3dDevice->SetPixelShader(MultiPS);
        g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
        g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
        g_pd3dDevice->SetIndices(g_pIB);

        g_pd3dDevice->SetTexture(earthDesc.RegisterIndex, earthtexture);
        g_pd3dDevice->SetSamplerState(earthDesc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
        g_pd3dDevice->SetSamplerState(earthDesc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
        g_pd3dDevice->SetSamplerState(earthDesc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

        g_pd3dDevice->SetTexture(galaxyDesc.RegisterIndex, galaxytexture);
        g_pd3dDevice->SetSamplerState(galaxyDesc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
        g_pd3dDevice->SetSamplerState(galaxyDesc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
        g_pd3dDevice->SetSamplerState(galaxyDesc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);

        g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
        g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
        g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

        g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,4,0,2);

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

//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
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);
}

//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
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,
        L"D3D Tutorial", NULL
    };
    RegisterClassEx(&wc);

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

    // Initialize Direct3D
    if (SUCCEEDED(InitD3D(hWnd)))
    {
        // Create the scene geometry
        if (SUCCEEDED(CreateBuffer()))
        {
            // Show the window
            ShowWindow(hWnd, SW_SHOWDEFAULT);
            UpdateWindow(hWnd);

            // Enter the message loop
            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(L"D3D Tutorial", wc.hInstance);
    return 0;
}

運行效果如下:

原始圖片如下:


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

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