一、顶点着色器简介
顶点着色器(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
版权声明:本文为博主原创文章,转载请附上博文链接!