DirectXプログラミング05 Xファイルの読み込み・表示

̃Gg[͂ĂȃubN}[Nɒlj

ようやくXファイルの扱いに入ります。


Xファイルって

[中身]
・頂点情報
・テクスチャ情報
・アニメーション情報
が格納されているらしい。
[使用目的]
・メッシュを一括して読み込むために使用される

Xファイルの読み込み

◆メッシュを読み込む

■D3DXLoadMeshFromX
[関数プロトタイプ]

HRESULT D3DXLoadMeshFromX(
	LPCTSTR pFilename,
	DWORD Options,
	LPDIRECT3DDEVICE9 pDevice,
	LPD3DXBUFFER* ppAdjacency,
	LPD3DXBUFFER* ppMaterials,
	LPD3DXBUFFER* ppEffectInstances,
	DWORD* dwNumMaterials,
	LPD3DXMESH* ppMesh
);

各引数の解説は→MSDN Microsoft DirectX 9.0 D3DXLoadMeshFromX 関数

LPCTSTR pFilename ファイル名を指定する文字列へのポインタ
DWORD Options メッシュの作成オプションを指定
D3DXMESH列挙型フラグ組み合わせ指定
LPDIRECT3DDEVICE9 pDevice IDirect3DDevice9 インターフェイスへのポインタ
メッシュに関連付けられているデバイス オブジェクト
LPD3DXBUFFER* ppAdjacency
LPD3DXBUFFER* ppMaterials マテリアル データを含むバッファへのポインタ
LPD3DXBUFFER* ppEffectInstances
DWORD* dwNumMaterials D3DXMATERIAL構造体の数へのポインタ
LPD3DXMESH* ppMesh D3DXMeshインターフェイスへのポインタのアドレス
	LPD3DXMESH pMesh = NULL;
	DWORD dwNumMaterials = 0;

	/* Xファイルからメッシュをロードする	*/
	LPD3DXBUFFER pD3DXMtrlBuffer = NULL;/*	マテリアルバッファのポインタ	*/
	if(FAILED(D3DXLoadMeshFromX(L"inosisi.x",
								D3DXMESH_SYSTEMMEM,
								pDevice,
								NULL,
								&pD3DXMtrlBuffer,
								NULL,
								&dwNumMaterials,
								&pMesh))){
		MessageBox(NULL, L"Xファイルの読み込みに失敗しました", NULL, MB_OK);
		return E_FAIL;
	}

この関数の役割は以下。

①マテリアルバッファポインタの初期化(第5引数)
このバッファは、マテリアルを取得(後述)し終わったら解放します。

	pD3DXMtrlBuffer->Release();

②マテリアルの数を返す(第7引数)
③メッシュのポインタの初期化(第8引数)

◆マテリアルとテクスチャを読み込む

マテリアルは、D3DXLoadMeshFromX関数で取得したマテリアルバッファから格納
テクスチャは、D3DXCreateTextureFromFileで取得する。

■D3DXCreateTextureFromFile
[関数プロトタイプ]

HRESULT D3DXCreateTextureFromFile(
	LPDIRECT3DDEVICE9 pDevice,
	LPCTSTR pSrcFile,
	LPDIRECT3DTEXTURE9 *ppTexture
);

各引数の解説は→MSDN Microsoft DirectX 9.0 D3DXCreateTextureFromFile 関数

LPDIRECT3DDEVICE9 pDevice Direct3DDevice9インターフェイスへのポインタ
LPCTSTR pSrcFile ファイル名を指定する文字列へのポインタ
LPDIRECT3DTEXTURE9 *ppTexture Direct3DTexture9インターフェイスへのポインタのアドレス
	D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
	D3DMATERIAL9* 		pMeshMaterials	= NULL;
	LPDIRECT3DTEXTURE9* pMeshTextures	= NULL;

	pMeshMaterials = new D3DMATERIAL9[dwNumMaterials];
	pMeshTextures = new LPDIRECT3DTEXTURE9[dwNumMaterials];
	for(DWORD i=0; i<dwNumMaterials; i++)
	{
		pMeshMaterials[i]			= d3dxMaterials[i].MatD3D;
		pMeshMaterials[i].Ambient	= pMeshMaterials[i].Diffuse;
		pMeshTextures[i] = NULL;

		if(d3dxMaterials[i].pTextureFilename != NULL &&
		   lstrlen(d3dxMaterials[i].pTextureFilename) > 0){
			if(FAILED(D3DXCreateTextureFromFile(pDevice,
												d3dxMaterials[i].pTextureFilename,
												&pMeshTextures[i]))){
				MessageBox(NULL, L"テクスチャの読み込みに失敗しました", NULL, MB_OK);
			}
		}
	}

レンダリングステートの設定

・Zバッファー処理を有効にする。
 後ろに隠れているポリゴンは描画しないようにする。
 メッシュの描画するときは有効にするらしい。
・ライトを有効にする。
 頂点に色情報がないメッシュでは有効にするらしい。
 ※前回は頂点に色情報があったので無効にしていた。
・アンビエント光(環境光)の設定
 均一に照射され、影を作らない光らしい。

	/*	Zバッファー処理を有効にする	*/
	pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
	/*	ライトを有効にする	*/
	pDevice->SetRenderState( D3DRS_LIGHTING, TRUE);
	/*	アンビエントライト(環境光)を設定する	*/
	pDevice->SetRenderState(D3DRS_AMBIENT, 0x00111111);
	/*	スペキュラ(鏡面反射)を有効にする	*/
	pDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE);

