Microsoft Visual 2017 Community C++
 Direct3D 11.0( SM 5.0 )
 DirectXTex texture processing library
 XMLLite
 DirectXMath

■Direct3D11 Reflective Shadow Maps Prev Top Next
関連ページ:Direct3D11 自作ライブラリ


ひさしぶりの更新です。Playstation Mobileはなかったことにして、前回の Percentage-Closer Soft Shadows の更新が2013/12/23だったので1年半ぶりとなります。
今回のネタは日本語解説されているサイトも多数あり、技術的にも古いので当サイトを参考にする価値はほとんどないです。
が、自分自身がぶっちゃけShader忘れてるので(笑)リハビリかねて簡単なネタやることにします。
今更ここで解説するようなことはなにもないのでそこは省略させていただきます。あ一応論文のURLはアップします。pdfです。
なお品質についてはつっこまないように!!

それとこっそり既存のソースを結構修正してます。もし当サイトをすでに参考にされている方がいらっしゃるようでしたら、お手数ですが Direct3D11 自作ライブラリを参照してソースの差し替えを行ってください。
今後も予告なしで過去ソースの更新を行う可能性がありますがご了承ください。


@Direct3D 自作の共通ライブラリ一式をここを参照して作成してください。

Aシェーダー系で使用するソースです。
ReflectiveShadowMaps_Pass0.hlsl ライトビューでHigh解像度の深度マップ作成するシェーダーソース
ReflectiveShadowMaps_Pass1.hlsl ライトビューでLow解像度の深度マップ、座標マップ、法線マップ、放射マップを作成するシェーダーソース
ReflectiveShadowMaps_Pass2.hlsl 最終レンダリングするシェーダーソース
ReflectiveShadowMaps.h ReflectiveShadowMapsクラスのヘッダーファイル
ReflectiveShadowMaps.cpp ReflectiveShadowMapsクラスのソースファイル

B個別に使用するソースです。
BackGroundMesh.h 地面メッシュクラスのヘッダーファイル
BackGroundMesh.cpp 地面メッシュクラスのソースファイル
main.cpp main関数のソースファイル


---ReflectiveShadowMaps_Pass0.hlsl---  ↑

// ************************************************************
// Reflective Shadow Maps Pass0
// Hight解像度のdepth マップ作成
// ************************************************************

// 定数バッファ
cbuffer cbBuffer0 : register( b0 )
{
   column_major float4x4 g_matLightWorldViewProj   : packoffset( c0 );   // ライトビューでのワールドとビューと射影行列
};

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

struct VS_OUT_PS_IN
{
   float4 pos      : SV_POSITION;
};

// 頂点シェーダー
VS_OUT_PS_IN ReflectiveShadowMaps_Pass0_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out;

   Out.pos = mul( float4( In.pos, 1.0f ), g_matLightWorldViewProj );
   
   return Out;
}

---ReflectiveShadowMaps_Pass1.hlsl---  ↑


// ************************************************************
// Reflective Shadow Maps Pass1
// depth, world space coordinates, normal, flux マップ作成
// ************************************************************

// 定数バッファ
cbuffer cbBuffer0 : register( b0 )
{
   column_major float4x4 g_matLightWorldViewProj   : packoffset( c0 );   // ライトビューでのワールドとビューと射影行列
   column_major float4x4 g_matLightWorldView   : packoffset( c4 );   // ライトビューでのワールドとビュー行列
};

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

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

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

struct VS_OUT_PS_IN
{
   float4 pos      : SV_POSITION;
   float3 normal   : NORMAL;
   float4 posLightWorldViewProj    : TEXCOORD1;
   float2 texel    : TEXCOORD2;
};

struct PS_OUT
{
   float3 worldSpaceCoordinatesMap : SV_TARGET0;
   float3 worldSpaceNormalMap : SV_TARGET1;
   float4 worldSpaceFluxMap : SV_TARGET2;
};

// 頂点シェーダー
VS_OUT_PS_IN ReflectiveShadowMaps_Pass1_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out;

   Out.pos = mul( float4( In.pos, 1.0f ), g_matLightWorldViewProj );
   Out.posLightWorldViewProj = Out.pos;
   Out.normal = mul( In.normal, (float3x3)g_matLightWorldView );
   Out.texel = In.texel;

   return Out;
}

PS_OUT ReflectiveShadowMaps_Pass1_PS_Main( VS_OUT_PS_IN In )
{
   PS_OUT Out = (PS_OUT)0;

   // ワールド座標系の座標
   // 単位が大きすぎると反射しないので適当にスケーリングする
   Out.worldSpaceCoordinatesMap = In.posLightWorldViewProj.xyz * 0.02f;
   // ワールド座標系の法線ベクトル
   // DXGI_FORMAT_R11G11B10_FLOAT を使用するため
   Out.worldSpaceNormalMap = In.normal * 0.5f + 0.5f;
   // ワールド座標系のカラーマップ( 光束 )
   Out.worldSpaceFluxMap = g_DecalMap.Sample( g_Sampler, In.texel ).bgra;

   return Out;
}

---ReflectiveShadowMaps_Pass2.hlsl---  ↑


// ************************************************************
// Reflective Shadow Maps Pass2
// 最終レンダリング( 反射マップと影のレンダリング )
// ************************************************************

// 定数バッファ
cbuffer cbBuffer0 : register( b0 )
{
   column_major float4x4 g_matLightWorldViewProj   : packoffset( c0 );   // ライトビューでのワールドとビューと射影行列
   column_major float4x4 g_matCameraWorldViewProj   : packoffset( c4 );   // カメラビューでのワールドとビューと射影行列
   float4 g_vecLightPos         : packoffset( c8 );    // ローカル座標系での平行光源の位置ベクトル
   float4 g_offsetXArray[20]         : packoffset( c9 );
   float4 g_offsetYArray[20]         : packoffset( c29 );
};

