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

~複数ライトの設定~

実際のゲームシーンではライトは1つでなく、同時に複数利用されることが多い。

もっとも標準的なライティングに三点照明という考え方があるので、今回はそれを実現してみたい。


※↓「三点照明」の概念については、以下のサイトの「11.三点照明」の欄がわかりやすく参考になるため、ここに紹介しておく。

http://www.alchemyschool.com/mayatips/lighting01/

//  ライト情報のセット								
DXUTGetD3DDevice()->SetLight( 0, &dlight );     //  0番ライトに情報をセット		
DXUTGetD3DDevice()->LightEnable( 0 , true );    //  0番ライト有効		
            

複数のライトを設定するためには、以下のライト設定関数の番号を変えてやればよい。

> [ SetLight( 0, &dlight ); ]

> [ LightEnable( 0 , true ); ]


※ライトを無効にするには、LightEnable()メソッドで false をセットする。

今回は三点照明にのっとり、以下のようなライトをセットし、効果を確認してみよう。


0番ライト キーライト:正面からあてる強いライト(真っ白はやめよう、他のライトの効果が確認しずらくなります)

1番ライト フィルライト:横方向からあてる弱めのライト

2番ライト バックライト:後ろからあてる弱めのライト


定数で管理するのは効率がよくないので、変数とループを用いて3つのライトを管理する。

さらにライトパラメータ変数もここで配列にして管理していく。


2-3-1.変数宣言

				
int index;      // ライト管理変数		
				
            

変数から配列変数へ変更

D3DCOLORVALUE diff[3];		
D3DCOLORVALUE spec[3];		
D3DXVECTOR3 dir[3];
            
  

▲TOP

2-3-2.ライトパラメータ変数への値を設定

//  ライト向きの初期設定						
dir[0] = D3DXVECTOR3(0.5f,-0.7f,0.2f);						
dir[1] = D3DXVECTOR3(3.5f,0.1f,-0.8f);						
dir[2] = D3DXVECTOR3(0.1f,-0.8f,2.1f);						
						
//  ライトの色の初期化 わかりやすくライトの色を別々な色に設定						
diff[0].r = diff[1].g = diff[2].b = 1.0f;						
diff[1].r = diff[0].g = diff[0].b = 0.0f;						
diff[2].r = diff[2].g = diff[1].b = 0.0f;
						
//  ハイライトの色の初期化						
for(int i = 0; i < 3;i++)						
{						
	spec[i].r = spec[i].g = spec[i].b = 1.0f;					
}															
        
  

▲TOP

2-3-3.プログラミング

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

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

//--------------------------------------------------------------------------------------														
// File: EmptyProject.cpp														
//														
// Empty starting point for new Direct3D applications														
//														
// Copyright (c) Microsoft Corporation. All rights reserved.														
//--------------------------------------------------------------------------------------														
														
#include "dxstdafx.h"														
#include "resource.h"														
														
//  フォントオブジェクト													
LPD3DXFONT pFont;														
														
//  3Dメッシュ変数と関連変数 													
//  CDXUTMeshクラスを使用するには、commonフォルダにある DXUTMesh.cppとDXUTMesh.hをプロジェクトに追加すること													
CDXUTMesh   *g_mesh;            //  メッシュを扱うポインタ変数					
														
void setDirectionalLight();														
D3DCOLORVALUE diff[3];          //  ライト色の変数						
D3DCOLORVALUE spec[3];          //  ハイライト色の変数						
D3DXVECTOR3 dir[3];             //  ライト向きの変数

        

※補足説明※

●20行めの[ D3DCOLORVALUE diff[3]; ]

●21行めの[ D3DCOLORVALUE spec[3]; ]

●22行めの[ D3DXVECTOR3 dir[3]; ]

以上は処理を変更した箇所である。


↓ Rejects any devices that aren't acceptable by returning 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														
//--------------------------------------------------------------------------------------														
void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )														
{														
/*  //  ライトのパラメータを変更													
	//  ライト方向の変更													
	if(DXUTIsKeyDown(VK_UP))													
	{													
		dir.y -= 0.1f;												
	}													
	if(DXUTIsKeyDown(VK_DOWN))													
	{													
		dir.y += 0.1f;												
	}													
	if(DXUTIsKeyDown(VK_LEFT))													
	{													
		dir.x -= 0.1f;												
	}													
	if(DXUTIsKeyDown(VK_RIGHT))													
	{													
		dir.x += 0.1f;												
	}													
	if(DXUTIsKeyDown('Z'))													
	{													
		dir.z -= 0.1f;												
	}													
	if(DXUTIsKeyDown('X'))													
	{													
		dir.z += 0.1f;												
	}													
														
	//  ライト色の変更													
	if(DXUTIsKeyDown('R'))                  //  赤								
	{													
		if(DXUTIsKeyDown(VK_UP))												
		{												
			diff.r += 0.1f;											
		}												
		if(DXUTIsKeyDown(VK_DOWN))												
		{												
			diff.r -= 0.1f;											
		}												
	}													
	if(DXUTIsKeyDown('G'))                  //  緑								
	{													
		if(DXUTIsKeyDown(VK_UP))												
		{												
			diff.g += 0.1f;											
		}												
		if(DXUTIsKeyDown(VK_DOWN))												
		{												
			diff.g -= 0.1f;											
		}												
	}													
	if(DXUTIsKeyDown('B'))                  //  青								
	{													
		if(DXUTIsKeyDown(VK_UP))												
		{												
			diff.b += 0.1f;											
		}												
		if(DXUTIsKeyDown(VK_DOWN))												
		{												
			diff.b -= 0.1f;											
		}												
	}													
*/														
	//  ディレクションライト処理													
	setDirectionalLight();													
}																												
														
