【Directx3D游戏开发】——简单渲染

            这是个令人十分激动的时刻,用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;
};

除此之外还需要一个描述这个顶点结构的常量FVF,这个常量可以是以下常量或它们的一些组合

  • D3DFVF_DIFFUSE:表示有漫反射颜色对象
  • D3DFVF_NORMAL:表示有顶点法线对象,不可和D3DFVF_XYZRHW同时使用
  • D3DFVF_SPECULAR:表示有镜面反射颜色对象
  • D3DFVF_XYZ:表示未转换顶点坐标,不可和D3DFVF_XYZRHW同时使用
  • D3DFVF_XYZRHW:表示转换过的顶点坐标,不可和D3DFVF_XYZ 及 D3DFVF_NORMAL同时使用
  • D3DFVF_XYZB1 到 D3DFVF_XYZB5:表示顶点混合权重数据,数值后缀为几就用几
  • D3DFVF_TEX0 到 D3DFVF_TEX8:表示纹理映射,几重映射后缀就是几
只是列出了FVF可能的取值,但对于具体什么时候该用什么还是很模糊。

                2.顶点缓冲区:Directx3D中的每个模型都是由三角形组成,每个三角形都是由三个顶点决定(不是废话,是什么?),为了更好地去渲染这些模型,需要把这些顶点放到Direct3D可以识别和读取的地方,这就是顶点缓冲区。
                3.索引缓冲区:在一个物体模型中,组成他们的三角形的顶点被多个面共用着,(如一个正方体它的每个顶点都是由三个面共用),如一个正方体有12个三角形,那顶点缓冲区里面就有36个点。也就是说顶点缓冲区里面其实有大量的重复数据,直接对其进行渲染必然导致效率下降。这时候就引入了索引缓冲区,它定义了一种缓冲区对顶点缓冲区提供索引,给定了顶点缓冲区里面顶点的组织方式,这样顶点缓冲区就没必要存放重复的点,既减少了内存,也提高了渲染时的效率。

                顶点缓冲区的创建:
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;
}



【Directx3D游戏开发】——简单渲染_第1张图片

旋转立方体:

//--------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;
}


【Directx3D游戏开发】——简单渲染_第2张图片


The End ~~~~~~

你可能感兴趣的:(游戏开发,DirectX,Direct3D)