// テクスチャー
Texture2D g_DecalMap : register( t0 );
Texture2D g_worldSpaceDepthMap : register( t1 );
Texture2D g_worldSpaceCoordinatesMap : register( t2 );
Texture2D g_worldSpaceNormalMap : register( t3 );
Texture2D g_worldSpaceFluxMap : register( t4 );

// サンプラーステート
SamplerState g_Sampler;

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

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

VS_OUT_PS_IN ReflectiveShadowMaps_Pass2_VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out;

   Out.pos = mul( float4( In.pos, 1.0f ), g_matCameraWorldViewProj );
   Out.posLightWorldViewProj = mul( float4( In.pos, 1.0f ), g_matLightWorldViewProj );
   Out.normal = In.normal;
   Out.texel = In.texel;

   return Out;
}

float4 ReflectiveShadowMaps_Pass2_PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   float shadowColor;
   float3 reflectiveColor;
   
   // テクセルを計算
   float2 texel = In.posLightWorldViewProj.xy / In.posLightWorldViewProj.w * float2( 0.5f, -0.5f ) + 0.5f;
   
   // ライトビューでの深度マップ
   float worldSpaceDepthOfCenter = g_worldSpaceDepthMap.Sample( g_Sampler, texel ).x;

   // ライトビューでの位置マップ
   float3 worldSpaceCoordinatesOfCenter = g_worldSpaceCoordinatesMap.Sample( g_Sampler, texel ).xyz;

   // ライトビューでの法線マップ
   float3 worldSpaceNormalOfCenter = ( g_worldSpaceNormalMap.Sample( g_Sampler, texel ).xyz - 0.5f ) * 2.0f;

   reflectiveColor = 0.0f;
      
   [unroll(20)]
   for( int i=0; i<20; i++ )
   {
      for( int j=0; j<4; j++ )
      {
         float2 t = texel + float2( g_offsetXArray[i][j], g_offsetYArray[i][j] );
      
         // ライトビューでの位置マップ
         float3 worldSpaceCoordinates = g_worldSpaceCoordinatesMap.Sample( g_Sampler, t ).xyz;

         // ライトビューでの法線マップ
         float3 worldSpaceNormal = ( g_worldSpaceNormalMap.Sample( g_Sampler, t ).xyz - 0.5f ) * 2.0f;

         // ライトビューでのカラーマップ
         float3 worldSpaceFlux = g_worldSpaceFluxMap.Sample( g_Sampler, t ).rgb;

         float d = distance( worldSpaceCoordinates, worldSpaceCoordinatesOfCenter );
      
         // Ep(x,n)
         float3 rc = worldSpaceFlux * 
                     max( 0, dot( worldSpaceNormalOfCenter, normalize( worldSpaceCoordinates - worldSpaceCoordinatesOfCenter ) ) ) *
                     max( 0, dot( worldSpaceNormal, normalize( worldSpaceCoordinatesOfCenter - worldSpaceCoordinates ) ) ) /
//                      pow( d, 4.0f );
                         pow( d, 2.0f );

         // E(x,n)
         reflectiveColor += rc;
      }
   }

   // 現在の深度値と深度マップ上の深度値を比較
   if( worldSpaceDepthOfCenter < In.posLightWorldViewProj.z / In.posLightWorldViewProj.w - 0.0008f )
      shadowColor = 0.3f;
   else
      shadowColor = 1.0f;

   // ハーフランバート
   float lambert = dot( normalize(g_vecLightPos.xyz), In.normal );
   lambert = lambert * 0.5f + 0.5f;

   // デカールマップ
   float4 decalmap = g_DecalMap.Sample( g_Sampler, In.texel ).bgra;

   return min( 1.0f, ( decalmap + float4( reflectiveColor, 1 ) ) * lambert ) * shadowColor;
//   return float4( reflectiveColor, 1 );
}

一部論文の計算式を変更しています。

---ReflectiveShadowMaps.h---  ↑


#ifndef REFLECTIVE_SHADOW_MAPS_H
#define REFLECTIVE_SHADOW_MAPS_H

#include "../Common/UCommon.h"
#include "../Common/UException.h"
#include "../Common/UGraphicsPipeline.h"
#include "../Common/UDirect3D11.h"

class ReflectiveShadowMaps
{
private:
   static const int SAMPLEPOINT_COUNT = 80;

   // パス0用行列
   typedef struct _CBUFFER_PASS0
   {
      // ライトビューでのワールドとビューと射影行列
      XMMATRIX matLightWorldViewProj;
   }CBUFFER_PASS0;

   // パス1用行列
   typedef struct _CBUFFER_PASS1
   {
      // ライトビューでのワールドとビューと射影行列
      XMMATRIX matLightWorldViewProj;
      // ライトビューでのワールドとビュー
      XMMATRIX matLightWorldView;
   }CBUFFER_PASS1;

   // パス2用行列
   typedef struct _CBUFFER_PASS2
   {
      // ライトビューでのワールドとビューと射影行列
      XMMATRIX matLightWorldViewProj;
      // カメラビューでのワールドとビューと射影行列
      XMMATRIX matCameraWorldViewProj;
      // 平行光源の方向ベクトル
      XMFLOAT4 vecLightPos;
      float offsetXArray[SAMPLEPOINT_COUNT];
      float offsetYArray[SAMPLEPOINT_COUNT];
   }CBUFFER_PASS2;

   ID3D11RenderTargetView* m_pRTViewMaps[3];
   ID3D11ShaderResourceView* m_pSRViewMaps[4];
   ID3D11DepthStencilView* m_pDSView[2];

