有些复杂的图形是由多个相邻的三角形拼接而成的,比如5、6边形等,假如为每个三角形分配3个顶点,但是这样就会出现顶点相互重合的情况,从而造成内存的浪费,显然这是得不偿失的。那有没有更合适的处理方式呢?当然,索引缓冲区可以很好解决这个问题。
索引缓冲区和顶点缓冲区一样,都是COM接口,它其中保存的是多边形的三角形顶点在顶点缓冲区的索引,程序需要做的就是设置三角形的组合,然后通过各种顶点的组合绘制出复杂图形,这样就避免了重复顶点的出现,它的数值最多就是一个16或32位的整数,这要比一个顶点所占用的内存小得多。因此在绘制那些顶点重复使用较多的复杂图形时,用索引缓冲区绘制效果好得多。
下面,我们就利用索引缓冲区绘制一个正多边形(此项目基于上一章内容)。
首先声明索引缓冲区指针对象:
1 2 3 |
LPDIRECT3DINDEXBUFFER9 g_pIB = NULL; |
然后,修改InitVB方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
HRESULT InitVB() { //创建顶点缓冲区 VERTEX vertexes[LINE_NUM + 1]; vertexes[0].x = POSITION_X; vertexes[0].y = POSITION_Y; vertexes[0].z = 1.0f; vertexes[0].rhw = 1.0f; vertexes[0].color = 0xffffffff; for (int index = 0; index < LINE_NUM; ++index) { vertexes[index + 1].x = (float)(RADIUS * sin(index * 2 * PI / LINE_NUM)) + POSITION_X; vertexes[index + 1].y = -(float)(RADIUS * cos(index * 2 * PI / LINE_NUM)) + POSITION_Y; vertexes[index + 1].z = 1.0f; vertexes[index + 1].rhw = 1.0f; vertexes[index + 1].color = 0xffabcdef; } if (FAILED(g_pDevice->CreateVertexBuffer( sizeof(vertexes) , 0 , FVF , D3DPOOL_DEFAULT , &g_pVB , NULL ))) { return E_FAIL; } void *pvertexes = NULL; if (FAILED(g_pVB->Lock(0, sizeof(vertexes), (void**)&pvertexes, 0))) { return E_FAIL; } memcpy(pvertexes, vertexes, sizeof(vertexes)); g_pVB->Unlock(); //创建索引缓冲区 WORD indices[3 * LINE_NUM]; for (int index = 0; index < LINE_NUM; ++index) { indices[index * 3] = 0; indices[(index * 3) + 1] = (index + 1) % (LINE_NUM + 1); indices[(index * 3) + 2] = (index + 2) % (LINE_NUM + 1) + (index == LINE_NUM - 1 ? 1 : 0); } if (FAILED(g_pDevice->CreateIndexBuffer(sizeof(indices), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &g_pIB, NULL))) { return E_FAIL; } void *pIndices = NULL; if (FAILED(g_pIB->Lock(0, sizeof(indices), (void**)&pIndices, 0))) { return E_FAIL; } memcpy(pIndices, indices, sizeof(indices)); g_pIB->Unlock(); return S_OK; } |
在InitVB方法中,我们修改了原来的顶点缓冲区,因为绘制的是正多边形,所以在填充顶点缓冲区时,使用了三角函数进行处理。初始化索引缓冲区大小时需要注意的是,索引缓冲区中的数据一定要可被3整除,因为我们是以三角形为单位绘制的。
其中CreateIndexBuffer方法创建了索引缓冲区,它有6个参数,第一个参数表示创建的索引缓冲区的大小(以字节为单位);第二个参数表示索引缓冲区的属性,此处取默认值0;第三个参数为索引缓冲区中数据的格式,这个有具体使用的数据为准,此处为16位数据;第四个参数为内存类型(D3DPOOL);第五个参数为索引缓冲区指针地址;第六个参数为保留参数,此处置为NULL。
在填充索引缓冲区时,和填充顶点缓冲区相同,都需要先加锁再解锁,以保证操作的安全。
接着是Render方法,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
void Render() { if (NULL == g_pDevice) { return; } g_pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(30, 60, 90), 1.0f, 0); if (SUCCEEDED(g_pDevice->BeginScene())) { g_pDevice->SetStreamSource(0, g_pVB, 0, sizeof(VERTEX)); g_pDevice->SetFVF(FVF); g_pDevice->SetIndices(g_pIB); g_pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, LINE_NUM + 1, 0, LINE_NUM); g_pDevice->EndScene(); } g_pDevice->Present(NULL, NULL, NULL, NULL); } |
在Render方法中主要增加了一个SetIndices方法,以及修改原来的绘制方法DrawPrimitive为DrawIndexedPrimitive。SetIndices方法只有一个参数,就是索引缓冲区指针。DrawIndexedPrimitive方法有6个参数,第一个参数是绘制的图元的类型,在此为三角形列表;第二个参数为索引缓冲区的起始地址,此处设置为0,表示从头开始绘制;第三个参数为索引缓冲区中最小的索引值;第四个参数为所要绘制的图形的顶点个数;第五个参数表示从索引缓冲区的哪个元素开始绘制;第六个参数绘制图元的数量。
最后,cleanup方法中添加索引缓冲区对象释放代码,
1 2 3 4 5 6 |
if (NULL != g_pIB) { g_pIB->Release(); } |
运行程序,我们看到下面的效果,
此文仅供参考,如有不足,还望赐教,大家共同学习进步。
ZXGoto祝大家编程愉快!
- 本文固定链接: https://www.xuanyusong.com/archives/884
- 转载请注明: ZXGoto 于 雨松MOMO程序研究院 发表
加油..期待作者更新
努力ing
学习了,支持!
支持一下张角!
多谢支持
前来学习