D3D 学习卡片 ( 一 )
渲染的基本步骤:
(1) 定义 FVF :
// 我们自定义的 FVF ,定义了顶点的结构
// D3DFVF_XYZ : 表示顶点坐标
// D3DFVF_DIFFUSE : 表示顶点有颜色
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
(2) 创建并填充顶点缓冲区:
① 用 IDirect3DDevice9::CreateVerTexBuffer 创建顶点缓冲区
② 用 IDirect3DVertexBuffer9:: Lock 锁定缓冲区
③ 将定义的三角形数据用内存拷贝的方法 (memcpy) 拷贝到顶点缓冲区
④ 用 IDirect3DVertexBuffer9:: UnLock 解锁缓冲区
如果不 Lock/Unlock 就直接使用会造成使用未定义指针;之所以这样做,而不是事先分配 vertex 数组是因为这不是在主存中分配空间,而是在显存中分配空间。
(3) 用D3D 进行渲染:
① 指定渲染源
IDirect3DDevice9::SetStreamSource( 0, g_pVB, sizeof(CUSTOMVERTEX) );
② 指定自定义的 FVF
IDirect3DDevice9::SetVertexShader( D3DFVF_CUSTOMVERTEX );
③ 渲染
IDirect3DDevice9::DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );
IDirect3DDevice9::CreateVertexBuffer
HRESULT CreateVertexBuffer(
UINT Length ,
DWORD Usage ,
DWORD FVF ,
D3DPOOL Pool ,
IDirect3DVertexBuffer9** ppVertexBuffer ,
HANDLE* pSharedHandle
);
Length :用字节表示顶点缓冲的大小。 FVF :灵活顶点格式
Usage : 高级应用。设 0
Pool :告诉 D3D 将顶点缓冲存储在内存中的哪个位置。
typedef enum _D3DPOOL {
D3DPOOL_DEFAULT = 0, // AGP, graphics card memory
D3DPOOL_MANAGED = 1, // AGP, graphics card memory && copy in sys memory
D3DPOOL_SYSTEMMEM = 2, // system memory, re-creatable
D3DPOOL_SCRATCH = 3, // system memory, not re-creatable
D3DPOOL_FORCE_DWORD = 0x7fffffff
} D3DPOOL;
ppVertexBuffer : 返回来的指向 IDirect3DVertexBuffer9 的指针。之后对顶点缓冲进行的操作就是通过这个指针啦。到这里还要再提醒一下,对于这些接口指针,在使用完毕后,一定要使用 Release 来释放它。
pSharedHandle :设为 NULL 就行了。
得到一个指向 IDirect3DVertexBuffer9 的指针后,顶点缓冲也就创建完毕了。现在要做的就是把之前保存在数组中的顶点信息放在顶点缓冲区里面。首先,使用 IDirect3DVertexBuffer9::Lock 来锁定顶点缓冲区:
IDirect3DVertexBuffer9:: Lock :
锁定一个资源意味着允许 CPU 访问其存储内容。除了允许处理器访问外,其它任何涉及资源的操作都会在锁定期间被串行化。对一个资源同一时刻只能锁定一次,那怕第二次锁定是一个非常重叠的区域也不行。并且当表面未解锁前,禁止在此表面进行任何加速器操作。
HRESULT Lock(
UINT OffsetToLock,
UINT SizeToLock,
void **p PB Data,
DWORD Flags
);
OffsetToLock : 指定要开始锁定的缓冲区的位置。通常在起始位置 0 开始锁定。
SizeToLock : 指定在锁定的缓冲区的大小。设为 0 的话就是表示要锁定整个缓冲区。
ppbData : 用来保存返回的指向顶点缓冲区的指针。通过这个指针来向顶点缓冲区填充数据。
Flags : 如何使用顶点缓冲器,即锁定方式:
D3DLOCK_DISCARD :应用程序将覆盖顶点缓冲器中的所有位置;
D3DLOCK_NO_DIRTY_UPDATE :对锁定的顶点缓冲器不添加 dirty 区域。
D3DLOCK_NOSYSLOCK :允许在 Lock() 期间改变显示模式。
D3DLOCK_READONLY :应用程序不会写入顶点缓冲器 ( 只读 )
D3DLOCK_NOOVERWRITE :顶点缓冲器的数据不会被覆盖。
填充为顶点缓冲区后,使用 IDirect3DVertexBuffer9:: Lock : 来解锁。
IDirect3DDevice9::SetStreamSource :
最后在渲染的时候使用 IDirect3DDevice9::SetStreamSource 来告诉 D3D 要渲染哪个顶点缓冲区里面的顶点。
HRESULT SetStreamSource(
UINT StreamNumber,
IDirect3DVertexBuffer9 *pStreamData,
UINT OffsetInBytes,
UINT Stride
);
StreamNumber : 设置数据流的数量。顶点缓冲最多可以使用 16 个数据流。确定所支持的数据流的数量,可以检查 D3DCAPS 中的 MaxStreams 成员的值。通常设为 0 ,表示使用单数据流。
pStreamData : 要与数据流绑定的数据。在这里我们要把顶点缓冲区与数据流绑定。
OffsetInBytes : 设置从哪个位置开始读数据。设为 0 表示从头读起。
Stride : 数据流里面数据单元的大小。在这里是每个顶点的大小。
IDirect3DDevice9::CreateIndexBuffer :
HRESULT CreateIndexBuffer(
UINT Length,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
IDirect3DIndexBuffer9** ppIndexBuffer
);
Length : 索引缓冲区的长度。通常使用索引数目乘以 sizeof ( WORD )或 sizeof(DWORD) 来设置,因为索引号的数据类型是字节( WORD )或双字节( DWORD ),嗯,一个 WORD 只有两个字节, DWORD 也就只有四个字节,比顶点的大小小多了吧。
Usage : 和 CreateVertexBuffer 中的 Usage 设置一样。一般设为 0 。
Format :设置索引格式。不是 D3DFMT_INDEX16 就是 D3DFMT_INDEX32 的啦。
Pool :又是和 CreateVertexBuffer 中的一样。一般设为 D3DPOOL_DEFAULT 。
ppIndexBuffer :指向 IDirect3DIndexBuffer9 的指针。操作索引缓冲区就靠它的啦。记得使用完后要 Release
IDirect3DDevice9::SetIndices :
最后使用 IDirect3DDevice9::SetIndices 来告诉设备要使用哪个索引。
HRESULT Setindices(
IDirect3DindexBuffer9* pIndexData,
UINT BaseVertexIndex
);
pIndexData :设置使用哪个索引缓冲。
BaseVertexIndex :设置以顶点缓冲区中的哪个顶点为索引 0 。
D3D 学习卡片 ( 二 )
IDirect3DDevice9::SetFVF(Vertex::FVF);
FVF 保存着顶点描述, FVF 的定义形式如下:
#defineFVF(D3DFVF_XYZ|D3DFVF_DIFFUSE) 或
DWORD const dwFVF = ( D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE );
D3DFVF_XYZ :表示顶点格式中包含顶点坐标信息。它告知系统你的游戏没有变换过顶点,要求Direct3D 来做顶点的变换工作。
D3DFVF_XYZRHW: 告知系统你的游戏引擎已对顶点作过变换,Direct3D 不需要再对它们作变换。也就是说,Direct3D 就不会再用世界矩阵、观察矩阵或投射矩阵来变换顶点了。
D3DFVF_DIFFUSE :表示顶点格式中包含了一个漫反射颜色信息。
D3DFVF_SPECULAR: 表示顶点格式中包含一个镜面反射颜色成分。
D3DFVF_NORMAL :表示顶点格式中包含有顶点朝向信息(即法线向量)。
D3DFVF_TEX0 —— D3DFVF_TEX8 :包含顶点格式坐标的个数( 1-8 个)。
例如:
typedef struct SObjVertex
{
FLOAT x, y, z; // position
FLOAT nx, ny, nz; // normal
DWORD diffuse; // diffuse color
DWORD specular; // specular color
FLOAT tu, tv; // first pair of texture coordinates
FLOAT tu2, tv2, tw2; // second pair of texture coordinates
FLOAT tu3, tv3; // third pair of texture coordinates
FLOAT tu4, tv4; // fourth pair of texture coordinates
} SObjVertex;
const DWORD gSObjVertexFVF = (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR |
D3DFVF_NORMAL | D3DFVF_TEX4 |
D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE3(1) |
D3DFVF_TEXCOORDSIZE2(2) | D3DFVF_TEXCOORDSIZE2(3));
IDirect3DDevice9::DrawPrimitive :
HRESULT DrawPrimitive(
D3DPRIMITIVETYPE PrimitiveType,
UINT StartVertex,
UINT PrimitiveCount
);
PrimitiveType : 定义了要使用的图元的类型。共有六种:
typedef enum D3DPRIMITIVETYPE
{
D3DPT_POINTLIST = 1, // 点,图元个数 N
D3DPT_LINELIST = 2,// 线,图元个数为 N/2
D3DPT_LINESTRIP = 3,//
D3DPT_TRIANGLELIST = 4,
D3DPT_TRIANGLESTRIP = 5,
D3DPT_TRIANGLEFAN = 6,
D3DPT_FORCE_DWORD = 0x7fffffff,
} D3DPRIMITIVETYPE, *LPD3DPRIMITIVETYPE;
StarVertex : 设置从顶点缓冲区中的第几个顶点画起。
PrimitiveCount : 要绘画的图元的数量。
IDirect3DDevice9::SetTexture :
IDirect3DDevice9::SetTexture() 方法将一张纹理指派给设备中的某个特定的阶段。 Direct3D 提供了 8 个阶段,这意味着可以为一次 DrawPrimitive() 调用同时设置最多 8 张纹理。(然而,你也可以多次调用 DrawPrimitive() ,这称 “ 多次渲染 ” )。 SetTexture() 的第一个参数中给出一个希望使用的纹理阶段编号。第二个参数为纹理对象指针。
HRESULT SetTexture (
DWORD Sampler, // 将一张纹理指派给设备中的某个特定的阶段
IDirect3DBaseTexture9 * pTexture // 纹理对象指针
);
当一个应用程序选择了一张纹理作为当前纹理时,它就指示 Direct3D 设备在下一次改变当前纹理之前,一直将该纹理应用到所有被渲染的图元上去。如果 3D 场景中的每个图元都有其自己的纹理,则必需在绘制每个图元之前设置相应的纹理,也就是说应在调用 DrawPrimitive() 函数之前进行纹理设置。
IDirect3DDevice9::SetTextureStageState :
HRESULT SetTextureStageState (
DWORD Stage, // 持有该纹理接口的纹理阶段号。
D3DTEXTURESTAGESTATETYPE Type, // 纹理状态类型
DWORD Value // 指定纹理状态类型的值
);
SetTextureStageState() 可用于在不同的材质 (material) 之间对颜色和 alpha 作混合。可用它来指定 Direct3D 纹理引擎的操作和参数。首先应选择想要使用的纹理,在第一个参数中给出持有该纹理接口的纹理阶段号。第 2 个参数用来设置纹理状态类型。
D3DXCreateTextureFromFile :
读入图像来创建纹理。
HRESULT D3DXCreateTextureFromFile(
LPDIRECT3DDEVICE9 pDevice,
LPCTSTR pSrcFile,
LPDIRECT3DTEXTURE9 * ppTexture
);
pDevice :指向创建过的 Direct3D 设备的指针,表示创建的纹理供哪个设备完成渲染功能时使用。
pSrcFile :