3Dプログラミング基本 2-8

レイピッキングによる当たり判定(地面)

レイピッキングの利点は、移動前と移動後の座標を自由に設定できる部分にある。

キャラクタの移動後、移動前座標でなくてもいい。

今回はレイを足元に飛ばすことによって、地面の識別をしてみたいと思う。

以下のXファイルが追加で必要になるので、以下のURLからダウンロードし利用して欲しい。


◆ Download:[ 2_8_model.zip ]

2-8-1.地面の描画

ボックス(box.x)の代わりに地面メッシュ(jimen.x)を 座標(0,-5,0)に描画する。

地面の描画

▲TOP

2-8-2.交差位置が格納される変数準備

//  地面の座標を保存する変数					
D3DXVECTOR3     g_jimenpos = D3DXVECTOR3(0,-5,0);		
            

▲TOP

2-8-3.現在の座標から足元に向かってレイピッキング

レイピッキングのパターン

▲TOP

2-8-4.地面メッシュとの交差位置に確認用の影メッシュを描画

■変数宣言

//  影を表示するモデルの変数										
CDXUTMesh       *g_mesh3;                       //  メッシュを扱うポインタ変数		
D3DXVECTOR3     g_pos3 = D3DXVECTOR3(0,0,0);    //  座標		
D3DXMATRIX      g_matrix3;		
            

■ロード

g_mesh3 = new CDXUTMesh();                          //  メッシュを実体化しポインタを取得			
g_mesh3->Create(DXUTGetD3DDevice(),L"shadow.X");    //  メッシュのロード(これは描画用でない)			
g_mesh3->RestoreDeviceObjects(DXUTGetD3DDevice());  //  描画用メッシュの作成
            

■行列作成

D3DXMatrixTranslation( &g_matrix3 , g_pos3.x , g_pos3.y ,g_pos3.z );    //  移動マトリクスの作成
            

■行列のセットと描画

DXUTGetD3DDevice()->SetTransform(D3DTS_WORLD, &g_matrix3);              //  マトリクスのセット	
g_mesh3->Render( DXUTGetD3DDevice() );
            

■交差位置を影表示位置に代入

//  影の位置を更新		
g_pos3 = g_jimenpos;
            

■メッシュ解放

SAFE_DELETE( g_mesh3 );
            

▲TOP

2-8-5.ジャンプ処理

Y軸方向の移動量を保持する変数を作成。

//  重力を保存する変数		
float gravity = 0;		
            

更新関数でY軸方向の移動量を座標変数に毎ループ加算

g_pos.y += gravity;
            

■現在のY値と、地面のY値を比較

現在のY値のほうが大きければ、重力に値を加算。

地面のY値のほうが大きければ、重力を0にリセットし、現在のY値に地面Y値の値をセット。

スペースキーが押されており、かつY移動量が0(接地)ならば、Y移動量に+の一定値をセットし、ジャンプとする。>


↓参考:上記アルゴリズムのコーディング例

ジャンプ処理アルゴリズムのコーディング例

▲TOP

2-8-6.プログラミング

※追加箇所はマーカーで表記

※変更箇所は下部にて別途補足説明をする

//--------------------------------------------------------------------------------------														
// File: EmptyProject.cpp														
//														
// Empty starting point for new Direct3D applications														
//														
// Copyright (c) Microsoft Corporation. All rights reserved.														
//--------------------------------------------------------------------------------------														
#include "dxstdafx.h"														
#include "resource.h"														
#include "raypicktomesh.h"														
														
//  フォントオブジェクト													
LPD3DXFONT pFont;														
														
//  3Dメッシュ変数と関連変数 													
CDXUTMesh       *g_mesh;                            //  メッシュを扱うポインタ変数					
D3DXVECTOR3     g_pos = D3DXVECTOR3(0,0,0);         //  座標					
D3DXVECTOR3     g_beforepos = D3DXVECTOR3(0,0,0);   //  1フレーム前の座標					
D3DXMATRIX      g_matrix;												
														
//  当たり判定を計測するモデルの変数													
CDXUTMesh       *g_mesh2;                           //  メッシュを扱うポインタ変数					
D3DXVECTOR3     g_pos2 = D3DXVECTOR3(0,-5,0);       //  座標					
D3DXMATRIX      g_matrix2;												
														
