【Direct3D -8 】交换连、顶点缓存、索引缓存

209 阅读5分钟

若网在纲,有条而不紊;若农服田,力穑乃亦有秋。 --《尚书·盘庚上》
网结在纲上,这样才能够有条不紊,不混乱。农民耕种天地,只有尽力的耕种,这样才能够有所收获。

交换链技术

使用交换链目的是让画面能够平滑过渡。

交换链是由两个或者两个以上的表面组成,每个表面都是存储着2D图形的一个线性数组,每个元素都表示屏幕上的一个像素。

对于三维物体,还有一个深度信息。Direct3D使用深度缓冲区为最终绘制的图像的每个像素都存储一个深度信息,深度缓冲区只包含特定像素的深度信息, 不包含图像数据的表面信息。

有了深度信息,在二维屏幕中的才能表现出三维物体的立体空间感。

Prenset() 函数的作用主要是用于页面反转操作,反转操作值得是,将指向前台缓冲区和后台缓冲区的指针进行交换,不需要复制表面的内容。

顶点坐标转换

空间物体是三维的, 屏幕是二维的,当在二维屏幕渲染三维场景的时候,需要将描述物体的三维坐标转换为二维坐标(世界坐标到屏幕坐标的转换)。顶点转换通常使用矩阵完成。

顶点缓存

顶点缓存使用步骤:

  1. 设计

固定流水线使用频繁的顶点格式:灵活顶点格式(flexible vertex format)

可编程渲染流水线:顶点声明、顶点定义

变量表示含义
D3DFVF_XYZ未经坐标变换的顶点坐标,不可以和D3D_FVF_XYZRHW一起使用
D3DFVF_XYZRHW经过坐标变换的顶点坐标,不可以和D3DFVF_XYZ、D3DFVF_NORMAL一起使用
D3DFVF_XYZB1~5标识顶点混合的权重值,该属性在骨骼动画中有使用
D3DFVF_NORMAL包含法向量的数值
D3DFVF_DIFFUSE包含漫反射的颜色值
D3DFVF_SPECULAR包含镜面反射的数值
D3DFVF_TEX1~8标识包含的纹理坐标信息,几重纹理数字就是几,最多为八重纹理

在书写灵活顶点格式的宏定义的时候,需要遵循一个顺序原则:

顶点坐标>RHW值>顶点混合权重>顶点法线向量>漫反射颜色>镜面反射颜色>纹理坐标

  1. 创建顶点缓存
CreateVertecBufer(UNIT Length, DWORD Usage, dword fvf, D3DPOOL Pool, IDirect3VertecBuffer9 **ppVertexBuffer, HANDLE *pShareHandle);
  • D3DPOOL 解释
枚举值含义
D3D3POOL_DEFAULT默认值,表示顶点缓存存在于显卡的显存中
D3D3POOL_MANAGEDDirect3D自由调度顶点缓冲区内存的位置
D3D3POOL_SYSTEMMEM顶点缓存在内存
D3D3POOL_SCRATCH表示顶点缓冲区位于临时内存当中,这种类型的顶点缓存区不能直接进行渲染,只能进行内存加锁和赋复制的操作
D3D3POOL_FORCE_DWORD表示将顶点缓存强制编译为32位,这个参数目前不使用
  1. 访问顶点缓存

访问顶点缓存前,必须使用lock()函数加锁

两种方式:

pVertexbuffer->Lock(0,0,(void**)pVertexs, 0)
pVertexs[0] = {}
pVertexbuffer->Unlock();
  1. 绘制
SetStreamSource()

把包含的几何体信息的顶点缓存和渲染流水线关联

SetFVF()

指定使用的灵活顶点格式的名称

DrawPrimitive()

完成最终的绘制操作,根据顶点缓存中的顶点来进行绘制

// 1. 设计顶点格式
struct CUSTOMVERTEX
{
	FLOAT x, y, z, rhw;
	DWORD color;
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)  //FVF灵活顶点格式

