Microsoft Visual C++ 2010 Express
 Microsoft DirectX SDK (June 2010)
 Direct3D 11.0
 Shader Model 4.0

■Direct3D 11.0 ジオメトリシェーダー Prev Top Next
関連ページ:Direct3D 11.0 初期化 Direct3D 11.0 デバック用フォント描画
2011/05/10:
  1. 入力レイアウトの作成処理を D3D11USER クラス内で行うように修正
2012/03/11:
  1. マルチレンダーターゲットに対応するためにブレンドステートを設定する関数を修正


しばらくぶりの更新です。仕事が忙しくてしばらく満足に更新できない状態が続きますが、まあ困る人はいないよね(笑)。

さてネットワークやらOracleのサンプル作成やらで迷走してましたが、今回からいよいよ楽しい楽しいシェーダープログラミングです。 手始めにジオメトリシェーダーからです。 ジオメトリシェーダーは Direct3D 10 から追加された機能です。 なのでかなり今更なところがありますが、自分 Direct3D 10 はスキップしたため今回初めて使うことになります。 なので、まずは基本的なことをやっていきます。

まずはジオメトリシェーダーとはなにか? ジオメトリシェーダーは既存のプリミティブから新しいプリミティブを生成したり削除するためのシェーダーです。 まあ頂点シェーダーでプリミティブの頂点の生成と削除が行えるように機能拡張したものだと考えていいと思います。 でジオメトリシェーダーはすでに説明したとおり Direct3D 10 から追加された機能のためビデオカードが Shader Model 4.0 に対応していることが条件となります。 とまあ簡単な説明ですが、これ以上書きようもないので。

ジオメトリシェーダーの説明はこんなところで、次にサンプルの概要です。 今回はジオメトリシェーダーの説明用のために、簡単なサンプルにします。
内容は、既存のボックスプリミティブをそのまま描画し、ジオメトリシェーダーにてスケール値を大きくした新しいボックスプリミティブを半透明で描画します。

サンプルの概要はこれだけですが、いくつか補足説明を。
自作のD3D11USERクラスにジオメトリシェーダー関連のメンバ関数を追加したので、まずは Direct3D 11.0 初期化を参照して修正を行ってください。
あと以前作成した FBX ローダーはサンプルソースの簡略化のため、今回使用しません。今後も可能な限り使用しないようにします。


---SimpleHLSL09.hlsl---

// ワールド行列 × ビュー × 射影行列
cbuffer cbMatrixWVP : register( b0 )
{
   // 列優先
   column_major  float4x4 g_matWVP : packoffset( c0 );
};

cbuffer cbVecLight : register( b1 )
{
   float4 g_vecLight : packoffset( c0 );
};

// テクスチャー
Texture2D g_Tex : register( t0 );

// サンプラーステート
SamplerState  g_Sampler : register( s0 );

// 頂点シェーダーの入力パラメータ
struct VS_IN
{
   float3 pos   : POSITION;   // 頂点座標
   float3 normal: NORMAL;     // 法線
   float2 texel : TEXCOORD;   // テクセル
};

// 頂点シェーダーの出力パラメータ
struct VS_OUT
{
   float4 pos    : POSITION;
   float3 normal : NORMAL;
   float2 texel  : TEXCOORD0;
};

// 頂点シェーダー
VS_OUT VS_Main( VS_IN In )
{
   VS_OUT Out = { float4( In.pos, 1.0f ), In.normal, In.texel };
   return Out;
}

// ジオメトリシェーダーの入力パラメータ
typedef VS_OUT GS_IN;

// ジオメトリシェーダーの出力パラメータ
struct GS_OUT
{
   float4 pos    : SV_POSITION;
   float3 normal : NORMAL;
   float2 texel  : TEXCOORD0;
   float4 color  : COLOR0;          // 頂点カラーはジオメトリシェーダー内で追加する
};

// ジオメトリ シェーダー オブジェクト (DirectX HLSL)