//  影を表示するモデルの変数													
CDXUTMesh       *g_mesh3;                           //  メッシュを扱うポインタ変数					
D3DXVECTOR3     g_pos3 = D3DXVECTOR3(0,0,0);        //  座標					
D3DXMATRIX      g_matrix3;												
														
//  地面の座標を保存する変数														
D3DXVECTOR3     g_jimenpos = D3DXVECTOR3(0,-5,0);												
														
//  重力を保存する変数														
float gravity = 0;														
														
//  当たっているかを保存する変数											
bool            g_hitFlag = false;											
														
//--------------------------------------------------------------------------------------														
// Rejects any devices that aren't acceptable by returning false														
//--------------------------------------------------------------------------------------														
bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 														
                                  D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext )														
{														
    //  Typically want to skip backbuffer formats that don't support alpha blending														
    IDirect3D9* pD3D = DXUTGetD3DObject(); 														
    if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,														
                    AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 														
                    D3DRTYPE_TEXTURE, BackBufferFormat ) ) )														
        return false;														
														
    return true;														
}														
																												
//--------------------------------------------------------------------------------------														
// Before a device is created, modify the device settings as needed														
//--------------------------------------------------------------------------------------														
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext )														
{														
    return true;														
}														
																												
//--------------------------------------------------------------------------------------														
// Create any D3DPOOL_MANAGED resources here 														
//--------------------------------------------------------------------------------------														
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )														
{														
    return S_OK;														
}														
																												
//--------------------------------------------------------------------------------------														
// Create any D3DPOOL_DEFAULT resources here 														
//--------------------------------------------------------------------------------------														
HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 														
                                const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )														
{														
    return S_OK;														
}
            

※補足説明※

●23行めの[ D3DXVECTOR3 g_pos2 = D3DXVECTOR3(0,-5,0); // 座標  ]

は処理を変更した箇所。


↓Handle updates to the scene

※変更箇所は下部にて別途補足説明をする

//--------------------------------------------------------------------------------------															
// Handle updates to the scene															
//--------------------------------------------------------------------------------------															
void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )															
{															
															
	//  移動処理														
	if(DXUTIsKeyDown(VK_UP))														
	{														
		g_pos.z += 0.2f;													
	}														
	if(DXUTIsKeyDown(VK_DOWN))														
	{														
		g_pos.z -= 0.2f;													
	}														
	if(DXUTIsKeyDown(VK_RIGHT))														
	{														
		g_pos.x += 0.2f;													
	}														
	if(DXUTIsKeyDown(VK_LEFT))														
	{														
		g_pos.x -= 0.2f;													
	}														
															
	//  レイピック判定														
	if( RaypicktoMesh( false , &g_jimenpos ,g_pos + D3DXVECTOR3(0,100,0),g_pos + D3DXVECTOR3(0,-100,0),g_mesh2->GetMesh(),g_matrix2 ))														
	{														
		g_hitFlag = true;													
	}														
	else														
	{														
		g_hitFlag = false;													
	}														
															
	//  影の位置を更新														
	g_pos3 = g_jimenpos;														
															
	//  重力処理														
	if(g_pos.y > g_jimenpos.y)														
	{														
		gravity -= 0.016;													
	}														
	else														
	{														
		gravity = 0;													
		//  g_jimenpos = g_pos;													
		g_pos = g_jimenpos;													
	}														
	//  ジャンプ処理														
	static int count;														
	if(count > 0)														
	{														
		count--;													
	}														
	if(DXUTIsKeyDown(VK_SPACE) && count == 0 && gravity == 0)														
	{														
		count = 20;													
		gravity = 0.4f;													
	}
												
	//  重力は常に足す														
	g_pos.y += gravity;														
																														
	//  メッシュをレンダリングするためのマトリクス作成													
	D3DXMatrixTranslation( &g_matrix , g_pos.x , g_pos.y ,g_pos.z );        //  移動マトリクスの作成						
	D3DXMatrixTranslation( &g_matrix2 , g_pos2.x , g_pos2.y ,g_pos2.z );    //  移動マトリクスの作成						
	D3DXMatrixTranslation( &g_matrix3 , g_pos3.x , g_pos3.y ,g_pos3.z );    //  移動マトリクスの作成
						
	//  前フレームの位置を保存														
	g_beforepos = g_pos;														
}															
            