   // レンダーターゲットと深度ステンシルとビューポートのバックアップ
   ID3D11RenderTargetView* m_pOldRTView;
   ID3D11DepthStencilView* m_pOldDSView;
   D3D11_VIEWPORT m_pOldViewport[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
   UINT m_ViewportCount;

   // シェーダー用定数バッファ
   ID3D11Buffer* m_pConstantBuffers[3];

   UGraphicsPipeline* m_pGraphicsPipeline[3];

   ID3D11SamplerState* m_pSamplerState;

   XMFLOAT2 m_DepthMapSize, m_WorldPosNormalFluxMapSize;

   int m_Pass;

   XMFLOAT4 m_VecLightPos;

   XMMATRIX m_MatLightView;
   XMMATRIX m_MatLightProj;
   XMMATRIX m_MatCameraView;
   XMMATRIX m_MatCameraProj;

   float m_offsetXArray[SAMPLEPOINT_COUNT];
   float m_offsetYArray[SAMPLEPOINT_COUNT];

public:
   ReflectiveShadowMaps();
   virtual ~ReflectiveShadowMaps();
   void Invalidate();
   void Create(ID3D11Device* pD3DDevice, XMFLOAT2* pDepthMapSize, XMFLOAT2* pWorldPosNormalFluxMapSize );
   void Begin(XMFLOAT4* pVecLightPos, XMMATRIX* pMatLightProj, XMMATRIX* pMatCameraView, XMMATRIX* pMatCameraProj);
   void BeginPass(ID3D11DeviceContext* pD3DDeviceContext, UINT Pass );
   void SetConstantBuffers(ID3D11DeviceContext* pD3DDeviceContext, XMMATRIX* pMatWorld);
   void EndPass(ID3D11DeviceContext* pD3DDeviceContext);
   void End();
   inline UINT GetMaxPass(){ return _countof(m_pGraphicsPipeline); };
   inline const ID3D11ShaderResourceView* GetDepthMap(){ return m_pSRViewMaps[0]; };
   inline const ID3D11ShaderResourceView* GetWorldPositionMap(){ return m_pSRViewMaps[1]; };
   inline const ID3D11ShaderResourceView* GetWorldNormalMap(){ return m_pSRViewMaps[2]; };
   inline const ID3D11ShaderResourceView* GetWorldFluxMap(){ return m_pSRViewMaps[3]; };
};

#endif

---ReflectiveShadowMaps.cpp---  ↑


#include "../../Header/Shader/ReflectiveShadowMaps.h"
#include "../../HLSL/ReflectiveShadowMaps_Pass0_VS_Main.h"
#include "../../HLSL/ReflectiveShadowMaps_Pass1_VS_Main.h"
#include "../../HLSL/ReflectiveShadowMaps_Pass1_PS_Main.h"
#include "../../HLSL/ReflectiveShadowMaps_Pass2_VS_Main.h"
#include "../../HLSL/ReflectiveShadowMaps_Pass2_PS_Main.h"

ReflectiveShadowMaps::ReflectiveShadowMaps()
{
   for(UINT i=0; i<_countof(m_pRTViewMaps); i++)
   {
      m_pRTViewMaps[i] = nullptr;
   }
   for(UINT i=0; i<_countof(m_pSRViewMaps); i++)
   {
      m_pSRViewMaps[i] = nullptr;
   }
   for(UINT i=0; i<_countof(m_pDSView); i++)
   {
      m_pDSView[i] = nullptr;
   }
   for(UINT i=0; i<_countof(m_pConstantBuffers); i++)
   {
      m_pConstantBuffers[i] = nullptr;
   }
   for(UINT i=0; i<_countof(m_pGraphicsPipeline); i++)
   {
      m_pGraphicsPipeline[i] = nullptr;
   }
   m_pSamplerState = nullptr;

   m_Pass = -2;
}

ReflectiveShadowMaps::~ReflectiveShadowMaps()
{
   SAFE_RELEASE(m_pSamplerState);
   for(UINT i=0; i<_countof(m_pGraphicsPipeline); i++)
   {
      SAFE_DELETE(m_pGraphicsPipeline[i]);
   }
   for(UINT i=0; i<_countof(m_pConstantBuffers); i++)
   {
      SAFE_RELEASE(m_pConstantBuffers[i]);
   }
   for(UINT i=0; i<_countof(m_pDSView); i++)
   {
      SAFE_RELEASE(m_pDSView[i]);
   }
   for(UINT i=0; i<_countof(m_pSRViewMaps); i++)
   {
      SAFE_RELEASE(m_pSRViewMaps[i]);
   }
   for(UINT i=0; i<_countof(m_pRTViewMaps); i++)
   {
      SAFE_RELEASE( m_pRTViewMaps[i]);
   }
}

void ReflectiveShadowMaps::Create(ID3D11Device* pD3DDevice, XMFLOAT2* pDepthMapSize, XMFLOAT2* pWorldPosNormalFluxMapSize)
{
   m_DepthMapSize = *pDepthMapSize;
   m_WorldPosNormalFluxMapSize = *pWorldPosNormalFluxMapSize;

   m_Pass = -2;

   for (UINT i=0; i<_countof(m_pGraphicsPipeline); i++)
   {
      m_pGraphicsPipeline[i] = NEW UGraphicsPipeline();
   }

   // ラスタライザーステートを作成する
   m_pGraphicsPipeline[0]->CreateRasterizerState(pD3DDevice, D3D11_CULL_MODE::D3D11_CULL_BACK);

   // 深度ステンシルステートを有効にする
   m_pGraphicsPipeline[0]->CreateDepthStencilState(pD3DDevice, TRUE, D3D11_DEPTH_WRITE_MASK::D3D11_DEPTH_WRITE_MASK_ALL);

   // ブレンドステートを作成する
   UGraphicsPipeline::UEBLEND_STATE BlendStateType[1] = { UGraphicsPipeline::UEBLEND_STATE::NONE };
   m_pGraphicsPipeline[0]->CreateBlendState(pD3DDevice, BlendStateType, 1);

   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 },
   };

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   m_pGraphicsPipeline[0]->CreateVertexShaderFromFile(pD3DDevice, _T("../HLSL/ReflectiveShadowMaps_Pass0.hlsl"), "ReflectiveShadowMaps_Pass0_VS_Main", layout, _countof(layout));
   m_pGraphicsPipeline[1]->CreateVertexShaderFromFile(pD3DDevice, _T("../HLSL/ReflectiveShadowMaps_Pass1.hlsl"), "ReflectiveShadowMaps_Pass1_VS_Main", layout, _countof(layout));
   m_pGraphicsPipeline[1]->CreatePixelShaderFromFile(pD3DDevice, _T("../HLSL/ReflectiveShadowMaps_Pass1.hlsl"), "ReflectiveShadowMaps_Pass1_PS_Main");
   m_pGraphicsPipeline[2]->CreateVertexShaderFromFile(pD3DDevice, _T("../HLSL/ReflectiveShadowMaps_Pass2.hlsl"), "ReflectiveShadowMaps_Pass2_VS_Main", layout, _countof(layout));
   m_pGraphicsPipeline[2]->CreatePixelShaderFromFile(pD3DDevice, _T("../HLSL/ReflectiveShadowMaps_Pass2.hlsl"), "ReflectiveShadowMaps_Pass2_PS_Main");
