若网在纲,有条而不紊;若农服田,力穑乃亦有秋。 --《尚书·盘庚上》
网结在纲上,这样才能够有条不紊,不混乱。农民耕种天地,只有尽力的耕种,这样才能够有所收获。
交换链技术
使用交换链目的是让画面能够平滑过渡。
交换链是由两个或者两个以上的表面组成,每个表面都是存储着2D图形的一个线性数组,每个元素都表示屏幕上的一个像素。
对于三维物体,还有一个深度信息。Direct3D使用深度缓冲区为最终绘制的图像的每个像素都存储一个深度信息,深度缓冲区只包含特定像素的深度信息, 不包含图像数据的表面信息。
有了深度信息,在二维屏幕中的才能表现出三维物体的立体空间感。
Prenset() 函数的作用主要是用于页面反转操作,反转操作值得是,将指向前台缓冲区和后台缓冲区的指针进行交换,不需要复制表面的内容。
顶点坐标转换
空间物体是三维的, 屏幕是二维的,当在二维屏幕渲染三维场景的时候,需要将描述物体的三维坐标转换为二维坐标(世界坐标到屏幕坐标的转换)。顶点转换通常使用矩阵完成。
顶点缓存
顶点缓存使用步骤:
- 设计
固定流水线使用频繁的顶点格式:灵活顶点格式(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值>顶点混合权重>顶点法线向量>漫反射颜色>镜面反射颜色>纹理坐标
- 创建顶点缓存
CreateVertecBufer(UNIT Length, DWORD Usage, dword fvf, D3DPOOL Pool, IDirect3VertecBuffer9 **ppVertexBuffer, HANDLE *pShareHandle);
- D3DPOOL 解释
| 枚举值 | 含义 |
|---|---|
| D3D3POOL_DEFAULT | 默认值,表示顶点缓存存在于显卡的显存中 |
| D3D3POOL_MANAGED | Direct3D自由调度顶点缓冲区内存的位置 |
| D3D3POOL_SYSTEMMEM | 顶点缓存在内存 |
| D3D3POOL_SCRATCH | 表示顶点缓冲区位于临时内存当中,这种类型的顶点缓存区不能直接进行渲染,只能进行内存加锁和赋复制的操作 |
| D3D3POOL_FORCE_DWORD | 表示将顶点缓存强制编译为32位,这个参数目前不使用 |
- 访问顶点缓存
访问顶点缓存前,必须使用lock()函数加锁
两种方式:
pVertexbuffer->Lock(0,0,(void**)pVertexs, 0)
pVertexs[0] = {}
pVertexbuffer->Unlock();
- 绘制
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();