※補足説明※

●26行めの[ if( RaypicktoMesh( false , &g_jimenpos ,g_pos + D3DXVECTOR3(0,100,0),g_pos + D3DXVECTOR3(0,-100,0),g_mesh2->GetMesh(),g_matrix2 )) ]

は処理を変更した箇所。


↓Render the scene

※変更箇所は下部にて別途補足説明をする

//--------------------------------------------------------------------------------------													
// Render the scene 													
//--------------------------------------------------------------------------------------													
void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )													
{													
    HRESULT hr;													
													
    //  Clear the render target and the zbuffer 													
    V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 45, 50, 170), 1.0f, 0) );													
													
    //  Render the scene													
    if( SUCCEEDED( pd3dDevice->BeginScene() ) )													
    {													
		//  メッシュのレンダリング										
		DXUTGetD3DDevice()->SetTransform(D3DTS_WORLD, &g_matrix);   //  マトリクスのセット			
		g_mesh->Render( DXUTGetD3DDevice() );                       //  レンダリング			
													
		DXUTGetD3DDevice()->SetTransform(D3DTS_WORLD, &g_matrix2);  //  マトリクスのセット			
		g_mesh2->Render( DXUTGetD3DDevice() );                      //  レンダリング			
													
		DXUTGetD3DDevice()->SetTransform(D3DTS_WORLD, &g_matrix3);  //  マトリクスのセット			
		g_mesh3->Render( DXUTGetD3DDevice() );											
													
		//  文字列の準備と生成										
		TCHAR str[255];											
		RECT rect;											
													
		SetRect( &rect , 0,0,640,480);											
		_stprintf( str ,L"十字キーでモデル移動");											
		pFont->DrawText( NULL,str,-1,&rect,NULL,D3DCOLOR_RGBA(255,255,255,255));											
													
		SetRect( &rect , 0,20,640,480);											
		_stprintf( str ,L"スペースキーでジャンプ");											
		pFont->DrawText( NULL,str,-1,&rect,NULL,D3DCOLOR_RGBA(255,255,255,255));											
													
		SetRect( &rect , 0,40,640,480);											
		if(g_hitFlag == true)											
		{											
			_stprintf( str ,L"hit!");										
		}											
		else											
		{											
			_stprintf( str ,L"NO hit");										
		}
								
		pFont->DrawText( NULL,str,-1,&rect,NULL,D3DCOLOR_RGBA(255,255,255,255));											
		V( pd3dDevice->EndScene() );											
    }													
}													
													
//--------------------------------------------------------------------------------------													
// Handle messages to the application 													
//--------------------------------------------------------------------------------------													
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 													
                          bool* pbNoFurtherProcessing, void* pUserContext )													
{													
    return 0;													
}													
													
//--------------------------------------------------------------------------------------													
// Release resources created in the OnResetDevice callback here 													
//--------------------------------------------------------------------------------------													
void CALLBACK OnLostDevice( void* pUserContext )													
{													
}													
            

※補足説明※

●36行めの[ SetRect( &rect , 0,40,640,480); ]

は処理を変更した箇所。


↓Release resources created in the OnCreateDevice callback here

※変更箇所は下部にて別途補足説明をする

//--------------------------------------------------------------------------------------													
// Release resources created in the OnCreateDevice callback here													
//--------------------------------------------------------------------------------------													
void CALLBACK OnDestroyDevice( void* pUserContext )													
{													
	SAFE_DELETE( g_mesh );												
	SAFE_DELETE( g_mesh2 );												
	SAFE_DELETE( g_mesh3 );												
													
	SAFE_RELEASE( pFont );												
}													
													
