ホーム < ゲームつくろー! < DirectX技術編

その56 カメラの視線で移動・回転してみよう:サンプルプログラム



 DirectX技術編その56「カメラの視線で移動・回転してみよう」で説明した内容を踏まえたサンプルプログラムです。実行するとティーポットが出現します。キー操作でティーポットが回転しますが、これはモデルが回転しているのではなくてカメラが回転しています。ティーポットと一緒についてきている影を見るとわかります。


サンプルスクリーンショット。キー操作でティーポットの周りをカメラが回ります。

 サンプルを動かすために必要なファイルはこちらからダウンロードできます(DXGSmp_No54.lzh)。アーカイブに含まれているヘッダーファイル(.h)、実装ファイル(.cpp)、Xファイルをプロジェクト直下に置いて、空のプロジェクトに実装ファイルを追加すると動かす事ができます。うまく動かない場合は掲示板にご連絡下さい。

 アーカイブ内にはViewerCameraクラスが含まれています。使用方法は以下のサンプルコードをご覧頂くと直ぐにわかると思います。毎フレーム更新を忘れずに行って下さい。

// main.cpp

// カメラベース回転サンプルプログラム

#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

#include <windows.h>
#include <tchar.h>
#include <d3d9.h>
#include <d3dx9.h>
#include "ViewerCamera.h"


TCHAR gName[100]  = _T("カメラベース回転サンプルプログラム");
TCHAR exprain_g[] = _T("←→: 左右球面上移動\n")
                    _T("↑↓: 上下球面上移動\n")
                    _T("  W : 奥行き方向移動\n")
                    _T("  S : 手前方向移動\n")
                    _T("Z-C : Z軸回転");

struct KeyInfo {
   float L;
   float R;
   float U;
   float D;
   float Pull;
   float Push;
   float Shift;
   float Ctrl;
   float Alt;
   float Space;
   float ZRol;
   float YRol;
   float XRol;

   void clear() {
      L = 0; R = 0; U = 0; D = 0; Pull = 0; Push = 0;
      Shift = 0; Ctrl = 0; Alt = 0; Space = 0;
      ZRol = 0;
      YRol = 0;
      XRol = 0;
   }
};

