这是个令人十分激动的时刻,用Directx3D去渲染出一些形状,还有会动的形状。感觉就跟中了彩票一样的心情。
好了,以上都是废话。在上一次的文章中学会了如何初始化Directx3D环境,now!开始真正的干事情了,首先要渲染一个三维三角形。在前面的代码的基础上其实添加小量代码就可以实现渲染了,不过还是要了解几个东西。
1.可变定点格式FVF(Flexible Vertex Format),Directx3D用这种方法来定义顶点结构,以满足各种不同情况的需求。用户可以根据自己程序的不同需要来定义相应的顶点对象,忽略某些对象,这样实现了在渲染模型是节省内存和最小化流水线宽度的目的。在此并不打算详细的说明FVF,因为其实我也不懂。。。简单来说FVF是Directx3D提供给用户灵活的定义自己的顶点结构的方式,你的顶点结构可以很复杂也可以很简单,只有x, y, z三个坐标,这完全看你的需要。在此我们要渲染一个彩色的三角形,所以我们为我们的顶点结构添加了除坐标之外的一个属性color。
struct CUSTOMVERTEX { FLOAT x, y, z, rhw; DWORD color; };
HRESULT IDirect3Ddevice9::CreateVetexBuffer( UINT Length, //分配给缓冲区的字节数 DWORD Usage, //标识缓冲区将会被怎样使用,设为0,标识没有附加属性 DWORD FVF, //缓冲区存储的顶点的可变顶点格式FVF D3DPOOL pool, //缓冲区的内存池类型 IDirect3DVertexBuffer9** ppVertexBuffer, //返回被创建的顶点缓冲区指针 HANDLE* pShareHandle //暂时未使用,扩展部分,设为0 );在创建顶点缓冲区后,需要用我们预先定义好的顶点数据去填充这个缓冲区,由于缓冲区有可能在显存或系统内存中,首先调用Lock()方法锁定获取缓冲区的首地址:
HRESULT IDirect3DVertexBuffer9::Lock( UNIT offsetToLock, //以字节计算的偏移地址,从缓冲区首部开始偏移地质处开始锁定 UNIT sizeToLock, //锁定的字节数 BYTE** ppData, //返回被锁定的缓冲区区域的头指针 DWORD Flags, //描述缓冲区锁定方式的标识 );
最后还要调用Unlock()解除锁定。
索引缓冲区的创建:和定点缓冲区类似HRESULT IDirect3DDevice9::CreateIndexBuffer( //参数含义基本和CreateVertexBuffer一样,只有Format不同 UINT Length, DWORD Usage, D3DFORMAT Format, //确定哪种索引格式,有16位,和32位,它们可以容纳的最大索引不同 D3DPOOL Pool, IDirect3DIndexBuffer** ppIndexBuffer, HANDLE* pShareHandle );
同样要用类似的Lock()方法锁定索引缓冲区:HRESULT IDirect3DIndexBuffer9::Lock( UNIT offsetToLock, //以字节计算的偏移地址,从缓冲区首部开始偏移地质处开始锁定 UNIT sizeToLock, //锁定的字节数 BYTE** ppData, //返回被锁定的缓冲区区域的头指针 DWORD Flags, //描述缓冲区锁定方式的标识 );
同样的Unlock()方法
到此渲染的数据已经准备完毕,在渲染之前还需要做几件事情:
1、设定数据源,也就是顶点缓冲区,把数据挂接到渲染流水线上等待渲染。
HRESULT IDirect3DDevice9::SetStreamSource( UINT StreamNumber, //根据显卡能力不同,可以支持多条流水线同时工作 IDirect3DVertexBuffer9* pStreamData, //顶点缓冲区数据指针 UINT offsetInBytes, //设置从缓冲区第几个字节开始挂接 UINT Stride, //顶点缓冲区的顶点大小,以字节计算 );
2、设置顶点格式:
SetFVF();
3、设置索引缓冲区:
SetIndices(IndexBuffer);
//---------------------------------------------------------------------------- //---------渲染一个一个基本的三维三角形 //---------by coderLing 2013.3.29 //---------------------------------------------------------------------------- #include <d3d9.h> //------Some gobal variables--------------------------------------------------- LPDIRECT3D9 g_pD3D = NULL; //用于创建D3DDevice 对象 LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; //指向顶点缓冲区 //------自定义顶点类型--------------------------------------------------------- struct CUSTOMVERTEX { FLOAT x, y, z, rhw; DWORD color; }; //------自定义的FVF------------------------------------------------------------ #define D3DFVF_CUSTOMVERTEX ( D3DFVF_XYZRHW | D3DFVF_DIFFUSE) //------常量------------------------------------------------------------------- #define WND_NAME L"vertexBuffer" #define WND_TITLE L"Directx3D深入详解之——创建使用定点缓冲区" //------初始化Directx3D-------------------------------------------------------- HRESULT InitD3D( HWND hWnd ) { //创建 D3D 对象 if( NULL == ( g_pD3D = Direct3DCreate9 ( D3D_SDK_VERSION) ) ) return E_FAIL; //设置D3DPRESENT_PRAMETERS参数 D3DPRESENT_PARAMETERS d3dpp; SecureZeroMemory( &d3dpp, sizeof(d3dpp) ); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; //创建 D3DDevice if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ) ) ) { return E_FAIL; } return S_OK; } //------初始化顶点缓冲区-------------------------------------------------------- HRESULT InitVB() { CUSTOMVERTEX vertices[] = { { 150.0f, 50.0f, 0.5f, 1.0f, 0xffff0000, }, //x, y, z, rhw, color { 250.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, }, { 50.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, }, }; //创建顶点缓冲区,要申请足够的内存空间 if( FAILED( g_pd3dDevice->CreateVertexBuffer( 3*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) ) ) return E_FAIL; //把顶点数据填充到缓冲区中 VOID* pVertices; if( FAILED( g_pVB->Lock( 0, sizeof(vertices), (void**)&pVertices, 0 ) ) ) return E_FAIL; memcpy( pVertices, vertices, sizeof(vertices) ); g_pVB->Unlock(); return S_OK; } //------释放资源---------------------------------------------------------------------- VOID Cleanup() { if( g_pVB != NULL) g_pVB->Release(); if( g_pd3dDevice != NULL) g_pd3dDevice->Release(); if( g_pD3D != NULL) g_pD3D->Release(); } //--------渲染过程--------------------------------------------------------------------- VOID Render() { //把背景缓冲区变为蓝色 g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0); //开始渲染 if( SUCCEEDED( g_pd3dDevice->BeginScene() ) ) { //绘制三角形 g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) ); //设置数据源 g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); //设置顶点格式 g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 ); //渲染顶点缓冲区中的图形 //渲染结束 g_pd3dDevice->EndScene(); } g_pd3dDevice->Present( NULL, NULL, NULL, NULL); } //---------消息过程--------------------------------------------------------------------- LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: Cleanup(); PostQuitMessage( 0 ); return 0; } return DefWindowProc( hWnd, msg, wParam, lParam ); } //---------WinMain()函数---------------------------------------------------------------- INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT) { WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, WND_NAME, NULL}; RegisterClassEx( &wc ); HWND hWnd = CreateWindow( WND_NAME, WND_TITLE, WS_OVERLAPPEDWINDOW, 100, 100, 300, 300, GetDesktopWindow(), NULL, wc.hInstance, NULL ); if( SUCCEEDED( InitD3D(hWnd) ) ) { if( SUCCEEDED( InitVB() ) ) { ShowWindow( hWnd, SW_SHOWDEFAULT ); UpdateWindow( hWnd ); //消息循环 MSG msg; SecureZeroMemory( &msg, sizeof(MSG) ); while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL,0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else Render(); } } } UnregisterClass( WND_NAME, wc.hInstance ); return 0; }
旋转立方体:
//--------ColorfulCube---------------------------------------------------------------- //--------by coderLing 2013.3.30 //------------------------------------------------------------------------------------ #include <d3d9.h> #include <d3dx9.h> //如果要使用D3DX库就必须加入这个头文件 //定义使用到的顶点结构 struct CUSTOMVERTEX { FLOAT x,y,z; //顶点坐标信息 DWORD color; //顶点颜色信息 }; //定义顶点的FVF结构 #define D3DFVF_CUSTOMVERTEX ( D3DFVF_XYZ | D3DFVF_DIFFUSE) #define WND_NAME L"ColorfulCube" #define WND_TITLE L"Directx3D游戏开发之-ColorfulCube" //some gobal variables LPDIRECT3D9 g_pD3D = NULL; //Direct3D对象指针,LP开头便是指针 LPDIRECT3DDEVICE9 g_pD3DDevice = NULL; //Direct3D 设备 LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; //顶点缓冲区指针 LPDIRECT3DINDEXBUFFER9 g_pIB = NULL; //索引缓冲区指针 //初始化Direct3D设备 HRESULT InitD3D( HWND hWnd) { //创建Directx3D对象 if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) return E_FAIL; //填写创建Direct3D设备的结构体 D3DPRESENT_PARAMETERS d3dpp; SecureZeroMemory( &d3dpp, sizeof( d3dpp )); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; //创建Direct3D设备 if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDevice) ) ) { return E_FAIL; } return S_OK; } //初始化绘图相关数据,顶点缓冲区,索引缓冲区 HRESULT InitDraw() { //创建顶点缓冲区 g_pD3DDevice->CreateVertexBuffer( 8 * sizeof(CUSTOMVERTEX), D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_MANAGED, &g_pVB, 0); //创建索引缓冲区 g_pD3DDevice->CreateIndexBuffer( 36 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &g_pIB, 0); //创建立方体的8个顶点,每个顶点的颜色都不同 //在绘制是,Direct3D会根据顶点的颜色对三角形内部像素进行插值,所以立方体看起来是彩色的 CUSTOMVERTEX source_vertices[] ={ { -1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255,0,0) }, { -1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0,255,0) }, { 1.0f, 1.0f, -1.0f, D3DCOLOR_XRGB(0,0,255) }, { 1.0f, -1.0f, -1.0f, D3DCOLOR_XRGB(255,255,0) }, { -1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(255,0,255) }, { -1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0,255,255) }, { 1.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0,0,0) }, { 1.0f, -1.0f, 1.0f, D3DCOLOR_XRGB(255,255,255) } }; //把上面的顶点数据复制到所创建的缓冲区中 CUSTOMVERTEX* pVertices; if( FAILED( g_pVB->Lock(0, 8*sizeof(CUSTOMVERTEX), (VOID**)&pVertices, 0) ) ) return E_FAIL; memcpy( pVertices, source_vertices, 8*sizeof(CUSTOMVERTEX) ); g_pVB->Unlock(); //定义索引缓冲区的内容 WORD* indices = 0; g_pIB->Lock(0, 0, (VOID**)&indices, 0); //正面 indices[0] = 0; indices[1] = 1; indices[2] = 2; indices[3] = 0; indices[4] = 2; indices[5] = 3; //背面 indices[6] = 4; indices[7] = 6; indices[8] = 5; indices[9] = 4; indices[10] = 7; indices[11] = 6; //左面 indices[12] = 4; indices[13] = 5; indices[14] = 1; indices[15] = 4; indices[16] = 1; indices[17] = 0; //右面 indices[18] = 3; indices[19] = 2; indices[20] = 6; indices[21] = 3; indices[22] = 6; indices[23] = 7; //顶面 indices[24] = 1; indices[25] = 5; indices[26] = 6; indices[27] = 1; indices[28] = 6; indices[29] = 2; //顶面 indices[30] = 4; indices[31] = 0; indices[32] = 3; indices[33] = 4; indices[34] = 3; indices[35] = 7; g_pIB->Unlock(); //设置摄像机 D3DXVECTOR3 position(0.0f, 0.0f, -5.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMATRIX V; D3DXMatrixLookAtLH(&V, &position, &target, &up); g_pD3DDevice->SetTransform(D3DTS_VIEW, &V); //设置投影矩阵 D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, D3DX_PI * 0.5f, (float)800 / (float)600, 1.0f, 1000.0f ); g_pD3DDevice->SetTransform( D3DTS_PROJECTION, &proj); //没有材质,纹理信息,关闭灯光显示出本身颜色 g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); return S_OK; } //------释放资源------------------------------------------------------------------------------ VOID Cleanup() { if( g_pVB != NULL ) g_pVB->Release(); if( g_pIB != NULL ) g_pIB->Release(); if( g_pD3DDevice != NULL ) g_pD3DDevice->Release(); if( g_pD3D != NULL) g_pD3D->Release(); } //--------渲染函数------------------------------------------------------------------ VOID Render() { //清除屏幕缓冲区到蓝色屏幕 g_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 255),1.0f, 0); //开始绘制 if( SUCCEEDED( g_pD3DDevice->BeginScene() ) ) { //创建沿3个轴的矩阵 D3DXMATRIXA16 matWorld_X; D3DXMatrixIdentity( &matWorld_X); D3DXMatrixRotationX( &matWorld_X, timeGetTime()/500.0f); D3DXMATRIXA16 matWorld_Y; D3DXMatrixIdentity( &matWorld_Y); D3DXMatrixRotationY( &matWorld_Y, timeGetTime()/500.0f); D3DXMATRIXA16 matWorld_Z; D3DXMatrixIdentity( &matWorld_Z); D3DXMatrixRotationZ( &matWorld_Z, timeGetTime()/500.0f); //设置物体的世界矩阵 g_pD3DDevice->SetTransform( D3DTS_WORLD, &(matWorld_X*matWorld_Y*matWorld_Z) ); g_pD3DDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) ); g_pD3DDevice->SetFVF( D3DFVF_CUSTOMVERTEX ); g_pD3DDevice->SetIndices( g_pIB ); g_pD3DDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 8, 0,12); //结束绘制 g_pD3DDevice->EndScene(); } //显示 g_pD3DDevice->Present( NULL, NULL, NULL, NULL); } //消息回调函数 LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: Cleanup(); PostQuitMessage( 0 ); return 0; } return DefWindowProc( hWnd, msg, wParam, lParam ); } //Main函数 INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT) { //创建及注册窗口类 WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL, WND_NAME, NULL}; RegisterClassEx( &wc ); //创建窗口 HWND hWnd = CreateWindow( WND_NAME, WND_TITLE, WS_OVERLAPPEDWINDOW, 100, 100, 800, 600, GetDesktopWindow(), NULL, wc.hInstance, NULL ); if( SUCCEEDED( InitD3D(hWnd) ) ) { if( SUCCEEDED( InitDraw() ) ) { //显示窗口 ShowWindow( hWnd, SW_SHOWDEFAULT ); UpdateWindow( hWnd ); //消息循环 MSG msg; SecureZeroMemory( &msg, sizeof(msg) ); while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else Render(); } } } UnregisterClass( WND_NAME, wc.hInstance ); return 0; }
The End ~~~~~~