トランスフォーム処理

ワールドトランスフォームのみ、前回から変更。
※今回も特に取り上げない。

レンダリング処理

IDirect3DDevice9::SetMaterialによりマテリアル設定を適用、
IDirect3DDevice9::SetTextureによりテクスチャを設定、
ID3DXMesh::DrawSubsetによりレンダリングするらしい。

	pDevice->Clear(	0,
					NULL,
					D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
					D3DCOLOR_XRGB(100,100,100),
					1.0f,
					0);
	if(SUCCEEDED(pDevice->BeginScene())){
		for(DWORD i=0; i<dwNumMaterials; i++)
		{
			pDevice->SetMaterial(&pMeshMaterials[i]);
			pDevice->SetTexture(0, pMeshTextures[i]);
			pMesh->DrawSubset(i);
		}

		pDevice->EndScene();
	}
	pDevice->Present(NULL,
					 NULL,
					 NULL,
					 NULL); 

コード全体

#include <windows.h>
#include <d3dx9.h>;
#define SAFE_RELEASE(p) {if(p){(p)-&gt;Release(); (p)=NULL;}}

FLOAT CamX=0, CamY=1, CamZ=-3;

/*	Direct3D関連	*/
LPDIRECT3D9 pD3d;
LPDIRECT3DDEVICE9 pDevice;
LPD3DXMESH pMesh = NULL;
D3DMATERIAL9* pMeshMaterials = NULL;
LPDIRECT3DTEXTURE9* pMeshTextures = NULL;
DWORD dwNumMaterials = 0;

/*	プロトタイプ宣言	*/
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HRESULT InitD3d(HWND);
VOID Render();
VOID FreeDx();