[maxvertexcount(6)]   // ジオメトリシェーダーで出力する最大頂点数
// ジオメトリシェーダー
void GS_Main( triangle GS_IN In[3],                    // トライアングル リストを構成する頂点配列の入力情報
              inout TriangleStream<GS_OUT> TriStream   // 頂点情報を追加するためのストリームオブジェクト
            )
{
   GS_OUT Out;
   
   int i;
   
   // もとの頂点を出力
   for( i=0; i<3; i++ )
   {
      Out.pos = mul( float4( In[i].pos.xyz, 1.0f ), g_matWVP );
      Out.normal = In[i].normal;
      Out.texel = In[i].texel;
      Out.color = float4( 1.0f, 1.0f, 1.0f, 1.0f );   // 元の頂点は不透明で出力
      
      // 頂点を追加する
      TriStream.Append( Out );
   }
   // 現在のストリップを終了し、新しいストリップを開始する。
   TriStream.RestartStrip();

   // 新しく頂点を追加する
   for( i=0; i<3; i++ )
   {
      Out.pos = mul( float4( In[i].pos.xyz + In[i].normal * 2.0f, 1.0f ), g_matWVP );
      Out.normal = In[i].normal;
      Out.texel = In[i].texel;
      Out.color = float4( 1.0f, 1.0f, 1.0f, 0.5f );   // 追加した頂点は半透明で出力
      
      // 頂点を追加する
      TriStream.Append( Out );
   }
   // 現在のストリップを終了し、新しいストリップを開始する。
   TriStream.RestartStrip();
}

// ピクセルシェーダーの入力パラメータ
typedef GS_OUT PS_IN;

// ピクセルシェーダ
float4 PS_Main( PS_IN In ) : SV_TARGET
{
   // ランバート拡散照明
   float Color = max( dot( -g_vecLight.xyz, normalize( In.normal ) ), 0.8f );

   return g_Tex.Sample( g_Sampler, In.texel ) * Color * In.color;
}

シェーダーを記述した、HLSLファイルです。ライティングはいつものランバート拡散照明です。

さて、順に説明していきます。

1.頂点シェーダー
これまでのサンプルでは頂点シェーダーとピクセルシェーダーのみ使用していました。 この場合、頂点の行列変換は頂点シェーダーで行いますが、今回はジオメトリシェーダーのほうで行列変換するため、頂点シェーダーでは行列変換せずそのまま返すようにします。 だったら頂点シェーダー使用しなければいいのではとか思ったのですが、ID3D11DeviceContext::VSSetShader( NULL, NULL, 0 ); とすると ディスプレイドライバが停止して実行不可能になります。どうも頂点シェーダーは必須っぽいです。それともやりかたが悪いのかなあ。

2.ジオメトリシェーダー
GS_Main() については ジオメトリ シェーダー オブジェクト (DirectX HLSL) を参照するといいでしょう。
またジオメトリシェーダーの実装方法については、 チュートリアル 13:ジオメトリ シェーダー を参照するといいでしょう。
手抜きくさいけどオンラインマニュアル以上の説明は必要ないので。

3.ピクセルシェーダー
ピクセルシェーダーについては特に説明することはないです。

---main.cpp---


#include "../../USER/DX11User.h"
#include "../../USER/D3D11User.h"

#include "../../USER/DebugFontUser.h"
// コンパイル済み頂点シェーダー
#include "../../USER/HLSL/SimpleHLSL09_vs.h"
// コンパイル済みジオメトリシェーダー
#include "../../USER/HLSL/SimpleHLSL09_gs.h"
// コンパイル済みピクセルシェーダー
#include "../../USER/HLSL/SimpleHLSL09_ps.h"

// シェーダーオブジェクトを作成するとき、ファイルから読むか、メモリから読むかを切り替える
#if defined(DEBUG) || defined(_DEBUG)
#define UNCOMPILED_SHADER     // ファイルを読み込んでコンパイルする
#endif

// アプリケーション名
TCHAR* AppName = _T("DX11_Tutrial09");

