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

レイピッキングによる当たり判定

レイピッキングの当たり判定

レイピッキングとは、移動前と移動後の2点間を結ぶ線分と、ポリゴンメッシュとの交差判定を表す。

当たり判定の中でもっとも現実の考え方に沿っている方式の一つである。

今回は、こちらで準備したレイピッキング用関数を用い交差判定を行う。

興味のある人は、この関数も自作できるよう目指して欲しい。

2-6-1.レイピッキングによる衝突判定

まず、下記4つのファイルを下のURLよりダウンロード。

「raypicktomesh.cpp」

「raypicktomesh.h」

「box.x」

「tpot.x」


◆ Download:[ 2_6_model+src.zip ]

プロジェクトに追加後、使用したいソースでヘッダファイルをインクルードすれば使える。

プロジェクトへの追加は、1-1でやっているのでそちらを参照。

▲TOP

2-6-2.関数リファレンス

RaypicktoMesh() オーバーロード1 静止しているメッシュに対し、移動前、移動後の座標情報での判定

第1引数 bool moveflag, すべりモードのOn/Off を true か false で渡す
第2引数 D3DXVECTOR3 *resultpos, 衝突した場合の座標を格納する変数へのアドレス。衝突地点が必要なければ NULL
第3引数 D3DXVECTOR3 pos_before , 移動前の座標
第4引数 D3DXVECTOR3 pos_after , 移動後の座標
第5引数 LPD3DXMESH mesh , 当たり判定を取るメッシュの頂点情報
第6引数 D3DXMATRIX matrix 当たり判定を取るメッシュを変換する行列

戻り値 bool型 当ったときにtrue 当っていないときにfalseを返す。

  

▲TOP

2-6-3.コーディング準備

2つのモデルがレンダリング(表示)され、片方はカーソルキーで操作できるようにする


2つのモデルの判定メッシュ

ティーポットの前フレーム座標の保存  D3DXVECTOR3 g_beforeposを定義

更新関数 OnFrameMove()の最後で位置を保存し、前フレームの位置を利用できるようにする。

前フレームの位置情報保存

※↑画像の文字が見にくい場合は画像クリックで大きくなります。


↓ヒット確認フラグを定義 bool g_hitFlag を定義

//  当たっているかを保存する変数			
bool	g_hitFlag = false;	
            

↓交差判定

更新関数 OnFrameMove() で交差判定を行う。交差していたらフラグを使って、文字列を描画してみる。

//  レイピックによる衝突判定							
if( RaypicktoMesh( false , NULL ,g_beforepos,g_pos,g_mesh2->GetMesh(),g_matrix2 ))								
{								
        g_hitFlag = true;							
}								
else								
{								
        g_hitFlag = false;							
}
            
  

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

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

													
//--------------------------------------------------------------------------------------													
// 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,0,5);        //  座標				
D3DXMATRIX      g_matrix2;											
													
//  当たっているかを保存する変数													
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;													
}													
        

↓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 , NULL , g_beforepos , g_pos , g_mesh2->GetMesh() , g_matrix2) )												
	{												
		g_hitFlag = true;											
	}												
	else												
	{												
		g_hitFlag = false;											
	}												
													
	//  メッシュをレンダリングするためのマトリクス作成											
	D3DXMatrixTranslation( &g_matrix , g_pos.x , g_pos.y ,g_pos.z );    //  移動マトリクスの作成				
	D3DXMatrixTranslation( &g_matrix2 , g_pos2.x , g_pos2.y ,g_pos2.z );//  移動マトリクスの作成
				
	//  前フレームの位置を保存												
	g_beforepos = g_pos;												
}													
																										
//--------------------------------------------------------------------------------------													
// 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() );                      //  レンダリング			
													
													
		//  文字列の準備と生成										
		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);	
										
		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 )													
{													
}													
													
													
//--------------------------------------------------------------------------------------													
// Release resources created in the OnCreateDevice callback here													
//--------------------------------------------------------------------------------------													
void CALLBACK OnDestroyDevice( void* pUserContext )													
{													
	SAFE_DELETE( g_mesh );												
	SAFE_DELETE( g_mesh2 );												
													
	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"box.X");       //  メッシュのロード(これは描画用でない)				
	g_mesh2->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();													
}		
        

2-6-5.動作確認

↓十字キーで移動、移動中にボックスに当たったら、hit表示が出れば完了です。


2-6-5 動作確認

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

↓参考動画


▲TOP

>「2-7 レイピッキングによる当たり判定(すべり有り)」へ続く