/*	エントリ関数	*/
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szStr, INT iCmdShow)
{
	HWND hWnd = NULL;
	MSG msg;
	
	/*	ウィンドウの初期化	*/
	LPCWSTR szAppName = L&quot;DirectXプログラミング05 Xファイルの読み込み・表示&quot;;
	WNDCLASSEX wndclass;
	wndclass.cbSize			= sizeof(wndclass);
	wndclass.style			= CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc	= WndProc;
	wndclass.cbClsExtra		= 0;
	wndclass.cbWndExtra		= 0;
	wndclass.hInstance		= hInst;
	wndclass.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wndclass.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
	wndclass.lpszMenuName	= NULL;
	wndclass.lpszClassName	= szAppName;
	wndclass.hIconSm		= LoadIcon(NULL, IDI_APPLICATION);
	RegisterClassEx(&amp;wndclass);
	hWnd = CreateWindow(szAppName,
						szAppName,
						WS_OVERLAPPEDWINDOW,
						0,
						0,
						640,
						480,
						NULL,
						NULL,
						hInst,
						NULL);
	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);
	
	/*	Direct3Dの初期化	*/
	if(FAILED(InitD3d(hWnd))){
		return 0;
	}
	/*	メッセージループ	*/
	ZeroMemory(&amp;msg, sizeof(msg));
	while(msg.message != WM_QUIT){
		if(PeekMessage( &amp;msg,
						NULL,
						0U,
						0U,
						PM_REMOVE)){
			TranslateMessage(&amp;msg);
			DispatchMessage(&amp;msg);
		} else {
			Render();
		}
	}
	/*	メッセージループから抜けたらオブジェクトをすべて開放する。	*/
	FreeDx();

	/*	アプリケーションを終了する	*/
	return(INT)msg.wParam;
}

/*	ウィンドウプロシージャ	*/
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
	switch(iMsg){
		case WM_DESTROY :
			PostQuitMessage(0);
		break;
		case WM_KEYDOWN :
			switch((CHAR)wParam){
				case VK_ESCAPE:
				PostQuitMessage(0);
				break;
				case VK_LEFT:
					CamX += 0.5;
				break;
				case VK_RIGHT:
					CamX -= 0.5;
				break;
				case VK_UP:
					CamY += 0.5;
				break;
				case VK_DOWN:
					CamY -= 0.5;
				break;
				case VK_NUMPAD8:
					CamZ += 0.5;
				break;
				case VK_NUMPAD2:
					CamZ -= 0.5;
				break;
			}
		break;
	}
	return DefWindowProc(hWnd, iMsg, wParam, lParam);
}