// Direct3D関連の自作クラス
D3D11USER* g_pD3D11User = NULL;

// デバッグ専用のテキスト描画する自作クラス
CDebugFont* g_pDebugFontUser = NULL;

// 頂点バッファ
ID3D11Buffer* g_pVertexBuffer = NULL;
// インデックスバッファ
ID3D11Buffer* g_pIndexBuffer = NULL;
// 頂点シェーダー
ID3D11VertexShader* g_pVertexShader = NULL;
// 入力レイアウト
ID3D11InputLayout* g_pLayout = NULL;
// 定数バッファ
ID3D11Buffer* g_pConstantBuffers[2] = { NULL, NULL };
// ピクセルシェーダー
ID3D11PixelShader* g_pPixelShader = NULL;
// ジオメトリシェーダー
ID3D11GeometryShader* g_pGeometryShader = NULL;
// シェーダーリソースビュー
ID3D11ShaderResourceView* g_pSRView = NULL;
// サンプラーステート
ID3D11SamplerState* g_pSamplerState = NULL;
// 深度ステンシルステート
ID3D11DepthStencilState*  g_pDepthStencilState = NULL;

// 節電モードの制御に使用する変数。
bool Activate = true;    // ウィンドウがアクティブか
bool StandBy = false;    // スタンバイ状態か

bool ScreenShot = false; // スクリーンショットを作成するかフラグ

D3DXVECTOR4 g_vecLight = D3DXVECTOR4( -0.3f, -0.3f, 0.5f, 0.0f );

typedef struct _CBUFFER
{
   D3DXMATRIX  g_matWVP;
   D3DXVECTOR4 g_vecLight;
}CBUFFER;

// 頂点定義
struct VERTEX
{
   // 頂点座標
   D3DXVECTOR3 pos;
   // 法線ベクトル
   D3DXVECTOR3 normal;
   // テクセル
   D3DXVECTOR2 texel;
};