#define KEYCHECK( x ) ( keyState[ x ] & 0x80 )
void updateKeyInfo( KeyInfo& info ) {

   info.clear();

   BYTE keyState[ 256 ];
   GetKeyboardState( keyState );
   
   if ( KEYCHECK( VK_SPACE ) )      { info.Space = 1.0f; }
   if ( KEYCHECK( VK_SHIFT ) )      { info.Shift = 1.0f; }
   if ( KEYCHECK( VK_CONTROL ) )   { info.Ctrl = 1.0f; }
   if ( KEYCHECK( VK_MENU ) )      { info.Alt = 1.0f; }
   if ( KEYCHECK( VK_LEFT ) )      { info.L = 1.0f; }
   if ( KEYCHECK( VK_RIGHT ) )      { info.R = 1.0f; }
   if ( KEYCHECK( VK_UP ) )      { info.U = 1.0f; }
   if ( KEYCHECK( VK_DOWN ) )      { info.D = 1.0f; }
   if ( KEYCHECK( 'S' ) )         { info.Pull = 1.0f; }
   if ( KEYCHECK( 'W' ) )         { info.Push = 1.0f; }
   if ( KEYCHECK( 'Z' ) )         { info.ZRol = -1.0f; }
   if ( KEYCHECK( 'C' ) )         { info.ZRol = +1.0f; }
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam){
   if(mes == WM_DESTROY || mes == WM_CLOSE ) { PostQuitMessage(0); return 0; }
   return DefWindowProc(hWnd, mes, wParam, lParam);
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
   // アプリケーションの初期化
   MSG msg; HWND hWnd;
   WNDCLASSEX wcex ={sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, NULL, NULL,
                                    (HBRUSH)(COLOR_WINDOW+1), NULL, (TCHAR*)gName, NULL};
   if(!RegisterClassEx(&wcex))
      return 0;

   if(!(hWnd = CreateWindow(gName, gName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
                                    NULL, NULL, hInstance, NULL)))
      return 0;

   // Direct3Dの初期化
   LPDIRECT3D9 g_pD3D;
   LPDIRECT3DDEVICE9 g_pD3DDev;
   if( !(g_pD3D = Direct3DCreate9( D3D_SDK_VERSION )) ) return 0;

   D3DPRESENT_PARAMETERS d3dpp = {0,0,D3DFMT_UNKNOWN,0,D3DMULTISAMPLE_NONE,0,
                                                      D3DSWAPEFFECT_DISCARD,NULL,TRUE,0,D3DFMT_UNKNOWN,0,0}; 
   d3dpp.EnableAutoDepthStencil = TRUE;
   d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;

   if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
   if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
   {
      g_pD3D->Release();
      return 0;
   }

   ShowWindow(hWnd, nCmdShow);


   // フォントの生成
   int fontsize = 24;
   D3DXFONT_DESC lf = { fontsize, 0, 0, 1, 0, SHIFTJIS_CHARSET, OUT_TT_ONLY_PRECIS,
                        PROOF_QUALITY, FIXED_PITCH | FF_MODERN, _T("MS ゴシック") };

   // ID3DXFontコンポーネント生成
   LPD3DXFONT pD3DFont;
   if(FAILED(D3DXCreateFontIndirect(g_pD3DDev, &lf, &pD3DFont))){
      g_pD3DDev->Release();  g_pD3D->Release();
      return 0;
   }
   RECT r={ 0, 0, 0, 0 };
   if(FAILED(pD3DFont->DrawText(NULL, exprain_g, -1, &r, DT_CALCRECT | DT_LEFT | DT_WORDBREAK, 0xffffffff))){
      g_pD3DDev->Release();  g_pD3D->Release();
      return 0;
   }

   // テストモデル作成
   ID3DXMesh* mesh;
   D3DXCreateTeapot( g_pD3DDev, &mesh, NULL );

   D3DXVECTOR3 cameraPos( 0, 0, -5 );
   D3DXVECTOR3 cameraViewPos( 0, 0, 0 );
   D3DXVECTOR3 cameraUp( 0, 1, 0 );

   // ライト
   D3DLIGHT9 light;
   ZeroMemory(&light, sizeof(D3DLIGHT9) );
   light.Direction = D3DXVECTOR3(-1, -20, 0);
   light.Type = D3DLIGHT_DIRECTIONAL; 
   light.Diffuse.r = 1.0f;
   light.Diffuse.g = 1.0f;
   light.Diffuse.b = 1.0f;
   light.Ambient.r = 0.5f;
   light.Ambient.g = 0.5f;
   light.Ambient.b = 0.5f;
   light.Range = 1000;

   g_pD3DDev->SetLight( 0, &light );
   g_pD3DDev->LightEnable( 0, true );
   g_pD3DDev->SetRenderState( D3DRS_LIGHTING, TRUE );
   g_pD3DDev->SetRenderState( D3DRS_AMBIENT, 0x00808080 );   // アンビエントライト

   // マテリアル
   D3DMATERIAL9 material;
   memset( &material, 0, sizeof( D3DMATERIAL9 ) );
   D3DCOLORVALUE diffuse = { 1.0f, 1.0f, 1.0f, 1.0f };
   material.Diffuse = diffuse;

   // ビューワーカメラ
   Dix::ViewerCamera viewerCamera;
   viewerCamera.update();
   viewerCamera.setLookAt( D3DXVECTOR3( 0, 0, 0 ) );

   // 各種行列
   D3DXMATRIX world, view, proj;
   D3DXMatrixIdentity( &world );
   D3DXMatrixLookAtLH( &view, &cameraPos, &cameraViewPos, &cameraUp );
   D3DXMatrixPerspectiveFovLH( &proj, D3DXToRadian( 45.0f ), 640.0f/480.0f, 1.0f, 3000.0f );
   g_pD3DDev->SetTransform( D3DTS_WORLD, &world );
   g_pD3DDev->SetTransform( D3DTS_VIEW, &view );
   g_pD3DDev->SetTransform( D3DTS_PROJECTION, &proj );



   // メッセージ ループ
   do{
      Sleep(1);
      if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){ DispatchMessage( &msg ); }
      else{
         // キー情報取得
         KeyInfo keyInfo;
         updateKeyInfo( keyInfo );

         // カメラの位置を更新
         viewerCamera.move( keyInfo.R - keyInfo.L, keyInfo.D - keyInfo.U, keyInfo.Push - keyInfo.Pull );
         viewerCamera.rotZ( D3DXToRadian( keyInfo.ZRol ) );
         viewerCamera.update();
         viewerCamera.getViewMatrix( &view );

         g_pD3DDev->SetTransform( D3DTS_VIEW, &view );

         // Direct3Dの処理
         g_pD3DDev->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );
         g_pD3DDev->BeginScene();

            // 描画
         g_pD3DDev->SetMaterial( &material );
         mesh->DrawSubset( 0 );
            pD3DFont->DrawText(NULL, exprain_g, -1, &r, DT_LEFT | DT_WORDBREAK, 0xffffffff);

         g_pD3DDev->EndScene();
         g_pD3DDev->Present( NULL, NULL, NULL, NULL );
      }
   }while(msg.message != WM_QUIT);

   mesh->Release();
   pD3DFont->Release();
   g_pD3DDev->Release();
   g_pD3D->Release();

   return 0;
}