/*	Direct3Dの初期化	*/
HRESULT InitD3d(HWND hWnd)
{
	/*	Direct3Dオブジェクトの生成	*/
	if(NULL == (pD3d = Direct3DCreate9(D3D_SDK_VERSION))){
		MessageBox(0, L&quot;Direct3Dの作成に失敗しました&quot;, L&quot;&quot;, MB_OK);
		return E_FAIL;
	}
	/*	Direct3Dデバイスオブジェクトの生成	*/
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&amp;d3dpp, sizeof(d3dpp));
	d3dpp.BackBufferFormat	= D3DFMT_UNKNOWN;
	d3dpp.BackBufferCount	= 1;
	d3dpp.SwapEffect		= D3DSWAPEFFECT_DISCARD;
	d3dpp.Windowed			= TRUE;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;	
	if(FAILED(pD3d-&gt;CreateDevice(	D3DADAPTER_DEFAULT,
									D3DDEVTYPE_HAL,
									hWnd,
									D3DCREATE_MIXED_VERTEXPROCESSING,
									&amp;d3dpp,
									&amp;pDevice))){
		MessageBox(0, L&quot;HALモードでDirect3Dデバイスを作成できませんnREFモードで再試行します&quot;, NULL, MB_OK);
		if(FAILED(pD3d-&gt;CreateDevice(D3DADAPTER_DEFAULT,
									 D3DDEVTYPE_REF,
									 hWnd,
									 D3DCREATE_MIXED_VERTEXPROCESSING,
									 &amp;d3dpp,
									 &amp;pDevice))){
			 MessageBox(0, L&quot;DIRECT3Dデバイスの作成に失敗しました&quot;, NULL, MB_OK);
			 return E_FAIL;
		}
	}
	/* Xファイルからメッシュをロードする	*/
	LPD3DXBUFFER pD3DXMtrlBuffer = NULL;/*	マテリアルバッファのポインタ	*/
	if(FAILED(D3DXLoadMeshFromX(L&quot;inosisi.x&quot;,
								D3DXMESH_SYSTEMMEM,
								pDevice,
								NULL,
								&amp;pD3DXMtrlBuffer,
								NULL,
								&amp;dwNumMaterials,
								&amp;pMesh))){
		MessageBox(NULL, L&quot;Xファイルの読み込みに失敗しました&quot;, NULL, MB_OK);
		return E_FAIL;
	}
	D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer-&gt;GetBufferPointer();
	pMeshMaterials = new D3DMATERIAL9[dwNumMaterials];
	pMeshTextures = new LPDIRECT3DTEXTURE9[dwNumMaterials];
	for(DWORD i=0; i&lt;dwNumMaterials; i++)
	{
		pMeshMaterials[i] = d3dxMaterials[i].MatD3D;
		pMeshMaterials[i].Ambient = pMeshMaterials[i].Diffuse;
		pMeshTextures[i] = NULL;
		if(d3dxMaterials[i].pTextureFilename != NULL &amp;&amp;
		   lstrlen((LPCWSTR)d3dxMaterials[i].pTextureFilename) &gt; 0)
		{
			/*	プロジェクト設定を「ユニコード文字セットを使用する」にしており、	*/
			/*	関数D3DXCreateTextureFromFileの第2引数には、ユニコード文字列を要求される	*/
			/*	第2引数に渡したい、d3dxMaterials[i].pTextureFilenameの型は、		*/
			/*	LPSTR型(マルチバイト文字列?)かもしれなので対応が必要					*/
#if Kaiketu01
			/*	解決法その①														*/
			/*	3DXCreateTextureFromFile→3DXCreateTextureFromFileAにする。			*/
			/*	多分、マルチバイト文字列(?)を使用して動作するようになる。			*/
			if(FAILED(D3DXCreateTextureFromFileA(pDevice,
												d3dxMaterials[i].pTextureFilename,
												&amp;pMeshTextures[i])))
			{
				MessageBox(NULL, L&quot;テクスチャの読み込みに失敗しました&quot;, NULL, MB_OK);
			}
#endif
			/*	解決法その②														*/
			/*	関数MultiByteToWideCharを使用してLPWSTR型(ユニコード文字列?)に変換	*/
			LPSTR lpstrFileName = d3dxMaterials[i].pTextureFilename;
			WCHAR wstrFileName[MAX_PATH] = {0};
			MultiByteToWideChar(CP_ACP,			/* コードページ					*/
								0,				/* 文字の種類を指定するフラグ	*/
								lpstrFileName,	/* 文字列のポインタ				*/
								-1,				/* 文字列のバイト数				*/
								wstrFileName,	/* UNICODE文字列バッファのポインタ	*/
								MAX_PATH);		/* UNICODE文字列バッファのサイズ	*/
			if(FAILED(D3DXCreateTextureFromFile(pDevice,
												wstrFileName,
												&amp;pMeshTextures[i])))
			{
				MessageBox(NULL, L&quot;テクスチャの読み込みに失敗しました&quot;, NULL, MB_OK);
			}
		}
	}
	pD3DXMtrlBuffer-&gt;Release();
	
	/*	レンダリングステートの設定	*/
	/*	Zバッファー処理を有効にする	*/
	pDevice-&gt;SetRenderState(D3DRS_ZENABLE, TRUE);
	/*	ライトを有効にする	*/
	pDevice-&gt;SetRenderState( D3DRS_LIGHTING, TRUE);
	/*	アンビエントライト(環境光)を設定する	*/
	pDevice-&gt;SetRenderState(D3DRS_AMBIENT, 0x00888888);
	/*	スペキュラ(鏡面反射)を有効にする	*/
	pDevice-&gt;SetRenderState(D3DRS_SPECULARENABLE, TRUE);

	return S_OK;
}
/*	Xファイルから読み込んだメッシュをレンダリング	*/
VOID Render()
{
	/*	ポリゴン(やメッシュ)のレンダリングに必要な3つのトランスフォームを実施	*/
	/*	1:ワールドトランスフォーム(絶対座標変換)			*/
	/*		ローカル座標をワールド座標絶対座標に変換する	*/
	D3DXMATRIXA16 matWorld, matRotation;
	D3DXMatrixRotationX(&amp;matWorld, timeGetTime()/3000.0f);
	D3DXMatrixRotationY(&amp;matRotation, 0.5f);
	D3DXMatrixMultiply(&amp;matWorld, &amp;matWorld, &amp;matRotation);
	/*	matWorld行列を係数としてワールドトランスフォーム実施	*/
	pDevice-&gt;SetTransform(D3DTS_WORLD, &amp;matWorld);
	
	/*	2:ビュートランスフォーム(視点座標変換)	*/
	/*		カメラの位置を指定する。				*/
	D3DXVECTOR3 vecEyePt( CamX, CamY, CamZ);	/*	カメラ(視点)位置	*/
	D3DXVECTOR3 vecLookatPt( 0.0f, 0.0f, 0.0f);/*	注視位置	*/
	D3DXVECTOR3 vecUpVec( 0.0f, 1.0f, 0.0f);	/*	上方位置	*/
	//D3DMATRIXA16 matView;
	D3DMATRIX matView;
	D3DXMatrixLookAtLH((D3DXMATRIX *)&amp;matView,
					   &amp;vecEyePt,
					   &amp;vecLookatPt,
					   &amp;vecUpVec);
	pDevice-&gt;SetTransform( D3DTS_VIEW, &amp;matView);

	/*	3:プロジェクショントランスフォーム(射影変換)	*/
	/*		カメラレンズのズーム等の指定				*/
	D3DXMATRIXA16 matProj;
	D3DXMatrixPerspectiveFovLH( &amp;matProj, 
								D3DX_PI/4,
								1.0f,
								1.0f,
								100.0f);
	pDevice-&gt;SetTransform( D3DTS_PROJECTION, &amp;matProj);

	/*	ライトをあてる(白紙で鏡面反射ありに設定)	*/
	D3DXVECTOR3 vecDirection(0, 1, 1);
	D3DLIGHT9 light;
	ZeroMemory(&amp;light, sizeof(D3DLIGHT9));
	light.Type = D3DLIGHT_DIRECTIONAL;
	light.Diffuse.r = 1.0f;
	light.Diffuse.g = 1.0f;
	light.Diffuse.b = 1.0f;
	light.Specular.r = 1.0f;
	light.Specular.b = 1.0f;
	light.Specular.g = 1.0f;
	D3DXVec3Normalize( (D3DXVECTOR3*)&amp;light.Direction,
					   &amp;vecDirection);
	light.Range = 200.0f;
	pDevice-&gt;SetLight(0, &amp;light);
	pDevice-&gt;LightEnable(0, TRUE);

	/*	レンダリング	*/
	pDevice-&gt;Clear(	0,
					NULL,
					D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
					D3DCOLOR_XRGB(100,100,100),
					1.0f,
					0);
	if(SUCCEEDED(pDevice-&gt;BeginScene())){
		for(DWORD i=0; i&lt;dwNumMaterials; i++)
		{
			pDevice-&gt;SetMaterial(&amp;pMeshMaterials[i]);
			pDevice-&gt;SetTexture(0, pMeshTextures[i]);
			pMesh-&gt;DrawSubset(i);
		}

		pDevice-&gt;EndScene();
	}
	pDevice-&gt;Present(NULL,
					 NULL,
					 NULL,
					 NULL); 
					
}
/*	DirectXオブジェクトの解放	*/
VOID FreeDx()
{
	SAFE_RELEASE(pMesh);
	SAFE_RELEASE(pDevice);
	SAFE_RELEASE(pD3d);
}

次回からは、今まで触れなかった移動や回転について掘り下げていきたいと思います。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です