#else
   m_pGraphicsPipeline[0]->CreateVertexShaderFromMemory(pD3DDevice, (LPBYTE)g_ReflectiveShadowMaps_Pass0_VS_Main, sizeof(g_ReflectiveShadowMaps_Pass0_VS_Main), layout, _countof(layout));
   m_pGraphicsPipeline[1]->CreateVertexShaderFromMemory(pD3DDevice, (LPBYTE)g_ReflectiveShadowMaps_Pass1_VS_Main, sizeof(g_ReflectiveShadowMaps_Pass1_VS_Main), layout, _countof(layout));
   m_pGraphicsPipeline[1]->CreatePixelShaderFromMemory(pD3DDevice, (LPBYTE)g_ReflectiveShadowMaps_Pass1_PS_Main, sizeof(g_ReflectiveShadowMaps_Pass1_PS_Main));
   m_pGraphicsPipeline[2]->CreateVertexShaderFromMemory(pD3DDevice, (LPBYTE)g_ReflectiveShadowMaps_Pass2_VS_Main, sizeof(g_ReflectiveShadowMaps_Pass2_VS_Main), layout, _countof(layout));
   m_pGraphicsPipeline[2]->CreatePixelShaderFromMemory(pD3DDevice, (LPBYTE)g_ReflectiveShadowMaps_Pass2_PS_Main, sizeof(g_ReflectiveShadowMaps_Pass2_PS_Main));
#endif

   // High解像度のdepthMap
   UMaps::CreateDepthStencilView(pD3DDevice, (UINT)m_DepthMapSize.x, (UINT)m_DepthMapSize.y, &m_pDSView[0], &m_pSRViewMaps[0]);

   // レンダーターゲットビューを作成する
   // Low解像度のdepthMap
   UMaps::CreateDepthStencilView(pD3DDevice, (UINT)m_WorldPosNormalFluxMapSize.x, (UINT)m_WorldPosNormalFluxMapSize.y, &m_pDSView[1], nullptr);
   // worldSpaceCoordinatesMap
   UMaps::CreateRenderTargetView(pD3DDevice, DXGI_FORMAT_R16G16B16A16_FLOAT, (UINT)m_WorldPosNormalFluxMapSize.x, (UINT)m_WorldPosNormalFluxMapSize.y, &m_pRTViewMaps[0], &m_pSRViewMaps[1]);
   // worldSpaceNormalMap
   UMaps::CreateRenderTargetView(pD3DDevice, DXGI_FORMAT_R11G11B10_FLOAT, (UINT)m_WorldPosNormalFluxMapSize.x, (UINT)m_WorldPosNormalFluxMapSize.y, &m_pRTViewMaps[1], &m_pSRViewMaps[2]);
   // worldSpaceFluxMap
   UMaps::CreateRenderTargetView(pD3DDevice, DXGI_FORMAT_B8G8R8X8_UNORM, (UINT)m_WorldPosNormalFluxMapSize.x, (UINT)m_WorldPosNormalFluxMapSize.y, &m_pRTViewMaps[2], &m_pSRViewMaps[3]);

   // 定数バッファを作成する
   m_pConstantBuffers[0] = m_pGraphicsPipeline[0]->CreateConstantBuffer(pD3DDevice, nullptr, sizeof(ReflectiveShadowMaps::CBUFFER_PASS0), D3D11_CPU_ACCESS_WRITE);
   m_pConstantBuffers[1] = m_pGraphicsPipeline[1]->CreateConstantBuffer(pD3DDevice, nullptr, sizeof(ReflectiveShadowMaps::CBUFFER_PASS1), D3D11_CPU_ACCESS_WRITE);
   m_pConstantBuffers[2] = m_pGraphicsPipeline[1]->CreateConstantBuffer(pD3DDevice, nullptr, sizeof(ReflectiveShadowMaps::CBUFFER_PASS2), D3D11_CPU_ACCESS_WRITE);

   // サンプラーステートを作成する
   m_pSamplerState = USamplers::CreateSamplerState(pD3DDevice, D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT);

   // 各種マップのサンプリング位置を計算
   // なおマップの縦横のサイズは同じ前提
   float offset = 1.0f / m_WorldPosNormalFluxMapSize.x * 2.0f;
   float radius = offset;
   float angle;
   UINT max = SAMPLEPOINT_COUNT - 4;
   for (UINT i=0; i<= max; i+=4)
   {
      if (radius > 1.0f)
      {
         throw(UException(-1, _T("ReflectiveShadowMaps::Create()でoffset値が不正です")));
      }

      angle = (float)(rand() % 90) / 90.0f * XM_PIDIV4;
      m_offsetXArray[i + 0] = cosf(angle) * radius;
      m_offsetYArray[i + 0] = sinf(angle) * radius;

      angle = (float)(rand() % 90) / 90.0f * XM_PIDIV4 + XM_PIDIV4;
      m_offsetXArray[i + 1] = cosf(angle) * radius;
      m_offsetYArray[i + 1] = sinf(angle) * radius;

      angle = (float)(rand() % 90) / 90.0f * XM_PIDIV4 + XM_PI;
      m_offsetXArray[i + 2] = cosf(angle) * radius;
      m_offsetYArray[i + 2] = sinf(angle) * radius;

      angle = (float)(rand() % 90) / 90.0f * XM_PIDIV4 + XM_PI * 1.5f;
      m_offsetXArray[i + 3] = cosf(angle) * radius;
      m_offsetYArray[i + 3] = sinf(angle) * radius;

      offset *= 1.08f;
      radius += offset;
   }
}