// リソースの初期化
HRESULT Init()
{
   HRESULT hr = E_FAIL;

   D3DX11_IMAGE_LOAD_INFO info;

   D3DXVECTOR3 N = D3DXVECTOR3( 1.0f,  1.0f, 1.0f );
   D3DXVec3Normalize( &N, &N );

   // ボックスプリミティブを設定
   VERTEX v[] = { 
                  D3DXVECTOR3( -2.0f,  2.0f, -2.0f ), D3DXVECTOR3( -N.x,  N.x, -N.x ), D3DXVECTOR2( 0.0f, 0.0f ),
                  D3DXVECTOR3(  2.0f,  2.0f, -2.0f ), D3DXVECTOR3(  N.x,  N.x, -N.x ), D3DXVECTOR2( 1.0f, 0.0f ),
                  D3DXVECTOR3( -2.0f, -2.0f, -2.0f ), D3DXVECTOR3( -N.x, -N.x, -N.x ), D3DXVECTOR2( 0.0f, 1.0f ),
                  D3DXVECTOR3(  2.0f, -2.0f, -2.0f ), D3DXVECTOR3(  N.x, -N.x, -N.x ), D3DXVECTOR2( 1.0f, 1.0f ),

                  D3DXVECTOR3(  2.0f,  2.0f,  2.0f ), D3DXVECTOR3(  N.x,  N.x,  N.x ), D3DXVECTOR2( 0.0f, 0.0f ),
                  D3DXVECTOR3( -2.0f,  2.0f,  2.0f ), D3DXVECTOR3( -N.x,  N.x,  N.x ), D3DXVECTOR2( 1.0f, 0.0f ),
                  D3DXVECTOR3(  2.0f, -2.0f,  2.0f ), D3DXVECTOR3(  N.x, -N.x,  N.x ), D3DXVECTOR2( 0.0f, 1.0f ),
                  D3DXVECTOR3( -2.0f, -2.0f,  2.0f ), D3DXVECTOR3( -N.x, -N.x,  N.x ), D3DXVECTOR2( 1.0f, 1.0f ),
   };

   // 頂点バッファを作成する
   hr = g_pD3D11User->CreateVertexBuffer( &g_pVertexBuffer, v, sizeof( v ), 0 );
   if( FAILED( hr ) ) goto EXIT;

   // 頂点インデックスを設定
   UINT Index[] = { 0, 2, 1,
                    1, 2, 3,
                    4, 6, 5,
                    5, 6, 7,
                    1, 3, 4,
                    4, 3, 6,
                    5, 7, 0,
                    0, 7, 2,
                    5, 0, 4,
                    4, 0, 1,
                    2, 7, 3,
                    3, 7, 6
   };

   // インデックスバッファを作成する。
   hr = g_pD3D11User->CreateIndexBuffer( &g_pIndexBuffer, Index, sizeof( Index ), 0 );
   if( FAILED( hr ) ) goto EXIT;

   // 頂点シェーダーを作成する

   D3D11_INPUT_ELEMENT_DESC layout[] = {
         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
         { "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT,    0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,       0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
   };

#ifndef UNCOMPILED_SHADER
   hr = g_pD3D11User->CreateVertexShaderFromMemory( &g_pVertexShader, g_VS_Main, sizeof( g_VS_Main ), &g_pLayout, layout, _countof( layout ) );
   if( FAILED( hr ) ) goto EXIT;
#else
   hr = g_pD3D11User->CreateVertexShaderFromFile( &g_pVertexShader, 
                                                  _T("../../USER/HLSL/SimpleHLSL09.hlsl"), "VS_Main", "vs_4_0",
                                                  &g_pLayout, layout, _countof( layout ) );
   if( FAILED( hr ) ) goto EXIT;
#endif

   // ジオメトリシェーダーを作成する
#ifndef UNCOMPILED_SHADER
   hr = g_pD3D11User->CreateGeometryShaderFromMemory( &g_pGeometryShader, g_GS_Main, sizeof( g_GS_Main ) );
   if( FAILED( hr ) ) goto EXIT;
#else
   hr = g_pD3D11User->CreateGeometryShaderFromFile( &g_pGeometryShader, _T("../../USER/HLSL/SimpleHLSL09.hlsl"), "GS_Main", "gs_4_0" );
   if( FAILED( hr ) ) goto EXIT;
#endif

   // ピクセルシェーダーを作成する
#ifndef UNCOMPILED_SHADER
   hr = g_pD3D11User->CreatePixelShaderFromMemory( &g_pPixelShader, g_PS_Main, sizeof( g_PS_Main ) );
   if( FAILED( hr ) ) goto EXIT;
#else
   hr = g_pD3D11User->CreatePixelShaderFromFile( &g_pPixelShader, _T("../../USER/HLSL/SimpleHLSL09.hlsl"), "PS_Main", "ps_4_0" );
   if( FAILED( hr ) ) goto EXIT;
#endif

   // 定数バッファを作成する。
   {
      hr = g_pD3D11User->CreateConstantBuffer( &g_pConstantBuffers[0], NULL, sizeof( D3DXMATRIX ), D3D11_CPU_ACCESS_WRITE );
      if( FAILED( hr ) ) goto EXIT;
   
      hr = g_pD3D11User->CreateConstantBuffer( &g_pConstantBuffers[1], NULL, sizeof( D3DXVECTOR4 ), D3D11_CPU_ACCESS_WRITE );
      if( FAILED( hr ) ) goto EXIT;
   }

   // ファイルからシェーダーリソースビューを作成する
   ::ZeroMemory( &info, sizeof( D3DX11_IMAGE_LOAD_INFO ) );
   info.Width = D3DX11_DEFAULT; 
   info.Height = D3DX11_DEFAULT; 
   info.Depth = D3DX11_DEFAULT; 
   info.FirstMipLevel = D3DX11_DEFAULT;
   info.MipLevels = 1;
   info.Usage = D3D11_USAGE_DEFAULT; 
   info.BindFlags = D3D11_BIND_SHADER_RESOURCE;
   info.CpuAccessFlags = 0;
   info.MiscFlags = 0;
   info.Format = DXGI_FORMAT_FROM_FILE;
   info.Filter = D3DX11_FILTER_POINT;
   info.MipFilter = D3DX11_FILTER_POINT;
   info.pSrcInfo = NULL;
   hr = D3DX11CreateShaderResourceViewFromFile( g_pD3D11User->m_D3DDevice, _T("res\\01.bmp"), &info, NULL, &g_pSRView, NULL );
   if( FAILED( hr ) ) goto EXIT;

   // サンプラーステートの設定
   D3D11_SAMPLER_DESC samplerDesc;
   samplerDesc.Filter = D3D11_FILTER_ANISOTROPIC;         // サンプリング時に使用するフィルタ。ここでは異方性フィルターを使用する。
   samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある u テクスチャー座標の描画方法
   samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある v テクスチャー座標の描画方法
   samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある w テクスチャー座標の描画方法
   samplerDesc.MipLODBias = 0;                            // 計算されたミップマップ レベルからのバイアス
   samplerDesc.MaxAnisotropy = 16;                        // サンプリングに異方性補間を使用している場合の限界値。有効な値は 1 〜 16 。
   samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;  // 比較オプション。
   ::CopyMemory( samplerDesc.BorderColor, &D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 0.0f ), sizeof( D3DXVECTOR4 ) ); // 境界色
   samplerDesc.MinLOD = 0;                                // アクセス可能なミップマップの下限値
   samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;                // アクセス可能なミップマップの上限値
   hr = g_pD3D11User->m_D3DDevice->CreateSamplerState( &samplerDesc, &g_pSamplerState );
   if( FAILED( hr ) ) goto EXIT;

   // 深度ステンシルステートを作成する
   D3D11_DEPTH_STENCIL_DESC ddsDesc;
   ::ZeroMemory( &ddsDesc, sizeof( ddsDesc ) );
   ddsDesc.DepthEnable = FALSE;                                     // 深度テストを無効にする
   ddsDesc.StencilEnable = FALSE;
   hr = g_pD3D11User->m_D3DDevice->CreateDepthStencilState( &ddsDesc, &g_pDepthStencilState );
   if( FAILED( hr ) ) goto EXIT;

   hr = S_OK;

EXIT:
   return hr;
}