//--------------------------------------------------------------------------------------														
// 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() ) )														
    {														
		//  メッシュのレンダリング											
		g_mesh->Render( DXUTGetD3DDevice() );   //  レンダリング				
														
		//  文字列の準備と生成											
		TCHAR str[255];												
		RECT rect;												
														
		SetRect( &rect , 0,0,640,480);												
		_stprintf( str ,L"3点照明");												
		pFont->DrawText( NULL,str,-1,&rect,NULL,D3DCOLOR_RGBA(255,255,255,255));												
/*		SetRect( &rect , 0,20,640,480);												
		_stprintf( str ,L"R・G・Bキー+上下キーで色変更");												
		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

※追加箇所のみマーカーで表記

											
//--------------------------------------------------------------------------------------														
// Release resources created in the OnCreateDevice callback here														
//--------------------------------------------------------------------------------------														
void CALLBACK OnDestroyDevice( void* pUserContext )														
{														
	//  3Dメッシュの解放												
	SAFE_DELETE( g_mesh );													
														
	SAFE_RELEASE( pFont );													
}														
														
//  アプリケーション初期化関数													
void InitApp( void )														
{														
	//  メッシュのロード												
	g_mesh = new CDXUTMesh();                           //  メッシュを実体化しポインタを取得					
	g_mesh->Create(DXUTGetD3DDevice(),L"isu.x");        //  メッシュのロード(これは描画用でない)					
	g_mesh->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);    //  マトリクスのセット		
														
	//  ライト向きの初期設定													
	dir[0] = D3DXVECTOR3(0.5f,-0.7f,0.2f);													
	dir[1] = D3DXVECTOR3(3.5f,0.1f,-0.8f);													
	dir[2] = D3DXVECTOR3(0.1f,-0.8f,2.1f);													
														
	//  ライトの色の初期化 わかりやすくライトの色を別々な色に設定													
	diff[0].r = diff[1].g = diff[2].b = 1.0f;	
	diff[1].r = diff[0].g = diff[0].b = 0.0f;					
	diff[2].r = diff[2].g = diff[1].b = 0.0f;
										
	//  ハイライトの色の初期化			
	for(int i = 0; i < 3;i++)		
	{													
		spec[i].r = spec[i].g = spec[i].b = 1.0f;												
	}													
}														
	

↓ Initialize everything and go into a render loop

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

															
//--------------------------------------------------------------------------------------														
// 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();														
}														
														
														
void setDirectionalLight()														
{														
	int index;      //  ライト管理変数											
	D3DLIGHT9 dlight;													
	ZeroMemory( &dlight , sizeof( D3DLIGHT9 ));													
														
	for(index = 0;index < 3;index++)													
	{													
		//  パラメータセット ライト												
		dlight.Diffuse = diff[index];												
														
		//  パラメータセット ハイライト												
		dlight.Specular = spec[index];												
														
		//  タイプ												
		dlight.Type = D3DLIGHT_DIRECTIONAL;												
														
		//  向き												
		dlight.Direction = dir[index];												
														
		//  情報セット												
		DXUTGetD3DDevice()->SetLight(index,&dlight);												
		DXUTGetD3DDevice()->LightEnable(index,true);												
	}													
														
	//  enable													
	DXUTGetD3DDevice()->SetRenderState(D3DRS_LIGHTING, TRUE);
}																											
        

※補足説明※

●64行めの[ dlight.Diffuse = diff[index]; ]

●67行めの[ dlight.Specular = spec[index]; ]

●73行めの[ dlight.Direction = dir[index]; ]


●76行めの[ DXUTGetD3DDevice()->LightEnable(index,&dlight); ]

●77行めの[ DXUTGetD3DDevice()->LightEnable(index,true); ]

以上は処理を変更した箇所である。


2-4.ライトの有効・無効切替

ここは、2-3でも説明していたので再度確認するだけにとどめておこう。


↓ライトを無効にするには、LightEnable()メソッドで false をセットする。

//  ライト情報のセット								
DXUTGetD3DDevice()->SetLight( 0, &dlight );     //  0番ライトに情報をセット		
DXUTGetD3DDevice()->LightEnable( 0 , false );   //  0番ライト有効
            

あとはキー情報をif文なりで取得すれば、ライトのオンオフを完成するので挑戦して欲しい。

  

2-3-4.動作確認

↓以下のような色味になっていれば完了です。


2-3-4 動作確認

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

▲TOP

>「2-5 ビルボード処理」へ続く