第三章
顶点缓存是一个包含顶点数据的连续内存空间
索引缓存是一个包含索引数据的连续的内存空间
之所以用顶点缓存和索引缓存而非数组来存储数据,是因为顶点缓存和索引缓存可以被放置在显存中
顶点缓存 IDirect3DVertexBuffer9表示,索引缓存用接口IDirectIndexBuffer9表示
创建顶点缓存
HRESULT IDirect3DDevice9::CreateVertexBuffer(
UINT Length,
DWORD Usage,
DWORD FVF,
D3DPOOL Pool ,
IDirect3DVertexBuffer9** ppVertexBuffer,
HANDLE* pShareHandle
);
创建索引缓存
HRESULT IDirect3DDevice9::CreateIndexBuffer(
UINT Length,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool ,
IDirect3DIndexBuffer9** ppIndexBuffer,
HANDLE* pShareHandle
);
*Length 为缓存分配的字节数
*Usage 指定关于如何使用缓存的一些属性。该值为0(表明无需附加属性)
# D3DUSAGE_DYNAMIC 将缓存设为动态缓存
# D3DUSAGE_POINTS 存储点图元
# D3DUSAGE_SOFTWAREPROCESSING 指定软件顶点运算方式
# D3DUSAGE_WRITEONLY 应用程序对缓存的操作模式为“只写”
*FVF 存储在顶点缓存中顶点的灵活顶点格式
*Pool 容纳缓存的内存池
*ppVertexBuffer 用于接收所创建的顶点缓存的指针
*pSharedHandle 不使用,为0
*Format 指定索引的大小,设为D3DFMT_INDEX16表示16为索引,设为D3DFMT_INDEX32表示32为索引
*ppIndexBuffer 用于接收所创建的索引缓存的指针
静态缓存一般放置在显存中
动态缓存一般放置在AGP中
对显存和AGP存储区进行读操作非常慢
例:创建一个可容纳8个Vertex类型的顶点的静态顶点缓存
IDirect3DVertexBuffer9* vb;
device -> CreateVertexBuffer(8*sizeof(Vertex),0,D3DFVF_XYZ,D3DPOOL_MANAGED,&vb,0);
创建一个动态缓存的例子,所创建的动态缓存可容纳36个16为索引
IDirect3DIndexBuffer9* ib;
device -> CreateIndexBuffer(36*sizeof(WORD),D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,D3DFMT_INDEX16,D3DPOOL_MANAGED,&ib,0);
访问缓存内容
借助方法Lock来获取缓存内容指针。
如果常见顶点缓存或索引缓存时,使用了D3DUSAGE_WRITEONLY标记,便无法对该缓存进行读操作
HRESULT IDirect3DVertexBuffer9::Lock(UINT OffsetToLock,
UINT SizeToLock,
BYTE** ppbData,//指定被锁定存储区的起始位置的指针
DWORD Flags//标记锁存方式
);
HRESULT IDirect3DIndexBuffer9::Lock(UINT OffsetToLock,
UINT SizeToLock,
BYTE** ppbData,
DWORD Flags
);
*Flags 标记锁存方式,可以是0
#D3DLOCK_DISCARD 仅用动态缓存。它指示硬件将缓存内容丢弃,并返回一个指向重新分配的缓存的指针的指针。该标记十分有用,因为这
允许在我们访问新分配的内存时,硬件能够继续使用被丢弃的缓存中的数据进行绘制,这样硬件的绘制就不会中止
#D3DLOCK_NOOVERWTITE 仅用动态缓存,该标记数据只能以追加方式写入缓存,可以保证在缓存中增加数据时,硬件仍可持续进行绘制
#D3DLOCK_READONLY 表示所锁定的缓存只可读而不可写,利用这一点可以作一些内部优化
例: Lock使用方法
Vertex* vertices;
_vb->Lock(0,0,(void**)&vertices,0);
vertices[0] = Vertex(-1.0f,0.0f,2.0f);
vertices[1] = Vertex(0.0f,1.0f,2.0f);
vertices[2] = Vertex(1.0f,0.0f,2.0f);
_vb->Unlock();
获取顶点缓存和索引缓存信息
D3DVERTEXBUFFER_DESC vbDescription;
vertexBuffer->GetDesc(&vbDescription);
D3DINDEXBUFFER_DESC ibDescription;
indexBuffer->GetDesc(&ibDescription);
D3DVERTEXBUFFER_DESC 和 D3DINDEXBUFFER_DESC 结构:
typedef struct _D3DVERTEXBUFFER_DESC{
D3DFORMAT Format;
D3DRESOURCETYPE Type;
DWORD Usage;
D3DPOOL Pool ;
UINT Size;
DWORD FVF;
}D3DVERTEXBUFFER_DESC
typedef struct _D3DINDEXBUFFER_DESC{
D3DFORMAT Format;
D3DRESOURCETYPE Type;
DWORD Usage;
D3DPOOL Pool ;
UINT Size;
DWORD FVF;
}D3DINDEXBUFFER_DESC
Direct3D封装了多种绘制状态(rendering state)
HRESULT IDirect3DDevice9::SetRenderState(
D3DRENDERSTATETYPE State,
DWORD Value
);
例:
_device->SetRenderState(D3DRS_FILLMODE,D3DFILL_WRITEFRAME);
一旦我们创建了顶点缓存以及索引缓存,我们基本上已经可以准备对其所存储的内容进行绘制了,但是绘制之前,还有3个步骤需要完成:
(1)指定数据流输入源。将顶点缓存和数据流进行链接,实质是将几何体的信息传输到绘制流水线中。
//设置顶点数据流的输入源
HRESULT IDirect3DDevice9::SetStreamSource(
UINT StreamNumber,//标识与顶点缓存建立链接的数据流。
IDirect3DVertexBuffer9* pStreamData,//与给定数据流建立链接的顶点缓存的指针
UINT offsetInBytes,自数据流的起始点算起的一个偏移量,单位为字节
UINT Stride//将要链接到数据流的顶点缓存中每个元素的大小,单位为字节
);
例:假定vb是一个存储为Vertex类型的顶点数据的顶点缓存
_device->SetStreamSource(0,vb,0,sizeof(Vertex));
(2)设置顶点格式:指定后续绘制调用中使用的顶点格式
_device->SetFVF(D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEXI);
(3)设置索引缓存。
_device->SetIndices(_ib);
使用DrawPrimitive或DrawIndexdPrimitive方法将待绘几何体信息通过绘制流水线传输,这两个方法从顶点数据流中获取顶点信息,并从
当前设定的索引缓存中提取索引信息
//该方法可用于绘制未使用索引信息的图元
HRESULT IDirect3DDevice9::DrawPrimitve(
D3DPRIMITIVETYPE PrimitiveType,//所要绘制的图元类型,#D3DPT_TRIANGLELIST三角形
UINT StartVertex,//顶点数据流中标识顶点数据读取起点的元素的索引
UINT PrimitiveCount//所要绘制的图元数量
);
HRESULT IDirect3DDevice9::DrawIndexedPrimitve(
D3DPRIMITIVETYPE Type,//绘制图元类型
INT BaseVertexIndex,//索引增加的一个基数
UINT MinIndex,//允许引用的最小索引值
UINT NumVertices,//本次调用中将引用的顶点总数
UINT StartIndex,//顶点缓存中标识索引的读取起始点的元素的索引
UINT PrimitiveCount //所要绘制的图元总数
);
所有绘制方法都必须在IDirect3DDevice9::BeginScene和IDirect3DDevice9::EndScene构成的方法之间进行调用
例:
_device->BeginScene();
_device->DrawPrimitive(...);
_device->EndScene();
D3DX库提供了一些用于生成简单3D几何体的网格数据方法
D3DX库提供如下6个网格创建函数
*D3DXCreateBox
*D3DXCreateSphere
*D3DXCreateCylinder
*D3DXCreateTeapot
*D3DXCreatePolygon
*D3DXCreateTorus
这6个方法都非常相似,并且都使用D3DX网格数据结构ID3DXMesh和ID3DXBuffer接口。