// メモリ開放
void Invalidate()
{
   SAFE_RELEASE( g_pSRView );
   SAFE_RELEASE( g_pDepthStencilState );
   SAFE_RELEASE( g_pSamplerState );
   SAFE_RELEASE( g_pVertexShader );
   SAFE_RELEASE( g_pPixelShader );
   SAFE_RELEASE( g_pGeometryShader );
   for( int i=0; i<2; i++ ) SAFE_RELEASE( g_pConstantBuffers[i] );
   SAFE_RELEASE( g_pLayout );
   SAFE_RELEASE( g_pIndexBuffer );
   SAFE_RELEASE( g_pVertexBuffer );

   SAFE_DELETE( g_pDebugFontUser );
   SAFE_DELETE( g_pD3D11User );
}

// 描画処理
HRESULT Render()
{
   HRESULT hr = E_FAIL;

   D3DXMATRIX matWorld;
   D3D11_MAPPED_SUBRESOURCE mappedResource;

   // クリア処理
   {
      float ClearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
   
      // バックバッファをクリア
      g_pD3D11User->m_D3DDeviceContext->ClearRenderTargetView( g_pD3D11User->m_RenderTargetView, ClearColor ); 

      // 深度バッファをクリア
      if( g_pD3D11User->m_DepthStencilView )
         g_pD3D11User->m_D3DDeviceContext->ClearDepthStencilView( g_pD3D11User->m_DepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );
   }

   // 頂点関連のデータをデバイスコンテキストにセット
   {
      // 頂点バッファ設定
      UINT stride = sizeof( VERTEX );
      UINT offset = 0;
      g_pD3D11User->m_D3DDeviceContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );

      // インデックスバッファ設定
      g_pD3D11User->m_D3DDeviceContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );

      // 頂点レイアウト設定
      g_pD3D11User->m_D3DDeviceContext->IASetInputLayout( g_pLayout );
   }

   // プリミティブ タイプおよびデータの順序に関する情報を設定
   g_pD3D11User->m_D3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

   // シェーダーをデバイスにセット
   {
      // 頂点シェーダーをデバイスに設定する。
      g_pD3D11User->m_D3DDeviceContext->VSSetShader( g_pVertexShader, NULL, 0 );

      // ハルシェーダーを無効にする。
      g_pD3D11User->m_D3DDeviceContext->HSSetShader( NULL, NULL, 0 );

      // ドメインシェーダーを無効にする。
      g_pD3D11User->m_D3DDeviceContext->DSSetShader( NULL, NULL, 0 );

     // ジオメトリシェーダーをデバイスに設定する。
      g_pD3D11User->m_D3DDeviceContext->GSSetShader( g_pGeometryShader, NULL, 0 );

      // ピクセルシェーダーをデバイスに設定する。
      g_pD3D11User->m_D3DDeviceContext->PSSetShader( g_pPixelShader, NULL, 0 );
      g_pD3D11User->m_D3DDeviceContext->PSSetSamplers( 0, 1, &g_pSamplerState );

      // コンピュートシェーダーを無効にする。
      g_pD3D11User->m_D3DDeviceContext->CSSetShader( NULL, NULL, 0 );
   }

   // 深度テストを無効にする
   g_pD3D11User->m_D3DDeviceContext->OMSetDepthStencilState( g_pDepthStencilState, 0 );

   // アルファブレンディングを線形合成で設定
   D3D11_RENDER_TARGET_BLEND_DESC BlendDesc;
   BlendDesc = g_pD3D11User->GetAlignmentBlendDesc();
   g_pD3D11User->SetBlendState( &BlendDesc, 1, FALSE );

   // ジオメトリシェーダー
   {
      D3DXMATRIX matView, matProj, matWVP;
      D3DXMATRIX matScale, matX, matY, matTranslation;
      D3DXMATRIX* mat;

      // 射影行列
      D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4.0f, 4.0f / 3.0f, 1.0f, 250.0f );
      // ビュー行列
      D3DXMatrixLookAtLH( &matView,
                          &D3DXVECTOR3( 0.0f, 0.0f, -15.0f ),
                          &D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
                          &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );

      // ワールド行列
      D3DXMatrixScaling( &matScale, 1.0f, 1.0f, 1.0f );

     float x = 30.0f;
     D3DXMatrixRotationX( &matX, D3DXToRadian( x ) );
     
     static float r = 0.0f;
      r += 0.02f;
      D3DXMatrixRotationY( &matY, D3DXToRadian( r ) );
      D3DXMatrixTranslation( &matTranslation, 0.0f, 0.0f, 0.0f );
      matWorld = matScale * matX * matY * matTranslation;

      // 行列の合成
      matWVP = matWorld * matView * matProj;

      hr = g_pD3D11User->m_D3DDeviceContext->Map( g_pConstantBuffers[0], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource );
      if( FAILED( hr ) ) goto EXIT;
      mat = (D3DXMATRIX*)(mappedResource.pData);
      // シェーダー内では列優先にしているので転置行列を作成する。
      D3DXMatrixTranspose( mat, &matWVP );   
      g_pD3D11User->m_D3DDeviceContext->Unmap( g_pConstantBuffers[0], 0 );

      // ジオメトリシェーダーに定数バッファを設定する。
      g_pD3D11User->m_D3DDeviceContext->GSSetConstantBuffers( 0, 1, &g_pConstantBuffers[0] );
   }
   
   // ピクセルシェーダー
   {
      D3DXMATRIX matInv;
      D3DXVECTOR4 v;

      hr = g_pD3D11User->m_D3DDeviceContext->Map( g_pConstantBuffers[1], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource );
      if( FAILED( hr ) ) goto EXIT;
      D3DXVECTOR4* pVec = (D3DXVECTOR4*)(mappedResource.pData);

      // 逆行列
      // ワールド行列の逆行列を作成
      D3DXMatrixInverse( &matInv, NULL, &matWorld );
      D3DXVec4Transform( &v, &g_vecLight, &matInv );
      D3DXVec3Normalize( (D3DXVECTOR3*)&v, (D3DXVECTOR3*)&v );
      ::CopyMemory( pVec, &v, sizeof( D3DXVECTOR4 ) );
      g_pD3D11User->m_D3DDeviceContext->Unmap( g_pConstantBuffers[1], 0 );

      // ピクセルシェーダーに定数バッファを設定する。
      g_pD3D11User->m_D3DDeviceContext->PSSetConstantBuffers( 1, 1, &g_pConstantBuffers[1] );

     // テクスチャーを設定する
      g_pD3D11User->m_D3DDeviceContext->PSSetShaderResources( 0, 1, &g_pSRView );
   }

   // インデックスバッファを使用した描画
   g_pD3D11User->m_D3DDeviceContext->DrawIndexed( 36, 0, 0 );

   if( g_pDebugFontUser )
   {
      // デバッグ専用フォント描画
      g_pDebugFontUser->RenderFPS( g_pD3D11User->m_D3DDeviceContext, 0, 0 );
   }

   // レンダリングされたイメージを表示。
   hr = g_pD3D11User->m_SwapChain->Present( 0, 0 );

   if( ScreenShot )
   {
      // スクリーンショット作成
      g_pD3D11User->CreateScreenShot();
      ScreenShot = false;
   }