void ReflectiveShadowMaps::Begin(XMFLOAT4* pVecLightPos, XMMATRIX* pMatLightProj, XMMATRIX* pMatCameraView, XMMATRIX* pMatCameraProj)
{
   if (m_Pass != -2)
   {
      throw(UException(-1, _T("ReflectiveShadowMaps::Begin()はCreate()またはEnd()実行後に使用してください")));
   }

   m_VecLightPos = *pVecLightPos;

   m_MatLightView = XMMatrixLookAtLH(XMLoadFloat3((XMFLOAT3*)&m_VecLightPos), XMLoadFloat3(&XMFLOAT3(0, 0, 0)), XMLoadFloat3(&XMFLOAT3(0, 1, 0)));
   m_MatLightProj = *pMatLightProj;
   m_MatCameraView = *pMatCameraView;
   m_MatCameraProj = *pMatCameraProj;

   m_Pass = -1;
}

void ReflectiveShadowMaps::BeginPass(ID3D11DeviceContext* pD3DDeviceContext, UINT Pass)
{
   if (m_Pass != -1)
   {
      throw(UException(-1, _T("ReflectiveShadowMaps::BeginPass()はBegin()またはEndPass()実行後に使用してください")));
   }

   m_Pass = (int)Pass;

   switch (m_Pass)
   {
   // High解像度のdepthMapの書込み
   case 0:
      {
         // レンダーターゲットを退避
         pD3DDeviceContext->OMGetRenderTargets(1, &m_pOldRTView, &m_pOldDSView);
         // レンダーターゲットを切り替え
         pD3DDeviceContext->OMSetRenderTargets(0, nullptr, m_pDSView[0]);

         // ビューポートの退避
         pD3DDeviceContext->RSGetViewports(&m_ViewportCount, nullptr);
         pD3DDeviceContext->RSGetViewports(&m_ViewportCount, &m_pOldViewport[0]);

         // ビューポートの切り替え
         D3D11_VIEWPORT Viewport[1];
         Viewport[0].TopLeftX = 0;
         Viewport[0].TopLeftY = 0;
         Viewport[0].Width = m_DepthMapSize.x;
         Viewport[0].Height = m_DepthMapSize.y;
         Viewport[0].MinDepth = 0.0f;
         Viewport[0].MaxDepth = 1.0f;
         pD3DDeviceContext->RSSetViewports(1, Viewport);

         // 深度バッファをクリアする。
         pD3DDeviceContext->ClearDepthStencilView(m_pDSView[0], D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

         // ピクセルシェーダーのサンプラーステートを設定する
         pD3DDeviceContext->PSSetSamplers(0, 1, &m_pSamplerState);
      }
      break;
   // Low解像度のdepthMapとworldSpaceCoordinatesMapとworldSpaceNormalMapとworldSpaceFluxMapの出力
   case 1:
      {
         // レンダーターゲットを切り替え
         pD3DDeviceContext->OMSetRenderTargets(3, m_pRTViewMaps, m_pDSView[1]);

         // ビューポートの切り替え
         D3D11_VIEWPORT Viewport[1];
         Viewport[0].TopLeftX = 0;
         Viewport[0].TopLeftY = 0;
         Viewport[0].Width = m_WorldPosNormalFluxMapSize.x;
         Viewport[0].Height = m_WorldPosNormalFluxMapSize.y;
         Viewport[0].MinDepth = 0.0f;
         Viewport[0].MaxDepth = 1.0f;
         pD3DDeviceContext->RSSetViewports(1, Viewport);

         float ClearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };

         // バックバッファをクリアする。
         for( int i=0; i<_countof(m_pRTViewMaps); i++)
         {
            pD3DDeviceContext->ClearRenderTargetView(m_pRTViewMaps[i], ClearColor);
         }

         // 深度バッファをクリアする。
         pD3DDeviceContext->ClearDepthStencilView(m_pDSView[1], D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
      }
      break;
   // 最終レンダリング
   case 2:
      {
         pD3DDeviceContext->PSSetShaderResources(1, _countof(m_pSRViewMaps), m_pSRViewMaps);
      }
      break;
   default:
      throw(UException(-1, _T("ReflectiveShadowMaps::BeginPass()で無効なPassが指定されました")));
   }

   // 各種ステートを設定する
   m_pGraphicsPipeline[0]->SetRasterizerState(pD3DDeviceContext);
   m_pGraphicsPipeline[0]->SetDepthStencilState(pD3DDeviceContext);
   m_pGraphicsPipeline[0]->SetBlendState(pD3DDeviceContext);

   // 各種グラフィックパイプラインを設定
   m_pGraphicsPipeline[m_Pass]->SetVertexShader(pD3DDeviceContext);
   m_pGraphicsPipeline[m_Pass]->SetHullShader(pD3DDeviceContext);
   m_pGraphicsPipeline[m_Pass]->SetDomainShader(pD3DDeviceContext);
   m_pGraphicsPipeline[m_Pass]->SetGeometryShader(pD3DDeviceContext);
   m_pGraphicsPipeline[m_Pass]->SetPixelShader(pD3DDeviceContext);
}

void ReflectiveShadowMaps::SetConstantBuffers(ID3D11DeviceContext* pD3DDeviceContext, XMMATRIX* pMatWorld)
{
   HRESULT hr = E_FAIL;

   if (m_Pass == -1)
   {
      throw(UException(-1, _T("ReflectiveShadowMaps::SetConstantBuffers()はBeginPass()実行に使用してください")));
   }

   switch (m_Pass)
   {
   case 0:
      {
         XMMATRIX matLightWorldViewProj = XMMatrixTranspose(*pMatWorld * m_MatLightView * m_MatLightProj);

         // 定数バッファを作成する
         D3D11_MAPPED_SUBRESOURCE mappedResource;
         if (FAILED(hr = pD3DDeviceContext->Map(m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)))
            throw(UException(-1, _T("ReflectiveShadowMaps::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。")));

         ReflectiveShadowMaps::CBUFFER_PASS0* cbuffer = (ReflectiveShadowMaps::CBUFFER_PASS0*)mappedResource.pData;
         ::CopyMemory(&cbuffer->matLightWorldViewProj, &matLightWorldViewProj, sizeof(XMMATRIX));
         pD3DDeviceContext->Unmap(m_pConstantBuffers[m_Pass], 0);

         // 定数バッファを設定
         pD3DDeviceContext->VSSetConstantBuffers(0, 1, &m_pConstantBuffers[m_Pass]);
      }
      break;
   case 1:
      {
         XMMATRIX matLightWorldViewProj = XMMatrixTranspose(*pMatWorld * m_MatLightView * m_MatLightProj);
         // ライトビューのワールドビュー行列( ローカル座標系の法線ベクトルの座標変換のため逆転置行列 )
         XMMATRIX matLightWorldView = XMMatrixInverse( nullptr, *pMatWorld * m_MatLightView );

         // 定数バッファを作成する
         D3D11_MAPPED_SUBRESOURCE mappedResource;
         if (FAILED(hr = pD3DDeviceContext->Map(m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)))
            throw(UException(-1, _T("ReflectiveShadowMaps::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。")));

         ReflectiveShadowMaps::CBUFFER_PASS1* cbuffer = (ReflectiveShadowMaps::CBUFFER_PASS1*)mappedResource.pData;

         ::CopyMemory(&cbuffer->matLightWorldViewProj, &matLightWorldViewProj, sizeof(XMMATRIX));
         ::CopyMemory(&cbuffer->matLightWorldView, &matLightWorldView, sizeof(XMMATRIX));

         pD3DDeviceContext->Unmap(m_pConstantBuffers[m_Pass], 0);

         // 定数バッファを設定
         pD3DDeviceContext->VSSetConstantBuffers(0, 1, &m_pConstantBuffers[m_Pass]);
         pD3DDeviceContext->PSSetConstantBuffers(0, 1, &m_pConstantBuffers[m_Pass]);
      }
      break;
   case 2:
      {
         XMMATRIX matLightWorldViewProj = XMMatrixTranspose(*pMatWorld * m_MatLightView * m_MatLightProj);
         XMMATRIX matCameraWorldViewProj = XMMatrixTranspose(*pMatWorld * m_MatCameraView * m_MatCameraProj);

         // 平行光源の座標変換
         XMMATRIX matInv = XMMatrixInverse(nullptr, *pMatWorld);
         XMVECTOR v = XMVector4Transform(XMLoadFloat4(&m_VecLightPos), matInv);
         XMVECTOR nv = XMVector3Normalize(v);
         XMFLOAT4 localLightPos;
         XMStoreFloat4(&localLightPos, nv);

         // 定数バッファを作成する
         D3D11_MAPPED_SUBRESOURCE mappedResource;
         if (FAILED(hr = pD3DDeviceContext->Map(m_pConstantBuffers[m_Pass], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)))
            throw(UException(-1, _T("ReflectiveShadowMaps::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。")));

         ReflectiveShadowMaps::CBUFFER_PASS2* cbuffer = (ReflectiveShadowMaps::CBUFFER_PASS2*)mappedResource.pData;

         ::CopyMemory(&cbuffer->matLightWorldViewProj, &matLightWorldViewProj, sizeof(XMMATRIX));
         ::CopyMemory(&cbuffer->matCameraWorldViewProj, &matCameraWorldViewProj, sizeof(XMMATRIX));
         ::CopyMemory(&cbuffer->vecLightPos, &localLightPos, sizeof(XMFLOAT4));
         ::CopyMemory(cbuffer->offsetXArray, m_offsetXArray, sizeof(m_offsetXArray));
         ::CopyMemory(cbuffer->offsetYArray, m_offsetYArray, sizeof(m_offsetYArray));

         pD3DDeviceContext->Unmap(m_pConstantBuffers[m_Pass], 0);

         // 定数バッファを設定
         pD3DDeviceContext->VSSetConstantBuffers(0, 1, &m_pConstantBuffers[m_Pass]);
         pD3DDeviceContext->PSSetConstantBuffers(0, 1, &m_pConstantBuffers[m_Pass]);
      }
      break;
   }
}

void ReflectiveShadowMaps::EndPass(ID3D11DeviceContext* pD3DDeviceContext)
{
   switch (m_Pass)
   {
   case 0:
      break;
   case 1:
      // レンダーターゲットビューと深度ステンシルビューとビューポートを戻す
      pD3DDeviceContext->OMSetRenderTargets(1, &m_pOldRTView, m_pOldDSView);
      SAFE_RELEASE(m_pOldRTView);
      SAFE_RELEASE(m_pOldDSView);

      pD3DDeviceContext->RSSetViewports(m_ViewportCount, m_pOldViewport);
      break;
   case 2:
      ID3D11ShaderResourceView* pNull[] = { nullptr, nullptr, nullptr, nullptr };
      pD3DDeviceContext->PSSetShaderResources(1, _countof(pNull), pNull);
      break;
   }

   m_Pass = -1;
}

void ReflectiveShadowMaps::End()
{
   m_Pass = -2;
}

サンプリング位置の計算方法はぶっちゃけ適当です。それとPass2でいきなり最終レンダリングしてますが、実際には間に低解像度の反射マップを作成する処理を追加してディファードレンダリングしたほうがいいらしいです。

また深度マップは影生成のために高解像度が必要ですが、他のマップはできるだけ広い範囲をサンプリングしたほうがよいため低解像度のレンダーターゲットビューを使用します。
つまり同じライトビューでのレンダーターゲットビューの生成であっても解像度が異なるため2回に分けてレンダリングしてます。
まあ高解像度のレンダーターゲットビューにすべてレンダリングして、低解像度のレンダーターゲットビューに縮小コピーするのとどちらが効率がいいかは試してませんけどね。

---main.cpp---  ↑


#include "../Header/Common/UCommon.h"
#include "../Header/Common/UException.h"
#include "../Header/Common/UDirect3D11.h"
#include "../Header/Common/UDebugFont.h"
#if defined(DEBUG) || defined(_DEBUG)
#include "../Header/Common/USRViewRenderer.h"
#endif
#include "../Header/Shader/ReflectiveShadowMaps.h"

#include "../Header/Mesh/BackGroundMesh.h"

// アプリケーション名
TCHAR* AppName = _T("Direct3D11 Reflective Shadow Maps");

// Direct3D関連の自作クラス
UDirect3D11* g_pDirect3D11 = nullptr;

ReflectiveShadowMaps* g_pReflectiveShadowMaps = nullptr;

BackGroundMesh* g_pBackGround = nullptr;

UDebugFont* g_pDebugFont = nullptr;
UFPS* g_pFPS = nullptr;

#if defined(DEBUG) || defined(_DEBUG)
USRViewRenderer* g_pSRViewRenderer[4] = { nullptr, nullptr, nullptr, nullptr };
#endif

DWORD g_Width = 640, g_Height = 480;
XMFLOAT2 g_DepthMapSize = XMFLOAT2( 512.0f, 512.0f );
XMFLOAT2 g_WorldPosNormalFluxMapSize = XMFLOAT2(128.0f, 128.0f);
float g_LightZFar = 3500.0f, g_LightZNear = 1500.0f;
float g_CameraZFar = 2000.0f, g_CameraZNear = 10.0f;

// カメラビューのビュー行列
XMMATRIX g_MatCameraView = XMMatrixIdentity();

// カメラービュー射影行列
XMMATRIX g_MatCameraProj = XMMatrixPerspectiveFovLH(XM_PI / 5.0f, (float)g_Width / (float)g_Height, g_CameraZNear, g_CameraZFar);

// ライトービュー射影行列( ビューポートのアスペクト比はHigh、Low解像度で同じとする )
XMMATRIX g_MatLightProj = XMMatrixPerspectiveFovLH(XM_PI / 5.0f, g_DepthMapSize.x / g_DepthMapSize.y, g_LightZNear, g_LightZFar);

// 平行光源の位置ベクトル
XMFLOAT4 g_VecLightPos = XMFLOAT4(1200.0f, 1900.0f, 1500.0f, 0);

// メモリ解放
void Invalidate()
{
#if defined(DEBUG) || defined(_DEBUG)
   for( int i=0; i<_countof(g_pSRViewRenderer); i++)
   {
      SAFE_DELETE_ARRAY(g_pSRViewRenderer[i]);
   }
#endif
   SAFE_DELETE(g_pReflectiveShadowMaps);
   SAFE_DELETE(g_pFPS);
   SAFE_DELETE(g_pDebugFont);
   SAFE_DELETE(g_pBackGround);
   SAFE_DELETE(g_pDirect3D11);
}

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

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

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

   return 0L;
}

