索引缓存实际上是为了优化顶点缓存而存在的东西,可以节省内存消耗。据了解使用索引缓存与顶点缓存的结合速度会快上不少。索引缓存和顶点缓存就好比俞伯牙和钟子期
索引缓存的使用步骤和顶点缓存一样,分四步进行
这一步和顶点缓存的第一步一样。
设计表示点的结构体,利用宏定义一个灵活顶点格式
顶点缓存由IDirect3DVertexBuffer9接口对象来表示。索引缓存则由IDirect3DIndexBuffer9接口对象来表示。
对于顶点缓存的对象不必再重述一次,接下来重点讲解索引缓存的创建
HRESULT CreateIndexBuffer(
[in]UINT Length,
[in]DWORD Usage,
[in]D3DFORMAT Format,
[in]D3DPOOL Pool,
[out,reval]IDirect3DIndexBuffer9 **ppIndexBuffer,
[in]HANDLE *pShareHandle
);
参数详解
l UINT Length:表示索引缓存的大小,以字节为单位
l DWORD Usage:用于指定使用缓存的一些附加属性,这个参数取0表示没有附加属性
n 其他参数参考顶点缓存说明文章中的示意
l D3DFORMAT Format:这是CreateVertexBuffer与CreateIndexBuffer最大的不同点。这个参数用于指定索引缓存中存储每个索引的大小,可以看到它为D3DFORMAT枚举类型。具体可查MSDN,有点多
l D3DPOOL Pool:这是一个D3DPOOL枚举类型,用来指定存储索引缓存的存储位置使在内存中还是在显卡的显存中。默认情况下是在显卡的显存中
l IDirect3DIndexBuffer9 **ppIndexBuffer:输出参数,调用CreateIndexBuffer就是为了初始化它,之后对索引缓存的操作都是基于这个输出的参数。
l 保留参数,一般设为NULL
与顶点缓存一样,访问索引缓存也需要Lock,和Unlock,访问代码写在Lock与Unlock之间
HRESULT Lock(
[in] UINT OffsetToLock,
[in] UINT SizeToLock,
[out] VOID **ppbData,
[in] DWORD Flags
);
参数详解
l UINT OffsetToLock:表示加锁区域自存储空间的起始位置到开始锁定位置的偏移量
l UINT SizeToLock:表示要锁定的字节数,也就是加锁区域大小
l VOID **ppbData:指向被锁定的存储区的起始地址的指针
l DWORD Flags:表示锁定的方式,我们可以把它设为0,也可以用下面的之一或者组合
n 参考顶点缓存中Lock的参数详解
在顶点缓存中,开始绘制前要调用三个函数
g_pd3dDevice->SetStreamSource(0,g_pVertexBuffer,0,sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,2);
而当顶点缓存与索引缓存结合后,当调用完前两个函数,需要调用IDirect3DDecive9接口的一个SetIndices方法设置索引缓存,最后才是绘制函数
HRESULT SetIndices(
[in]IDirect3DIndexBuffer9 *pIndexData
);
唯一的参数就是我们在CreateIndexBuffer中创建的缓存
最后的绘制函数不是DrawPrimitive而是DrawIndexedPrimitive
HRESULT DrawIndexPrimitive(
[in]D3DPRIMITIVETYPE type,
[in]INT BaseVertexIndex,
[in]UINT MinIndex,
[in]UINT NumVertices,
[in]UINT StartIndex,
[in]PrimitiveCount
);
参数详解
l D3DPRIMITIVETYPE type:表示要绘制的土元类型
l INT BaseVertexIndex:表示将要进行绘制的索引缓存的起始顶点的索引位置,也就是我们从哪个点开始做我们的索引目录
l UINT MinIndex:表示索引数组中最小的索引值,一般设为0
l UINT NumVertices:表示我们这次调用DrawIndexedPrimitive方法需要的顶点个数。
l UINT StartIndex:表示从索引位置中的第几个索引处开始绘制我们的图元
l UINT PrimitiveCount:要绘制的图元的个数
代码如下
//--------------------【程序说明】-------------------
//程序名称:D3DdemoCore
//2016年11月Created by 寒江雪
//描述:Direct3D 程序核心框架
//-------------------------------------------------
//---------------------【头文件部分】-------------------
//描述:包含程序所依赖的头文件
//----------------------------------------------------
#include
#include
#include
//----------------------【库文件包含部分】-----------------
#pragma comment(lib,"winmm.lib")//调用PlaySound函数所需的文件
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"dxerr.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"d3dx9d.lib")
#pragma comment(lib,"d3dx10.lib")
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"comctl32.lib")
//-----------------------【宏定义部分】-------------
//描述:定义一些辅助的宏
//-------------------------------------------------
#define WINDOW_WIDTH 800//为窗口宽度定义的宏,以方便在此处修改窗口宽度
#define WINDOW_HEIGHT 600//为窗口高度定义的宏,以方便在此处修改窗口高度
#define WINDOW_TITLE L"Direct3D程序的核心框架"//为床标题定义的宏
#define SAFE_RELEASE(p) {if(p){(p)->Release();(p)=NULL;}}//定义一个安全释放宏,便于后面COM接口指针的释放
//-------------------【结构体声明】-----------------
//描述:结构体声明
//-------------------------------------------------
struct CUSTOMVERTEX
{
float x, y, z, rhw;
DWORD color;
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)
//-------------------【全局变量声明】-----------------
//描述:全局变量声明
//-------------------------------------------------
IDirect3DDevice9* g_pd3dDevice = NULL;
ID3DXFont* g_pFont = NULL;//字体COM接口
float g_FPS = 0.0f;
wchar_t g_strFPS[50];
LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL;//顶点缓冲区对象
LPDIRECT3DINDEXBUFFER9 g_pIndexBuffer = NULL;//索引缓冲区对象
//--------------------【全局函数声明】---------------
//描述:全局函数声明,防止"未声明的标识"系列错误
//-------------------------------------------------
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);//窗口过程函数
HRESULT Direct3D_Init(HWND hwnd);//在这个函数中进行Direct3D的初始化
HRESULT Objects_Init(HWND hwnd);//在这个函数中进行要绘制的物体的资源初始化
VOID Direct3D_Render(HWND hwnd);//在这个函数中进行Direct3D渲染代码的书写
VOID Direct3D_CleanUp(HWND hwnd);//在这个函数中清理COM资源以及其他资源
float GET_FPS();
//-------------------【WinMain()函数】---------------
//描述:Window应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
//【1】窗口创建第一步:开始设计一个窗口类
WNDCLASSEX wndClass{ 0 };//用WNDCLASSEX 定义一个窗口类
wndClass.cbSize = sizeof(WNDCLASSEX);//设置结构体字节数大小
wndClass.style = CS_HREDRAW | CS_VREDRAW;//设置窗口演示
wndClass.lpfnWndProc = WndProc;//设置窗口过程函数指针
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = (HICON)::LoadImage(NULL, L"icon.ico", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = L"MainWindow";
//【2】第二步:注册窗口类
if (!RegisterClassEx(&wndClass))
return -1;
//【3】第三步:正式创建窗口
HWND hwnd = CreateWindow(L"MainWindow", WINDOW_TITLE, WS_OVERLAPPED, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
//Direct3D资源初始化
if (S_OK == Direct3D_Init(hwnd)) {
MessageBox(hwnd, L"DirectX3D 初始化完成", L"寒江雪消息窗口", 0);
}
else {
MessageBox(hwnd, L"DirectX3D 初始化失败", L"寒江雪窗口", 0);
}
//【4】窗口创建第四步:窗口的移动,显示和更新
MoveWindow(hwnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true);
ShowWindow(hwnd, nShowCmd);//调用ShowWindow函数来显示窗口
UpdateWindow(hwnd);
//PlaySound(L"War3XMainScreen.wav", NULL,SND_FILENAME | SND_ASYNC | SND_LOOP);
MessageBox(hwnd, L"DirectX,等着瞧吧,我们来降服你了~!", L"寒江雪的消息窗口", 0);
MSG msg = { 0 };
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {//查看应用程序消息队列,有消息时将队列中的消息派发出去
TranslateMessage(&msg);//将虚拟按键消息转换为字符消息
DispatchMessage(&msg);//该函数分发一个消息给窗口程序
}
else {
Direct3D_Render(hwnd);//进行渲染
}
}
//【6】窗口类的注销
UnregisterClass(L"MainWindow", wndClass.hInstance);
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_PAINT:
Direct3D_Render(hwnd);
ValidateRect(hwnd, NULL);
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break;
case WM_DESTROY:
Direct3D_CleanUp(hwnd);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
break;
}
return 0;
}
HRESULT Direct3D_Init(HWND hwnd)
{
LPDIRECT3D9 pD3D = NULL;//Direct3D接口对象的创建
if (!S_OK == Objects_Init(hwnd))return E_FAIL;
if (NULL == (pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
return E_FAIL;
D3DCAPS9 caps;
int vp = 0;
if (FAILED(pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps)))
return E_FAIL;
if (caps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT)//支持硬件顶点运算,我们就采用
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof d3dpp);
d3dpp.BackBufferWidth = WINDOW_WIDTH;
d3dpp.BackBufferHeight = WINDOW_HEIGHT;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = true;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = 0;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
if (FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, vp, &d3dpp, &g_pd3dDevice)))
return E_FAIL;
SAFE_RELEASE(pD3D);
if (!S_OK == Objects_Init(hwnd))
return E_FAIL;
return S_OK;
}
HRESULT Objects_Init(HWND hwnd)
{
if (FAILED(D3DXCreateFont(g_pd3dDevice, 36, 0, 0, 1, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, _T("微软雅黑"), &g_pFont)))
return E_FAIL;
srand(timeGetTime());
//创建顶点缓存
if (FAILED(g_pd3dDevice->CreateVertexBuffer(18 * sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT,&g_pVertexBuffer, NULL)))
return E_FAIL;
if (FAILED(g_pd3dDevice->CreateIndexBuffer(48*sizeof(WORD),0,D3DFMT_INDEX16,D3DPOOL_DEFAULT,&g_pIndexBuffer,NULL)))
return E_FAIL;
CUSTOMVERTEX Vertices[17];
Vertices[0].x = 400;
Vertices[0].y = 300;
Vertices[0].z = 0;
Vertices[0].rhw = 1;
Vertices[0].color = D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256);
for (int i = 0; i < 16; i++) {
Vertices[i + 1].x = (float)(250 *sin(i*3.14159 / 8.0f))+400;
Vertices[i + 1].y = -(float)(250 *cos(i*3.14159 / 8.0f))+300;
Vertices[i + 1].z = 0;
Vertices[i + 1].rhw = 1.0f;
Vertices[i + 1].color = D3DCOLOR_XRGB(rand() % 256,rand() % 256, rand() % 256);
}
VOID *pVertices;
if (FAILED(g_pVertexBuffer->Lock(0, sizeof(Vertices), (void**)(&pVertices), 0)))
return E_FAIL;
memcpy(pVertices, Vertices, sizeof(Vertices));
g_pVertexBuffer->Unlock();
WORD Indices[] = {0,1,2,0,2,3,0,3,4,0,4,5,0,5,6,0,6,7,0,7,8,0,8,9,0,9,10,0,10,11,0,11,12,0,12,13,0,13,14,0,14,15,0,15,16,0,16,1};
WORD* pIndices = NULL;
g_pIndexBuffer->Lock(0, 0, (void**)&pIndices,0);
memcpy(pIndices, Indices, sizeof(Indices));
g_pIndexBuffer->Unlock();
return S_OK;
}
VOID Direct3D_Render(HWND hwnd)
{
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
RECT formatRect;
GetClientRect(hwnd, &formatRect);
g_pd3dDevice->BeginScene();
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);//设置渲染
//绘制图形
g_pd3dDevice->SetStreamSource(0,g_pVertexBuffer, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
g_pd3dDevice->SetIndices(g_pIndexBuffer);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 17, 0, 16);
int charCount = swprintf_s(g_strFPS, 20, _T("FPS:%0.3f"), GET_FPS());
g_pFont->DrawText(NULL, g_strFPS, charCount, &formatRect, DT_TOP | DT_RIGHT, D3DCOLOR_XRGB(255, 39, 136));
g_pd3dDevice->EndScene();
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
return VOID();
}
VOID Direct3D_CleanUp(HWND hwnd)
{
SAFE_RELEASE(g_pVertexBuffer);
SAFE_RELEASE(g_pIndexBuffer);
SAFE_RELEASE(g_pFont);
SAFE_RELEASE(g_pd3dDevice);
return VOID();
}
float GET_FPS()
{
static float fps = 0; //我们需要计算的FPS值
static int frameCount = 0;//帧数
static float currentTime = 0.0f;//当前时间
static float lastTime = 0.0f;//持续时间
frameCount++;
currentTime = timeGetTime()*0.001f;
if (currentTime - lastTime > 1.0f) {
fps = (float)frameCount / (currentTime - lastTime);
lastTime = currentTime;
frameCount = 0;
}
return fps;
return 0.0f;
}