EXIT:
   return hr;
}

// 節電処理および描画処理
HRESULT PowerSavingAndRender()
{
   HRESULT hr = E_FAIL;

   switch( StandBy )
   {
   // スタンバイモード
   case  true:
      // テストのみ行い、描画処理は行わない。
      hr = g_pD3D11User->m_SwapChain->Present( 0, DXGI_PRESENT_TEST );
      switch( hr )
      {
      // いまだスタンバイ中。。。
      case DXGI_STATUS_OCCLUDED:
         // 電源管理によるスリープ状態の場合ここにくる。
         // フルスクリーンモード時にスクリーンセーバーが起動時した場合は、表示モードが強制的にウィンドウモードに変更されるためここにこない。
         goto EXIT;
         break;
      case S_OK:
         // フルスクリーンモード時にスクリーンセーバーが起動時した場合は表示モードが強制的にウィンドウモードに変更される。
         // ウィンドウモードの場合スタンバイから復帰してしまうため、ウィンドウがアクティブになったときに復帰するようにする。
         if( Activate == true )
         {
            // たまにウィンドウが表示されないときがあるので表示するようにする
            ::ShowWindow( g_pD3D11User->m_hWnd, SW_SHOW );
            StandBy = false;
         }
         break;
      default:
         goto EXIT;
         break;
      }
      break;
   // スタンバイモードでない
   case false:
      // 描画処理
      hr = Render();
      if( FAILED( hr ) ) goto EXIT;

      switch( hr )
      {
      case DXGI_STATUS_OCCLUDED:
         // スタンバイモードへ移行
         // フルスクリーンモード時のスクリーンセーバー起動時、
         // スリープ状態に移行した時に発生する。
         StandBy = true;
         goto EXIT;
         break;
      case S_OK:
         break;
      default:
         goto EXIT;
         break;
      }
      break;
   }

   hr = S_OK;

EXIT:

   return hr;
}

