一、頂點着色器簡介
頂點着色器(vertex shader)是一段運行在圖形卡GPU中的程序,它可取代固定功能流水線中的變換和光照環節。(當然,這也不是絕對的,因爲在硬件不支持頂點着色器的情況下,Direct3D運行時就會用軟件運算方式來模擬頂點着色器。)
使用頂點着色器的優勢有:
1、由於頂點着色器是用HLSL語言編寫的一段定製程序,這樣我們在可實現的圖形效果上就獲得了很大的靈活性。例如藉助頂點着色器,我們就可以使用任何在頂點着色器中實現的光照算法。這樣,我們就不再受限於Direct3D的固定功能流水線了。
2、而且,這種對頂點位置進行操作的能力具有廣泛的應用場合,例如織物模擬(cloth simulation)、粒子系統的點尺寸處理、頂點融合/變形技術(morphing)等。
3、此外,我們可用的頂點數據結構也更加靈活,而且可編程流水線中的頂點結構可以包含比固定功能流水線更加豐富的數據。
二、使用頂點着色器的步驟
(1)頂點聲明的創建和啓用
(2)編寫頂點着色器程序
(3)編譯頂點着色器程序
(4)創建一個IDirect3DVertexShader9接口的對象,用於表示基於所編譯的着色器代碼的頂點着色器
(5)用SetVertexShader方法啓用頂點着色器
(6)調用頂點着色器的Release方法釋放着色器
接下來詳細介紹每一步的具體操作:
1、頂點聲明
使用固定功能流水線時,我們一直都在用靈活頂點格式(FVF)來描述頂點結構的分量。但是,在可編程流水線中,頂點結構甚至可以包含那些超出FVF描述能力的數據。因此,我們通常使用描述能力更強、功能更豐富的頂點聲明(vertex declaration)。
1、頂點聲明的描述
頂點聲明描述爲一個D3DVERTEXELEMENT9類型的結構數組。該結構數組中的每個元素都描述了頂點結構的一個分量。
D3DVERTEXELEMENT9 decl[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
D3DDECL_END()
};
2、頂點聲明的創建
g_pd3dDevice->CreateVertexDeclaration(decl, &VertexDecl);
3、頂點聲明的啓用
使用頂點聲明時,無需調用SetFVF,只需調用以下函數即可
g_pd3dDevice->SetVertexDeclaration(VertexDecl);
2、編寫頂點着色器程序
// Globals
matrix ViewProjMatrix;
// Structures
struct VS_INPUT
{
vector position : POSITION;
vector color : COLOR;
};
struct VS_OUTPUT
{
vector position : POSITION;
vector diffuse : COLOR;
};
VS_OUTPUT Main(VS_INPUT input)
{
// zero out members of output
VS_OUTPUT output = (VS_OUTPUT)0;
output.position = mul(input.position, ViewProjMatrix);
output.diffuse = input.color;
return output;
}
3、編譯頂點着色器程序
HRESULT hr = 0;
ID3DXBuffer* shader = 0;
ID3DXBuffer* errorBuffer = 0;
hr = D3DXCompileShaderFromFile(
L"shade.txt",
0,
0,
"Main",
"vs_1_1",
D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY,
&shader,
&errorBuffer,
&VertexConstantTable);
4、創建一個IDirect3DVertexShader9接口的對象
hr = g_pd3dDevice->CreateVertexShader(
(DWORD*)shader->GetBufferPointer(),
&TriangleShader);
5、啓用頂點着色器
g_pd3dDevice->SetVertexShader(TriangleShader);
6、釋放資源
if (TriangleShader != NULL)
TriangleShader->Release();
三、程序源碼
程序簡要說明:繪製一個彩色三角形
頂點着色器程序:
// Globals
matrix ViewProjMatrix;
// Structures
struct VS_INPUT
{
vector position : POSITION;
vector color : COLOR;
};
struct VS_OUTPUT
{
vector position : POSITION;
vector diffuse : COLOR;
};
VS_OUTPUT Main(VS_INPUT input)
{
// zero out members of output
VS_OUTPUT output = (VS_OUTPUT)0;
output.position = mul(input.position, ViewProjMatrix);
output.diffuse = input.color;
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;
LPDIRECT3DVERTEXSHADER9 TriangleShader = NULL;
LPDIRECT3DVERTEXDECLARATION9 VertexDecl = NULL;
LPD3DXCONSTANTTABLE VertexConstantTable = NULL;
D3DXHANDLE ViewProjMatrixHandle = NULL;
struct CUSTOMVERTEX
{
FLOAT x, y, z;
DWORD color;
};
bool VertexShader()
{
if(TriangleShader)
return true;
HRESULT hr = 0;
ID3DXBuffer* shader = 0;
ID3DXBuffer* errorBuffer = 0;
hr = D3DXCompileShaderFromFile(
L"shade.txt",
0,
0,
"Main",
"vs_1_1",
D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY,
&shader,
&errorBuffer,
&VertexConstantTable);
hr = g_pd3dDevice->CreateVertexShader(
(DWORD*)shader->GetBufferPointer(),
&TriangleShader);
if(shader)
shader->Release();
if(errorBuffer)
errorBuffer->Release();
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(ViewProjMatrixHandle)
return true;
ViewProjMatrixHandle = VertexConstantTable->GetConstantByName(0, "ViewProjMatrix");
VertexConstantTable->SetDefaults(g_pd3dDevice);
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;
VertexConstantTable->SetMatrix(g_pd3dDevice, 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 (TriangleShader != NULL)
TriangleShader->Release();
if (VertexDecl != NULL)
VertexDecl->Release();
if (VertexConstantTable != NULL)
VertexConstantTable->Release();
}
int Render()
{
VertexBuffer();
VertexShader();
VertexDeclaration();
GetHandles();
SetupMatrices();
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0);
if (SUCCEEDED(g_pd3dDevice->BeginScene()))
{
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetVertexShader(TriangleShader);
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);
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);
}
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: VertexShader",
WS_OVERLAPPEDWINDOW, 100, 100, 700, 700,
NULL, NULL, wc.hInstance, NULL);
if (SUCCEEDED(InitD3D(hWnd)))
{
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
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/77527096
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!