// 顶点赋值
CUSTOMVERTEX vertices[] =
{
    { 300.0f, 100.0f, 0.0f, 1.0f,  D3DCOLOR_XRGB(25,25,25), },
    { 500.0f, 100.0f, 0.0f, 1.0f,  D3DCOLOR_XRGB(25,25,25), }, 
    { 300.0f, 300.0f, 0.0f, 1.0f,  D3DCOLOR_XRGB(25,25,25),},
    { 300.0f, 300.0f, 0.0f, 1.0f,  D3DCOLOR_XRGB(25,25,25),},
};

// 2. 创建顶点缓存
g_pd3dDevice->CreateVertexBuffer( 6*sizeof(CUSTOMVERTEX),0, D3DFVF_CUSTOMVERTEX,
	D3DPOOL_DEFAULT, &g_pVertexBuffer, NULL ) ) )
		
// 3. 填充顶点缓冲区
VOID* pVertices;
g_pVertexBuffer->Lock( 0, sizeof(vertices), (void**)&pVertices, 0 );
memcpy( pVertices, vertices, sizeof(vertices) );
g_pVertexBuffer->Unlock();

// 4. 绘制
g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(CUSTOMVERTEX) );
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2 );

顶点缓存索引

一般情况,三维物体的顶点缓存数量远远大于顶点的数量,这导致存储空间浪费。计算耗时。

为了解决这个问题,仅仅存储物体顶点,使用顶点的索引来记录顶点缓存。

顶点缓存索引与普通的顶点缓存唯一的区别就是,减少了顶点的数量。

一个立方体有8个顶点,6个面,每个面由2个三角形表示。一共12个三角形,如果是普通的顶点缓存,那么就需要24个顶点,如果使用索引,就还是八个顶点。

CUSTOMVERTEX Vertices[] =
{
    { -20.0f, 20.0f, -20.0f,  D3DCOLOR_XRGB(25,100,55) },
    { -20.0f, 20.0f, 20.0f,   D3DCOLOR_XRGB(25,100,55)}, 
    { 20.0f, 20.0f, 20.0f,    D3DCOLOR_XRGB(25,100,55)},
    { 20.0f, 20.0f, -20.0f,   D3DCOLOR_XRGB(25,100,55) },
    { -20.0f, -20.0f, -20.0f, D3DCOLOR_XRGB(25,100,55)},
    { -20.0f, -20.0f, 20.0f,  D3DCOLOR_XRGB(25,100,55) }, 
    { 20.0f, -20.0f, 20.0f,   D3DCOLOR_XRGB(25,100,55)},
    { 20.0f, -20.0f, -20.0f,  D3DCOLOR_XRGB(25,100,55) },
};

//填充顶点缓存
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 *pIndices = NULL;
g_pIndexBuffer->Lock(0, 0, (void**)&pIndices, 0);

// 顶面
pIndices[0] = 0, pIndices[1] = 1, pIndices[2] = 2;
pIndices[3] = 0, pIndices[4] = 2, pIndices[5] = 3;
// 正面
pIndices[6] = 0, pIndices[7]  = 3, pIndices[8]  = 7;
pIndices[9] = 0, pIndices[10] = 7, pIndices[11] = 4;
// 左侧面
pIndices[12] = 0, pIndices[13] = 4, pIndices[14] = 5;
pIndices[15] = 0, pIndices[16] = 5, pIndices[17] = 1;
// 右侧面
pIndices[18] = 2, pIndices[19] = 6, pIndices[20] = 7;
pIndices[21] = 2, pIndices[22] = 7, pIndices[23] = 3;
// 背面
pIndices[24] = 2, pIndices[25] = 5, pIndices[26] = 6;
pIndices[27] = 2, pIndices[28] = 1, pIndices[29] = 5;
// 底面
pIndices[30] = 4, pIndices[31] = 6, pIndices[32] = 5;
pIndices[33] = 4, pIndices[34] = 7, pIndices[35] = 6;
g_pIndexBuffer->Unlock();