// ウィンドウプロシージャ
LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, UINT wParam, LONG lParam )
{
   switch( msg )
   {
   case WM_KEYUP:
      // アプリ終了
      if( wParam == VK_ESCAPE )
         ::DestroyWindow( hWnd );

      // F2キーを押すと、ウィンドウモードを切り替える。
      // 自動的にウィンドウモードを切り替える機能もあるが、ウィンドウスタイルを自由に変更するために自分で実装することにした。
      if( wParam == VK_F2 )
      {
         g_pD3D11User->ChangeWindowMode();
      }
      // スクリーンショットを作成する
      if( wParam == VK_SNAPSHOT )
         ScreenShot = true;
      break;

   case WM_ACTIVATE:
      Activate = true;
      break;

   case WM_DESTROY:
      Invalidate();
      ::PostQuitMessage(0);
      break;

   default:
      return ::DefWindowProc( hWnd, msg, wParam, lParam );
   }

   return 0L;
}

// メイン関数
int APIENTRY _tWinMain( HINSTANCE hInstance,
                        HINSTANCE /*hPrevInstance*/,
                        LPTSTR    /*lpCmpLine*/,
                        INT       /*nCmdShow*/ )
{
   // メモリリーク検出
   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_EVERY_1024_DF);

   HRESULT hr = E_FAIL;
   MSG msg;
   ::ZeroMemory(&msg, sizeof(MSG));

   // 表示モードを記述するための構造体。
   DXGI_MODE_DESC sd;

   // Direct3D 関連自作クラスのインスタンスを作成
   g_pD3D11User = new D3D11USER();

   // ディスプレイモード一覧を取得する。
   // 取得した値はクラス内部に保持される。
   hr = g_pD3D11User->GetDisplayMode();
   if( FAILED( hr ) )
   {
      ::MessageBox( NULL, _T("ディスプレイモード取得エラー"), _T("初期化エラー"), MB_OK );
      goto EXIT;
   }
   // とりあえず最初に見つかったディスプレイモードを選択する
   CopyMemory( &sd, &g_pD3D11User->m_DisplayModeDesc[0], sizeof( DXGI_MODE_DESC ) );

   // ウィンドウの作成およびDirect3D の初期化
   hr = g_pD3D11User->InitD3D11( AppName, hInstance, WndProc, &sd, TRUE, TRUE, TRUE, TRUE );
   if( FAILED( hr ) )
   {
      ::MessageBox( NULL, _T("Direct3D 11.0 初期化エラー"), _T("初期化エラー"), MB_OK );
      goto EXIT;
   }

   // デバッグ専用フォント出力クラスの作成処理
   // デバックコンパイル時のみ使用する
