Direct3D中的绘制
1.顶点缓存和索引缓存
一个顶点缓存是一个包含顶点数据的连续内存空间;一个索引缓存是一个包含索引数据的连续内存空间。
顶点缓存用接口IDirect3DVertexBuffer9表示;索引缓存用接口IDirect3DIndexBuffer9表示。
1.1创建顶点缓存和索引缓存
HRESULT IDirect3DDevice9::CreateVertexBuffer(
UINT Length, //为缓存分配的字节数
DWORD Usage, //指定如何使用缓存的附加属性,0表明无需附加属性
DWORD FVF, //存储在顶点缓存中的灵活顶点格式
D3DPOOL Pool, //容纳缓存的内存池
IDirect3DVertexBuffer9** ppVertexBuffer, //顶点缓存的指针
HANDLE* pSharedHandle //不使用,为0。
);
HRESULT IDirect3DDevice9::CreateIndexBuffer(
UINT Length, //为缓存分配的字节数
DWORD Usage, //指定如何使用缓存的附加属性,0表明无需附加属性
D3DFORMAT Format, //索引的大小.D3DFMT_INDEX16(16位索引),D3DFMT_INDEX32 (32位索引)
D3DPOOL Pool, //容纳缓存的内存池
IDirect3DIndexBuffer9** ppIndexBuffer, //索引缓存的指针
HANDLE* pSharedHandle //不使用,为0。
);
下面例子,创建一个容纳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);
1.2访问缓存内容
借助方法Lock来获取指向缓存内容的指针。对缓存访问完毕后,要进行Unlock。
HRESULT IDirect3DVertexBuffer9::Lock(
UINT OffsetToLock,
UINT SizeToLock,
VOID ** ppbData,
DWORD Flags
);
HRESULT IDirect3DIndexBuffer9::Lock (
UINT OffsetToLock, //自缓存的起始点到开始锁定位置的偏移量,单位为字节。
UINT SizeToLock, //所要锁定的字节数
VOID ** ppbData, //指向被锁定的存储区,起始位置的指针
DWORD Flags //锁定的方式,可以为0.
);
注:Flags,可以是0,也可以是下列选项之一或组合。
D3DLOCK_DISCARD 仅用于动态缓存。它指示硬件将缓存丢弃,并返回一个新的缓存指针。
D3DLOCK_NOOVERWRITE仅用于动态缓存。数据以追加方式写入缓存。
D3DLOCK_NO_DIRTY_UPDATE
D3DLOCK_NOSYSLOCK
D3DLOCK_READONLY 对锁定的缓存只读,不能写
D3DLOCK_DONOTWAIT
下面例子说明了Lock的一般使用方式:
Vertex * v;
vb->Lock(0,0,(void **)&v,0);
v[0]=Vertex(-1.0f,0.0f,2.0f);
v[1]=Vertex(0.0f,1.0f,2.0f);
v[2]=Vertex(1.0f,0.0f,2.0f);
vb->Unlock();
1.3获取顶点缓存和索引缓存的信息
D3DVERTEXBUFFER_DESC vbDescription;
vb->GetDesc(&vbDescription);
D3DINDEXBUFFER_DESC ibDescription;
Ib->GetDesc(&ibDescription);
2.绘制状态
Direct3D封装了多种绘制状态,这些绘制状态影响了几何体的绘制方式。如果要更改默认值,用方法:
HRESULT IDirect3DDevice9::SetRenderState
{
D3DRENDERSTATETYPE State,
DWORD Value
}
3.绘制的准备工作
一旦我们创建了顶点缓存和索引缓存(可选),我们基本上可以对其存储内容进行绘制。在绘制前有3个步骤需完成:
3.1指定数据流输入源.实质是将几何体的信息传输的绘制流水线中。
HRESULT IDirect3DDevice9::SetStreamSource(
UINT StreamNumber, //标示与顶点缓存建立连接的数据流
IDirect3DVertexBuffer9 * pStreamData, //顶点缓存的指针
UINT OffsetInBytes, //指定了将被传输至绘制流水线的顶点数据的起始位置
UINT Stride //顶点缓存中每个元素的大小
);
Device->SetStreamSource(0,vb,0,sizeof(Vertex));
3.2设置顶点格式
Device->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE);
3.3设置索引缓存
Device->SetIndices(ib);
4.使用顶点缓存和索引缓存进行绘制
HRESULT IDirect3DDevice9::DrawPrimitive
(D3DPRIMITIVETYPE PrimitiveType, //所要绘制的图元类型,
UINT StartVertex, //读取起点元素的索引
UINT PrimitiveCount //图元数量
)
HRESULT IDirect3DDevice9::DrawIndexedPrimitive(
D3DPRIMITIVETYPE Type,
INT BaseVertexIndex,
UINT MinIndex, //允许引用的最小索引值
UINT NumVertices,//将引用的顶点总数
UINT StartIndex, //
UINT PrimitiveCount
);
以上的绘制函数必须位于BeginScene() 和EndScene()函数对之间。
#include "d3dUtility.h" IDirect3DDevice9* Device = 0; const int Width = 640; const int Height = 480; IDirect3DVertexBuffer9* Triangle = 0; struct Vertex { Vertex(){} Vertex(float x, float y, float z) { _x = x; _y = y; _z = z; } float _x, _y, _z; static const DWORD FVF; }; const DWORD Vertex::FVF = D3DFVF_XYZ; // // Framework Functions // bool Setup() { Device->CreateVertexBuffer( 3 * sizeof(Vertex), // size in bytes D3DUSAGE_WRITEONLY, // flags Vertex::FVF, // vertex format D3DPOOL_MANAGED, // managed memory pool &Triangle, // return create vertex buffer 0); // not used - set to 0 // // Fill the buffers with the triangle data. // Vertex* vertices; Triangle->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); Triangle->Unlock(); // // Set the projection matrix. // D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, // result D3DX_PI * 0.5f, // 90 - degrees (float)Width / (float)Height, // aspect ratio 1.0f, // near plane 1000.0f); // far plane Device->SetTransform(D3DTS_PROJECTION, &proj); // // Set wireframe mode render state. // Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); return true; } void Cleanup() { d3d::Release<IDirect3DVertexBuffer9*>(Triangle); } bool Display(float timeDelta) { if( Device ) { Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); Device->SetStreamSource(0, Triangle, 0, sizeof(Vertex)); Device->SetFVF(Vertex::FVF); // Draw one triangle. Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1); Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; } // // WndProc // LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); } // // WinMain // int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device)) { ::MessageBox(0, "InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) { ::MessageBox(0, "Setup() - FAILED", 0, 0); return 0; } d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; }
人生无处不代码,没有代码不人生。