【浅墨】索引缓存与顶点缓存的配合

索引缓存实际上是为了优化顶点缓存而存在的东西,可以节省内存消耗。据了解使用索引缓存与顶点缓存的结合速度会快上不少。索引缓存和顶点缓存就好比俞伯牙和钟子期

 

索引缓存的使用步骤和顶点缓存一样,分四步进行

设计顶点格式

这一步和顶点缓存的第一步一样。

设计表示点的结构体,利用宏定义一个灵活顶点格式

 

创建顶点缓存以及索引缓存

顶点缓存由IDirect3DVertexBuffer9接口对象来表示。索引缓存则由IDirect3DIndexBuffer9接口对象来表示。

对于顶点缓存的对象不必再重述一次,接下来重点讲解索引缓存的创建

HRESULT CreateIndexBuffer(

       [in]UINT Length,

       [in]DWORD Usage,

       [in]D3DFORMAT Format,

       [in]D3DPOOL Pool,

       [out,reval]IDirect3DIndexBuffer9 **ppIndexBuffer,

       [in]HANDLE *pShareHandle

);

参数详解

UINT Length:表示索引缓存的大小,以字节为单位

DWORD Usage:用于指定使用缓存的一些附加属性,这个参数取0表示没有附加属性

其他参数参考顶点缓存说明文章中的示意

D3DFORMAT Format:这是CreateVertexBuffer与CreateIndexBuffer最大的不同点。这个参数用于指定索引缓存中存储每个索引的大小,可以看到它为D3DFORMAT枚举类型。具体可查MSDN,有点多

D3DPOOL Pool:这是一个D3DPOOL枚举类型,用来指定存储索引缓存的存储位置使在内存中还是在显卡的显存中。默认情况下是在显卡的显存中

IDirect3DIndexBuffer9 **ppIndexBuffer:输出参数,调用CreateIndexBuffer就是为了初始化它,之后对索引缓存的操作都是基于这个输出的参数。

保留参数,一般设为NULL

 

访问索引缓存

与顶点缓存一样,访问索引缓存也需要Lock,和Unlock,访问代码写在Lock与Unlock之间

 

HRESULT Lock(

[in] UINT OffsetToLock,

[in] UINT SizeToLock,

[out] VOID **ppbData,

[in] DWORD Flags

);

参数详解

UINT OffsetToLock:表示加锁区域自存储空间的起始位置到开始锁定位置的偏移量

UINT SizeToLock:表示要锁定的字节数,也就是加锁区域大小

VOID **ppbData:指向被锁定的存储区的起始地址的指针

DWORD Flags:表示锁定的方式,我们可以把它设为0,也可以用下面的之一或者组合

参考顶点缓存中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

);

参数详解

D3DPRIMITIVETYPE type:表示要绘制的土元类型

INT BaseVertexIndex:表示将要进行绘制的索引缓存的起始顶点的索引位置,也就是我们从哪个点开始做我们的索引目录

UINT MinIndex:表示索引数组中最小的索引值,一般设为0

UINT NumVertices:表示我们这次调用DrawIndexedPrimitive方法需要的顶点个数。

UINT StartIndex:表示从索引位置中的第几个索引处开始绘制我们的图元

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;

}


【浅墨】索引缓存与顶点缓存的配合_第1张图片

你可能感兴趣的:(Direct3DX9)