#if defined(DEBUG) || defined(_DEBUG)
   g_pDebugFontUser = new CDebugFont();
   hr = g_pDebugFontUser->Create( g_pD3D11User->m_D3DDevice, 0.015f, 0.05f );
   if( FAILED( hr ) )
   {
      ::MessageBox( NULL, _T("デバックフォントクラス初期化エラー"), _T("初期化エラー"), MB_OK );
      goto EXIT;
   }
#endif

   // リソースの初期化
   hr = Init();
   if( FAILED( hr ) )
   {
      ::MessageBox( NULL, _T("リソース初期化エラー"), _T("初期化エラー"), MB_OK );
      goto EXIT;
   }

   ::ShowWindow(g_pD3D11User->m_hWnd, SW_SHOW);
   ::UpdateWindow(g_pD3D11User->m_hWnd);

   // メッセージループ
   do
   { 
      if( ::PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
      {
         ::TranslateMessage(&msg); 
         ::DispatchMessage(&msg); 
      }
      else
      {
         hr = PowerSavingAndRender();
         if( FAILED( hr ) )
            ::DestroyWindow( g_pD3D11User->m_hWnd );
      }
   }while( msg.message != WM_QUIT );

EXIT:
   if( g_pD3D11User && g_pD3D11User->m_hWnd )
      ::DestroyWindow( g_pD3D11User->m_hWnd );

   ::UnregisterClass( AppName, hInstance );

   return msg.wParam;

}

特に説明するようなことはありません。


web拍手 by FC2

Prev Top Next

inserted by FC2 system