// Direct3Dの作成
void CreateDirect3D(HINSTANCE hInstance)
{
   DXGI_MODE_DESC* pModeDescArray = nullptr;

   __try
   {
      DXGI_MODE_DESC  ModeDesc;
      UINT num;

      // ディスプレイモード一覧の数を取得する
      g_pDirect3D11->GetDisplayMode(nullptr, &num);

      pModeDescArray = NEW DXGI_MODE_DESC[num];
      // ディスプレイモード一覧を取得する
      g_pDirect3D11->GetDisplayMode(pModeDescArray, &num);

      bool find = false;
      for( UINT i=0; i<num; i++)
      {
         // 適切な解像度のディスプレイモードを検索する
         if (pModeDescArray[i].Width == g_Width && pModeDescArray[i].Height == g_Height)
         {
            find = true;
            ::CopyMemory(&ModeDesc, &pModeDescArray[i], sizeof(DXGI_MODE_DESC));
            break;
         }
      }

      if (find == false)
         throw(UException(-1, _T("InitDirect3D()でエラーが発生しました。適切なディスプレイモードの解像度を取得できません。")));

      // ウィンドウの作成およびDirect3D の作成
      g_pDirect3D11->CreateDirect3D11(AppName, hInstance, WndProc, &ModeDesc, TRUE, TRUE);

      g_pDebugFont->CreateMesh(g_pDirect3D11->m_pD3DDevice, 0.03f, 0.08f);

      // FPS描画クラス
      g_pFPS->CreateMesh(g_pDirect3D11->m_pD3DDevice);

#if defined(DEBUG) || defined(_DEBUG)
      for( int i=_countof(g_pSRViewRenderer)-1; i>=0; i--)
      {
         g_pSRViewRenderer[_countof(g_pSRViewRenderer) - i - 1]->Create(g_pDirect3D11->m_pD3DDevice, 1.0f - (200.0f / (float)g_Width) * (i + 1), 1.0f, 1.0f - (200.0f / (float)g_Width) * (i), 1.0f - 200.0f / (float)g_Height);
      }
#endif
   }
   __finally
   {
      SAFE_DELETE_ARRAY(pModeDescArray);
   }
}

