顶点着色器入门(龙书简单总结 DirectX 3D 9)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Spring_24/article/details/77527096

一、顶点着色器简介


      顶点着色器(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;
}


     程序运行效果如下:

  
     

猜你喜欢

转载自blog.csdn.net/Spring_24/article/details/77527096