1.DirectXのシーンをクラス化する

 

まずは、表示の一連の流れ、「シーン」をクラス化します。
これは、たとえば、ゲームなどにおいて

ゲーム画面 <−> 設定画面

といった切り替えを容易に行うことを想定して作っています。

DirectX10における「DXUT」ライブラリを用いることを前提にします。

まずは、DirectXにおいて、画面が描画される一連の処理を抽出してみましょう。

・初期化
・画面のリサイズ
・時間の経過
・描画処理
・終了処理

となります。

ソースコードで書くと、
#pragma once
#include "DXUT.h"

class TDXScene
{
public:
  TDXScene(void);
  virtual ~TDXScene(void);
  virtual HRESULT Init(ID3D10Device* pd3dDevice) = 0;
  virtual HRESULT OnFrameMove( double fTime, float fElapsedTime, void* pUserContext ) = 0;
  virtual HRESULT OnRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ) = 0;
  virtual HRESULT OnResize( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain,
                                           const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ) = 0;
protected:
//  ID3D10Device* pd3dDevice;  //対象となるデバイスへのポインタを持つべきか?
                             //対象となるデバイスは呼び出しの間に変わるかもしれない(画面モードの変更などの理由によって)
                 //よって、これは各呼び出しによって引数で渡されるべき


};

これは何もしないので抽象クラスです。

次にサンプルに付属する「Tutorial08」と同じものを表示させるクラスを作ってみます。

 


#pragma once
#include "tdxscene.h"

class TDXTestScene :
  public TDXScene
{
public:
  TDXTestScene(void);
  virtual ~TDXTestScene(void);
  virtual HRESULT Init(ID3D10Device* pd3dDevice);
  virtual HRESULT OnFrameMove( double fTime, float fElapsedTime, void* pUserContext );
  virtual HRESULT OnRender( ID3D10Device* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
  virtual HRESULT OnResize( ID3D10Device* pd3dDevice, IDXGISwapChain* pSwapChain,
                                          const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext );

protected:
ID3D10Effect*                       g_pEffect; //エフェクト=シェーダプログラムを読ませるところ
ID3D10InputLayout*                  g_pVertexLayout;
ID3D10EffectTechnique*              g_pTechnique;
ID3D10Buffer*                       g_pVertexBuffer;
ID3D10Buffer*                       g_pIndexBuffer;
ID3D10ShaderResourceView*           g_pTextureRV;
ID3D10EffectMatrixVariable*         g_pWorldVariable;
ID3D10EffectMatrixVariable*         g_pViewVariable;
ID3D10EffectMatrixVariable*         g_pProjectionVariable;
ID3D10EffectVectorVariable*         g_pMeshColorVariable;
ID3D10EffectVectorVariable*      g_pLightDirVariable;
ID3D10EffectShaderResourceVariable* g_pDiffuseVariable;
D3DXMATRIX                          g_World;
D3DXMATRIX                          g_View;
D3DXMATRIX                          g_Projection;
D3DXVECTOR4                         g_vMeshColor;
D3DXVECTOR4              g_vLightDir;

};

ずいぶんとプロテクトメンバが増えました。
Tutorialだとこの辺が全てグローバル変数なのでC++使いには気持ち悪いというのもクラス化の動機の一つです。

ほとんどがシェーダと、シェーダとCPUのやりとりに使われる変数です。

中身は割愛させていただきますが、(Tutorial丸写しになってしまうので)

・コンストラクタは実変数については初期化、ポインタ変数についてはNULLでクリア
・Init()でnewが必要な変数を作成する
・Resize()で
・FrameMove()は・OnRender()は・デストラクタでは

といったところでしょうか。

各メソッドとDirectXの動作との対応は以下のようになると思います。

関数 呼び出し元 コメント
コンストラクタ OnCreateDevice デバイスロストとの対応から。だが、Initと分ける意味がなくなる気もする。
デストラクタ OnDestroyDevice リソースの解放を忘れずに。
Init OnCreateDevice ID3D10Deviceのオブジェクトが必要な処理はこちらに分離。
FrameMove OnFrameMove 描画にかかわらず時間経過によって呼ばれる。ここでアニメーションに必要な処理を行う
OnRender OnFrameRender 実際の描画を行う。新たなパラメータを元に画面を描画する。
OnResize OnResizedSwapChain 射影行列を初期化する(プログラム内ではg_Projection)