//  アプリケーション初期化関数												
void InitApp( void )													
{													
	//  メッシュのロード											
	g_mesh = new CDXUTMesh();                           //  メッシュを実体化しポインタを取得				
	g_mesh->Create(DXUTGetD3DDevice(),L"tpot.X");       //  メッシュのロード(これは描画用でない)				
	g_mesh->RestoreDeviceObjects(DXUTGetD3DDevice());   //  描画用メッシュの作成				
													
	g_mesh2 = new CDXUTMesh();                          //  メッシュを実体化しポインタを取得				
	g_mesh2->Create(DXUTGetD3DDevice(),L"jimen.X");     //  メッシュのロード(これは描画用でない)				
	g_mesh2->RestoreDeviceObjects(DXUTGetD3DDevice());  //  描画用メッシュの作成				
													
	g_mesh3 = new CDXUTMesh();                          //  メッシュを実体化しポインタを取得				
	g_mesh3->Create(DXUTGetD3DDevice(),L"shadow.X");    //  メッシュのロード(これは描画用でない)				
	g_mesh3->RestoreDeviceObjects(DXUTGetD3DDevice());  //  描画用メッシュの作成				
													
	/////////////////////////////////////////////////////////////////////////////////////////////												
	//  3D環境の設定											
	//  カメラセット											
	D3DXMATRIX matview;
											
	//  注視マトリクスの生成        (カメラ位置  注視点  上方向)
	D3DXMatrixLookAtLH( &matview , &D3DXVECTOR3(0,10,-10),&D3DXVECTOR3(0,0,0),&D3DXVECTOR3(0,1,0));												
	DXUTGetD3DDevice()->SetTransform(D3DTS_VIEW,&matview);          //  マトリクスのセット				
													
	//  プロジェクション(パース)の生成											
	D3DXMATRIX matproj;
									
	//  注視マトリクスの生成    (視野角  アスペクト比    前方クリッピング平面 後方)		
	D3DXMatrixPerspectiveFovLH ( &matproj , D3DXToRadian(45),640.0f/480.0f , 0.1f,2000.0f);												
	DXUTGetD3DDevice()->SetTransform(D3DTS_PROJECTION,&matproj);    //  マトリクスのセット				
													
	//  ライトon 本当はセットライトで該当Noのライトに情報をセットするべきだが、有効にすればデフォルト値で初期化される											
	DXUTGetD3DDevice()->LightEnable(0,true);												
}													
													
//--------------------------------------------------------------------------------------													
// Initialize everything and go into a render loop													
//--------------------------------------------------------------------------------------													
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )													
{													
    //  Enable run-time memory check for debug builds.													
#if defined(DEBUG) | defined(_DEBUG)													
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );													
#endif													
													
    //  Set the callback functions													
    DXUTSetCallbackDeviceCreated( OnCreateDevice );													
    DXUTSetCallbackDeviceReset( OnResetDevice );													
    DXUTSetCallbackDeviceLost( OnLostDevice );													
    DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );													
    DXUTSetCallbackMsgProc( MsgProc );													
    DXUTSetCallbackFrameRender( OnFrameRender );													
    DXUTSetCallbackFrameMove( OnFrameMove );													
   													
    //  TODO: Perform any application-level initialization here													
													
    //  Initialize DXUT and create the desired Win32 window and Direct3D device for the application													
    DXUTInit( true, true, true );           //  Parse the command line, handle the default hotkeys, and show msgboxes													
    DXUTSetCursorSettings( true, true );    //  Show the cursor and clip it when in full screen													
    DXUTCreateWindow( L"EmptyProject" );													
    DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );													
													
//  フォントの作成												
D3DXCreateFont( DXUTGetD3DDevice(),													
	16,												
	0,												
	FW_NORMAL,												
	1,												
	false,												
	DEFAULT_CHARSET,												
	OUT_DEFAULT_PRECIS,												
	DEFAULT_QUALITY,												
	DEFAULT_PITCH,												
	L"",												
	&pFont);												
													
//  アプリケーションの初期化													
InitApp();													
    //  Start the render loop													
    DXUTMainLoop();													
													
    //  TODO: Perform any application-level cleanup here													
													
    return DXUTGetExitCode();													
}
            

※補足説明※

●22行めの[ g_mesh2->Create(DXUTGetD3DDevice(),L"jimen.X"); ]

は処理を変更した箇所。


2-8-7.動作確認

十字キーで移動、スペースキーでジャンプができ、地面の上に乗っていれば完了です。


> 完成例の実行ファイルはここからダウンロード

↓参考動画


▲TOP