void CreateGraphicePipeline()
{
   g_pReflectiveShadowMaps->Create(g_pDirect3D11->m_pD3DDevice, &g_DepthMapSize, &g_WorldPosNormalFluxMapSize);
}

// メッシュを作成する
void CreateMesh()
{
   g_pBackGround = NEW BackGroundMesh();
   g_pBackGround->CreateMesh(g_pDirect3D11->m_pD3DDevice);
}

void CreateResource(HINSTANCE hInstance)
{
   // Direct3D 関連自作クラスのインスタンスを作成
   // CreateDirect3D()関数内でインスタンスの作成を行うと、C2712 エラーが発生するのでここで行う。
   g_pDirect3D11 = NEW UDirect3D11();

   g_pReflectiveShadowMaps = NEW ReflectiveShadowMaps();

   g_pDebugFont = NEW UDebugFont();
   g_pFPS = NEW UFPS();

#if defined(DEBUG) || defined(_DEBUG)
   for( int i=0; i<_countof(g_pSRViewRenderer); i++)
   {
      g_pSRViewRenderer[i] = NEW USRViewRenderer();
   }
#endif

   // Direct3Dの作成
   CreateDirect3D(hInstance);

   // グラフィックパイプラインリソースの作成
   CreateGraphicePipeline();

   // リソースの作成
   CreateMesh();
}

void NextFrame()
{
   // ビュー行列
   if (GetKeyState(VK_UP) & 0x8000)
      g_MatCameraView *= XMMatrixTranslation(0, 0, -0.9f);
   if (GetKeyState(VK_DOWN) & 0x8000)
      g_MatCameraView *= XMMatrixTranslation(0, 0, 0.9f);
   if (GetKeyState(VK_RIGHT) & 0x8000)
      g_MatCameraView *= XMMatrixRotationY(-0.01f);
   if (GetKeyState(VK_LEFT) & 0x8000)
      g_MatCameraView *= XMMatrixRotationY(0.01f);
   if (GetKeyState('Q') & 0x8000)
      g_MatCameraView *= XMMatrixRotationX(0.01f);
   if (GetKeyState('A') & 0x8000)
      g_MatCameraView *= XMMatrixRotationX(-0.01f);

   g_pFPS->NextFrame();
   g_pBackGround->NextFrame();
}

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

   static float ClearColor[4] = { 0.3f, 0.3f, 1.0f, 1.0f };

   // バックバッファをクリアする。
   g_pDirect3D11->ClearBackBuffer(ClearColor);

   // 深度バッファをクリアする。
   g_pDirect3D11->ClearDepthStencilView(D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
   
   g_pReflectiveShadowMaps->Begin(&g_VecLightPos, &g_MatLightProj, &g_MatCameraView, &g_MatCameraProj);
   for( UINT i=0; i<g_pReflectiveShadowMaps->GetMaxPass(); i++)
   {
      g_pReflectiveShadowMaps->BeginPass(g_pDirect3D11->m_pD3DDeviceContext, i);
            
      g_pReflectiveShadowMaps->SetConstantBuffers(g_pDirect3D11->m_pD3DDeviceContext, g_pBackGround->GetMatWorld());
      g_pBackGround->Render(g_pDirect3D11->m_pD3DDeviceContext);

      g_pReflectiveShadowMaps->EndPass(g_pDirect3D11->m_pD3DDeviceContext);
   }
   g_pReflectiveShadowMaps->End();
   
#if defined(DEBUG) || defined(_DEBUG)
   int SrvRGB1[] = { 0, 0, 0, 3 };
   g_pSRViewRenderer[0]->SetSRView(g_pReflectiveShadowMaps->GetDepthMap(), SrvRGB1);
   g_pSRViewRenderer[0]->Render(g_pDirect3D11->m_pD3DDeviceContext);

   int SrvRGB2[] = { 0, 1, 2, 3 };
   g_pSRViewRenderer[1]->SetSRView(g_pReflectiveShadowMaps->GetWorldPositionMap(), SrvRGB2);
   g_pSRViewRenderer[1]->Render(g_pDirect3D11->m_pD3DDeviceContext);

   int SrvRGB3[] = { 0, 1, 2, 3 };
   g_pSRViewRenderer[2]->SetSRView(g_pReflectiveShadowMaps->GetWorldNormalMap(), SrvRGB3);
   g_pSRViewRenderer[2]->Render(g_pDirect3D11->m_pD3DDeviceContext);

   int SrvRGB4[] = { 0, 1, 2, 3 };
   g_pSRViewRenderer[3]->SetSRView(g_pReflectiveShadowMaps->GetWorldFluxMap(), SrvRGB4);
   g_pSRViewRenderer[3]->Render(g_pDirect3D11->m_pD3DDeviceContext);

   g_pDebugFont->Render(g_pDirect3D11->m_pD3DDeviceContext);
#endif
   
   g_pFPS->Render(g_pDirect3D11->m_pD3DDeviceContext);

   // レンダリングされたイメージをユーザーに表示。
   if (FAILED(hr = g_pDirect3D11->Present(0, 0)))
      throw(UException(hr, _T("IDXGISwapChain::Present()が失敗しました")));

   return hr;
}

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

   MSG msg = { 0 };

   try
   {
      CreateResource(hInstance);

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

      // メッセージループ
      do
      {
         if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
         {
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
         }
         else
         {
            NextFrame();
            Render();
         }
      } while (msg.message != WM_QUIT);
   }
   catch (UException ex)
   {
      ::MessageBox(nullptr, ex.m_pErrorStr, _T("エラー"), MB_OK);
   }

   Invalidate();

   ::UnregisterClass(AppName, hInstance);

   return msg.wParam;
}

やる気も戻ってきたので今後は可能な限り更新していきます。ペースは遅いでしょうけど。

Prev Top Next
inserted by FC2 system