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

■Direct3D11 Effective Water Simulation Prev Top Next
関連ページ:Direct3D11 自作ライブラリ


ほぼ一週間ぶりの更新です。こんなに速く更新できるとは思ってなかったですけど、まあ簡単なネタなので。
さて今回は、GPU Gems からのネタです。GPU Gems 3ではなく GPU Gems です。まあ毎度のことですが、うちのサイトは管理者がやりたいことを自由にやるサイトなので古いネタでもやっていきます。
ということで今回のネタも古いです。

今回は波生成です。以前やった波生成ではバンプマップを使用しましたが、今回はバンプマップを使用せず、頂点移動により波生成を行います。
説明は特にしませんが、元のドキュメントはここにありますので参照してください。


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

Aシェーダー系で使用するソースです。
EffectiveWaterSimulation_Pass0.hlsl ジオメトリレベルで波を生成するシェーダーソース
EffectiveWaterSimulation.h EffectiveWaterSimulationクラスのヘッダーファイル
EffectiveWaterSimulation.cpp EffectiveWaterSimulationクラスのソースファイル

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


---EffectiveWaterSimulation_Pass0.hlsl---  ↑

// ************************************************************
// Effective Water Simulation
// ************************************************************

// 定数バッファ
cbuffer cbBuffer_hull : register( b0 )
{
   float g_fTessFactor       : packoffset( c0.x );   // パッチのエッジのテッセレーション係数
   float g_fInsideTessFactor : packoffset( c0.y );   // パッチ内部のテッセレーション係数
};

cbuffer cbBuffer_domain : register( b1 )
{
   column_major float4x4 g_matCameraWorldViewProj   : packoffset( c0 );   // カメラビューでのワールドとビューと射影行列
   float4 g_vecWaveGeneratePosition[2] : packoffset( c4 );   // xyz:波の生成座標
   float4 g_vecWaveParameters[2] : packoffset( c6 );   // x:振幅、y:波長、z:角度、w:波のエッジ
};

cbuffer cbBuffer_pixel : register( b2 )
{
   float4 g_vecLightPos         : packoffset( c0 );    // ローカル座標系での平行光源の位置ベクトル
};

// 頂点シェーダーの入力パラメータ
struct VS_IN
{
   float3 pos    : POSITION;
   float3 normal : NORMAL;
   float2 texel  : TEXCOORD;
};

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

// ハルシェーダーのパッチ定数フェーズ用の出力パラメータ
struct CONSTANT_HS_OUT_DS_IN
{
   float Edges[3] : SV_TessFactor;        // パッチのエッジのテッセレーション係数
   float Inside : SV_InsideTessFactor; // パッチ内部のテッセレーション係数
};

// ハルシェーダーのコントロール ポイント フェーズ用の出力パラメータ
struct CONTROL_HS_OUT_DS_IN
{
   float3 pos   : POSITION;
   float3 normal : NORMAL;
   float2 texel : TEXCOORD0;
};

// ドメインシェーダーの出力パラメータ
struct DS_OUT_PS_IN
{
   float4 pos   : SV_POSITION;
   float3 normal : NORMAL;
   float2 texel : TEXCOORD0;
};

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

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

// *****************************************************************************************
// 頂点シェーダー
// *****************************************************************************************
VS_OUT_HS_IN EffectiveWaterSimulation_Pass0_VS_Main( VS_IN In )
{
   VS_OUT_HS_IN Out;

   Out.pos = In.pos;
   Out.normal = In.normal;
   Out.texel = In.texel;
   return Out;
}

// *****************************************************************************************
// ハルシェーダーのパッチ定数フェーズ
// *****************************************************************************************
CONSTANT_HS_OUT_DS_IN EffectiveWaterSimulation_Pass0_ConstantHS( InputPatch<VS_OUT_HS_IN, 3> ip, uint PatchID : SV_PrimitiveID )
{
   CONSTANT_HS_OUT_DS_IN Out;

   Out.Edges[0] = Out.Edges[1] = Out.Edges[2] = g_fTessFactor;  // パッチのエッジのテッセレーション係数
   Out.Inside = g_fInsideTessFactor;  // パッチ内部のテッセレーション係数
 
   return Out;
}

// *****************************************************************************************
// ハルシェーダーのコントロール ポイント フェーズ
// *****************************************************************************************
[domain("tri")]                              // テッセレートするメッシュの形状を指定する
[partitioning("integer")]                    // パッチの分割に使用するアルゴリズムを指定する
[outputtopology("triangle_ccw")]             // メッシュの出力方法を指定する
[outputcontrolpoints(3)]                     // ハルシェーダーのコントロール ポイント フェーズがコールされる回数
[patchconstantfunc("EffectiveWaterSimulation_Pass0_ConstantHS")]      // 対応するハルシェーダーのパッチ定数フェーズのメイン関数
CONTROL_HS_OUT_DS_IN EffectiveWaterSimulation_Pass0_HS_Main( InputPatch<VS_OUT_HS_IN, 3> In, uint i : SV_OutputControlPointID, uint PatchID : SV_PrimitiveID )
{
   CONTROL_HS_OUT_DS_IN Out;

   Out.pos = In[i].pos;
   Out.normal = In[i].normal;
   Out.texel = In[i].texel;
   return Out;
}

// 波の高さを計算
float getHeight(   float3 waveGeneratePos // 波の生成座標
                 , float3 localPos        // 頂点座標
                 , float  amplitude       // 振幅
                 , float  wavelength      // 波長
                 , float  angle           // 角度
                 , float  waveEdge        // 波のエッジ
               )
{
   // 波の生成座標と頂点座標の距離
   float len = length( waveGeneratePos - localPos );
   // 波の高さを計算
   return amplitude * pow( ( sin( len / wavelength + angle ) + 1.0f ) * 0.5f, waveEdge );
}

// *****************************************************************************************
// ドメインシェーダー
// *****************************************************************************************
[domain("tri")]
DS_OUT_PS_IN EffectiveWaterSimulation_Pass0_DS_Main( CONSTANT_HS_OUT_DS_IN In, float3 uvw : SV_DomainLocation, const OutputPatch<CONTROL_HS_OUT_DS_IN, 3> patch )
{
   DS_OUT_PS_IN Out;

   float aroundh[4] = { 0, 0, 0, 0 };
   float offset = 0.1f;   // 適当に設定
   float dx, dz, h, totalh = 0.0f;
   
   // 頂点座標
   float3 p = patch[2].pos * uvw.x + patch[1].pos * uvw.y + patch[0].pos * uvw.z;
   
   // ローカル座標系で波生成
   for( int i=0; i<2; i++ )
   {
      // 波の高さを計算
      h = getHeight( g_vecWaveGeneratePosition[i].xyz, p, g_vecWaveParameters[i].x, g_vecWaveParameters[i].y, g_vecWaveParameters[i].z, g_vecWaveParameters[i].w );

      totalh += h;
      
      // 処理対象の頂点の周囲4箇所の波の高さを計算
      aroundh[0] += getHeight( g_vecWaveGeneratePosition[i].xyz, p + float3(  offset, 0, 0.0f ),    g_vecWaveParameters[i].x, g_vecWaveParameters[i].y, g_vecWaveParameters[i].z, g_vecWaveParameters[i].w );
      aroundh[1] += getHeight( g_vecWaveGeneratePosition[i].xyz, p + float3(  0.0f,   0, -offset ), g_vecWaveParameters[i].x, g_vecWaveParameters[i].y, g_vecWaveParameters[i].z, g_vecWaveParameters[i].w );
      aroundh[2] += getHeight( g_vecWaveGeneratePosition[i].xyz, p + float3( -offset, 0, 0.0f ),    g_vecWaveParameters[i].x, g_vecWaveParameters[i].y, g_vecWaveParameters[i].z, g_vecWaveParameters[i].w );
      aroundh[3] += getHeight( g_vecWaveGeneratePosition[i].xyz, p + float3(  0.0f,   0, offset ),  g_vecWaveParameters[i].x, g_vecWaveParameters[i].y, g_vecWaveParameters[i].z, g_vecWaveParameters[i].w );
   }

   p.y += totalh;
 
   // 行列変換後の頂点座標
   Out.pos =  mul( float4( p, 1.0f ), g_matCameraWorldViewProj );

   // 高さの差を計算
   dx = aroundh[2] - aroundh[0];
   dz = aroundh[1] - aroundh[3];

   // 法線ベクトル( yは適当に調整 )
   Out.normal = normalize( float3( dx, 0.2f, dz ) );

   // テクセル
   Out.texel = patch[2].texel * uvw.x + patch[1].texel * uvw.y + patch[0].texel * uvw.z;

   return Out;
}

// *****************************************************************************************
// ピクセルシェーダ
// *****************************************************************************************
float4 EffectiveWaterSimulation_Pass0_PS_Main( DS_OUT_PS_IN In ) : SV_TARGET
{
   // ハーフランバート
   float lambert = dot( g_vecLightPos.xyz, In.normal );
   lambert = lambert * 0.5f + 0.5f;

//   return float4( In.normal.zzz * 0.5f + 0.5f, 1 );
   return g_Tex.Sample( g_Sampler, In.texel ).bgra * lambert;
}

今回はテッセレーションを使用しました。が、必須ではありません。
ポリゴンの分割数によって品質がどう変化するかを確認するためにテッセレーションを使用しただけです。

さて波生成ですが、ローカル座標系上の2箇所で波生成を行います。その波の生成位置から円を描いて広がっていきます。
それぞれの波の高さは波の生成座標と頂点座標との距離、および時間( 正確には正弦波の角度 )と振幅からリアルタイムに計算されます。
よって波の生成座標を変更するとすべての波に影響するので注意してください。

そして最終的な波の高さは生成された2つの波の高さの合計値となります。

法線ベクトルは前後4箇所の頂点の高さのそれぞれの差分から計算しています。

---EffectiveWaterSimulation.h---  ↑


#pragma once

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

class EffectiveWaterSimulation
{
private:
   // ハルシェーダー用 定数バッファ構造体
   typedef struct _CBUFFER_HS
   {
      float fTessFactor;
      float fInsideTessFactor;
      float Dummy2;
      float Dummy3;
   }CBUFFER_HS;

   // ドメインシェーダー用 定数バッファ構造体
   typedef struct _CBUFFER_DS
   {
      XMMATRIX matCameraWorldViewProj;
      // 波の生成位置
      XMFLOAT4 vecWaveGeneratePosition[2];
      // 0:振幅、1:波長、2:角度、3:波のエッジ
      XMFLOAT4 vecWaveParameters[2];
   }CBUFFER_DS;

   // ピクセルシェーダー用 定数バッファ構造体
   typedef struct _CBUFFER_PS
   {
      // 平行光源の位置ベクトル
      XMFLOAT4 vecLightPos;
   }CBUFFER_PS;

public:
   typedef struct _WAVE
   {
      XMFLOAT4 vecWaveGeneratePosition;   // 波の生成座標
      float fAmplitude;                   // 振幅
      float fWavelength;                  // 波長
      float fAngle;                       // 角度
      float fAngularVelocity;             // 角速度
      float fWaveEdge;                    // 波のエッジ
   }WAVE;

private:
   WAVE m_pWave[2];

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

   UGraphicsPipeline* m_pGraphicsPipeline[1];

   int m_Pass;

   XMMATRIX m_MatCameraView, m_MatCameraProj;
   XMFLOAT4 m_VecLightPos;

   D3D11_FILL_MODE m_FillMode;

public:
   EffectiveWaterSimulation();
   virtual ~EffectiveWaterSimulation();
   void Invalidate();
   void Create(ID3D11Device* pD3DDevice, WAVE pWave[2]);
   void Begin(ID3D11Device* pD3DDevice, XMFLOAT4* pVecLightPos, XMMATRIX* pMatCameraView, XMMATRIX* pMatCameraProj, D3D11_FILL_MODE FillMode = D3D11_FILL_SOLID);
   void BeginPass(ID3D11DeviceContext* pD3DDeviceContext, UINT Pass);
   void SetConstantBuffers(ID3D11DeviceContext* pD3DDeviceContext, XMMATRIX* pMatWorld, float fTessFactor, float fInsideTessFactor);
   void EndPass(ID3D11DeviceContext* pD3DDeviceContext);
   void End();
   inline UINT GetMaxPass(){ return 1; };
};

---EffectiveWaterSimulation.cpp---  ↑


#include "../../Header/Shader/EffectiveWaterSimulation.h"
#include "../../HLSL/EffectiveWaterSimulation_Pass0_VS_Main.h"
#include "../../HLSL/EffectiveWaterSimulation_Pass0_HS_Main.h"
#include "../../HLSL/EffectiveWaterSimulation_Pass0_DS_Main.h"
#include "../../HLSL/EffectiveWaterSimulation_Pass0_PS_Main.h"

EffectiveWaterSimulation::EffectiveWaterSimulation()
{
   for (int i = 0; i<_countof(m_pGraphicsPipeline); i++)
   {
      m_pGraphicsPipeline[i] = nullptr;
   }
   for (int i = 0; i<_countof(m_pConstantBuffers); i++)
   {
      m_pConstantBuffers[i] = nullptr;
   }

   m_FillMode = D3D11_FILL_MODE::D3D11_FILL_SOLID;
   m_Pass = -2;
}

EffectiveWaterSimulation::~EffectiveWaterSimulation()
{
   for (int i = 0; i < _countof(m_pGraphicsPipeline); i++)
   {
      SAFE_DELETE(m_pGraphicsPipeline[i]);
   }
   for (int i = 0; i < _countof(m_pConstantBuffers); i++)
   {
      SAFE_RELEASE(m_pConstantBuffers[i]);
   }
}

void EffectiveWaterSimulation::Create(ID3D11Device* pD3DDevice, WAVE pWave[2])
{
   m_FillMode = D3D11_FILL_MODE::D3D11_FILL_SOLID;

   ::CopyMemory(m_pWave, pWave, sizeof(m_pWave));

   m_Pass = -2;

   // *******************************************************************************************************
   // UGraphicsPipelineの作成
   // *******************************************************************************************************

   m_pGraphicsPipeline[0] = NEW UGraphicsPipeline();

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

   // 深度ステンシルステートを作成する
   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/EffectiveWaterSimulation_Pass0.hlsl"), "EffectiveWaterSimulation_Pass0_VS_Main", layout, _countof(layout));
   m_pGraphicsPipeline[0]->CreateHullShaderFromFile(pD3DDevice, _T("../HLSL/EffectiveWaterSimulation_Pass0.hlsl"), "EffectiveWaterSimulation_Pass0_HS_Main");
   m_pGraphicsPipeline[0]->CreateDomainShaderFromFile(pD3DDevice, _T("../HLSL/EffectiveWaterSimulation_Pass0.hlsl"), "EffectiveWaterSimulation_Pass0_DS_Main");
   m_pGraphicsPipeline[0]->CreatePixelShaderFromFile(pD3DDevice, _T("../HLSL/EffectiveWaterSimulation_Pass0.hlsl"), "EffectiveWaterSimulation_Pass0_PS_Main");
#else
   m_pGraphicsPipeline[0]->CreateVertexShaderFromMemory(pD3DDevice, (LPBYTE)g_EffectiveWaterSimulation_Pass0_VS_Main, sizeof(g_EffectiveWaterSimulation_Pass0_VS_Main), layout, _countof(layout));
   m_pGraphicsPipeline[0]->CreateHullShaderFromMemory(pD3DDevice, (LPBYTE)g_EffectiveWaterSimulation_Pass0_HS_Main, sizeof(g_EffectiveWaterSimulation_Pass0_HS_Main));
   m_pGraphicsPipeline[0]->CreateDomainShaderFromMemory(pD3DDevice, (LPBYTE)g_EffectiveWaterSimulation_Pass0_DS_Main, sizeof(g_EffectiveWaterSimulation_Pass0_DS_Main));
   m_pGraphicsPipeline[0]->CreatePixelShaderFromMemory(pD3DDevice, (LPBYTE)g_EffectiveWaterSimulation_Pass0_PS_Main, sizeof(g_EffectiveWaterSimulation_Pass0_PS_Main));
#endif

   // 定数バッファを作成する
   m_pConstantBuffers[0] = m_pGraphicsPipeline[0]->CreateConstantBuffer(pD3DDevice, nullptr, sizeof(EffectiveWaterSimulation::CBUFFER_HS), D3D11_CPU_ACCESS_WRITE);
   m_pConstantBuffers[1] = m_pGraphicsPipeline[0]->CreateConstantBuffer(pD3DDevice, nullptr, sizeof(EffectiveWaterSimulation::CBUFFER_DS), D3D11_CPU_ACCESS_WRITE);
   m_pConstantBuffers[2] = m_pGraphicsPipeline[0]->CreateConstantBuffer(pD3DDevice, nullptr, sizeof(EffectiveWaterSimulation::CBUFFER_PS), D3D11_CPU_ACCESS_WRITE);
}

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

   if (FillMode != m_FillMode)
   {
      m_FillMode = FillMode;
      m_pGraphicsPipeline[0]->CreateRasterizerState(pD3DDevice, D3D11_CULL_MODE::D3D11_CULL_BACK, m_FillMode);
   }

   m_VecLightPos = *pVecLightPos;

   m_MatCameraView = *pMatCameraView;
   m_MatCameraProj = *pMatCameraProj;

   // 波のアニメーション
   for (int i = 0; i < _countof(m_pWave); i++)
   {
      m_pWave[i].fAngle += m_pWave[i].fAngularVelocity;
      if (m_pWave[i].fAngle > XM_2PI)
         m_pWave[i].fAngle -= XM_2PI;
   }

   m_Pass = -1;
}

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

   m_Pass = (int)Pass;

   switch (m_Pass)
   {
   case 0:
      {

      }
      break;
   default:
      throw(UException(-1, _T("EffectiveWaterSimulation::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 EffectiveWaterSimulation::SetConstantBuffers(ID3D11DeviceContext* pD3DDeviceContext, XMMATRIX* pMatWorld, float fTessFactor, float fInsideTessFactor)
{
   HRESULT hr = E_FAIL;

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

   switch (m_Pass)
   {
   case 0:
      {
         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[0], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)))
         {
            throw(UException(-1, _T("EffectiveWaterSimulation::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。")));
         }
         EffectiveWaterSimulation::CBUFFER_HS* cbuffer_hs = (EffectiveWaterSimulation::CBUFFER_HS*)mappedResource.pData;
         cbuffer_hs->fTessFactor = fTessFactor;
         cbuffer_hs->fInsideTessFactor = fInsideTessFactor;
         pD3DDeviceContext->Unmap(m_pConstantBuffers[0], 0);

         // ドメインシェーダー用定数バッファ
         if (FAILED(hr = pD3DDeviceContext->Map(m_pConstantBuffers[1], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)))
         {
            throw(UException(-1, _T("EffectiveWaterSimulation::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。")));
         }
         EffectiveWaterSimulation::CBUFFER_DS* cbuffer_ds = (EffectiveWaterSimulation::CBUFFER_DS*)mappedResource.pData;
         ::CopyMemory(&cbuffer_ds->matCameraWorldViewProj, &matCameraWorldViewProj, sizeof(XMMATRIX));
         for (int i = 0; i < _countof(m_pWave); i++)
         {
            ::CopyMemory(&cbuffer_ds->vecWaveGeneratePosition[i], &m_pWave[i].vecWaveGeneratePosition, sizeof(XMFLOAT4));

            cbuffer_ds->vecWaveParameters[i].x = m_pWave[i].fAmplitude;
            cbuffer_ds->vecWaveParameters[i].y = m_pWave[i].fWavelength;
            cbuffer_ds->vecWaveParameters[i].z = m_pWave[i].fAngle;
            cbuffer_ds->vecWaveParameters[i].w = m_pWave[i].fWaveEdge;
         }
         pD3DDeviceContext->Unmap(m_pConstantBuffers[1], 0);

         // ピクセルシェーダー用定数バッファ
         if (FAILED(hr = pD3DDeviceContext->Map(m_pConstantBuffers[2], 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)))
         {
            throw(UException(-1, _T("EffectiveWaterSimulation::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。")));
         }
         EffectiveWaterSimulation::CBUFFER_PS* cbuffer_ps = (EffectiveWaterSimulation::CBUFFER_PS*)mappedResource.pData;
         ::CopyMemory(&cbuffer_ps->vecLightPos, &localLightPos, sizeof(XMFLOAT4));
         pD3DDeviceContext->Unmap(m_pConstantBuffers[2], 0);

         // 定数バッファを設定

         pD3DDeviceContext->HSSetConstantBuffers(0, 1, &m_pConstantBuffers[0]);
         pD3DDeviceContext->DSSetConstantBuffers(1, 1, &m_pConstantBuffers[1]);
         pD3DDeviceContext->PSSetConstantBuffers(2, 1, &m_pConstantBuffers[2]);
      }
      break;
   }
}

void EffectiveWaterSimulation::EndPass(ID3D11DeviceContext*)
{
   switch (m_Pass)
   {
   case 0:
      break;
   }

   m_Pass = -1;
}

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

---main.cpp---  ↑


#include "../Header/Common/UCommon.h"
#include "../Header/Common/UException.h"
#include "../Header/Common/UDirect3D11.h"
#include "../Header/Shader/EffectiveWaterSimulation.h"
#include "../Header/Common/UDebugFont.h"
#include "../Header/Mesh/PlaneMesh.h"

// アプリケーション名
TCHAR* AppName = _T("Direct3D11 Effective Water Simulation");

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

EffectiveWaterSimulation* g_pEffectiveWaterSimulation = nullptr;

PlaneMesh* g_pPlaneMesh = nullptr;

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

DWORD g_Width = 640, g_Height = 480;

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);

// 平行光源の位置ベクトル
XMFLOAT4 g_VecLightPos = XMFLOAT4(20.0f, 200.0f, 300.0f, 0);

D3D11_FILL_MODE g_FillMode = D3D11_FILL_SOLID;
float g_fTessFactor = 20.0f;

// メモリ解放
void Invalidate()
{
   SAFE_DELETE(g_pFPS);
   SAFE_DELETE(g_pDebugFont);
   SAFE_DELETE(g_pEffectiveWaterSimulation);
   SAFE_DELETE(g_pPlaneMesh);
   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);
      else if (wParam == 'M')
      {
         if (g_FillMode == D3D11_FILL_SOLID)
            g_FillMode = D3D11_FILL_WIREFRAME;
         else
            g_FillMode = D3D11_FILL_SOLID;
      }
      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);
   }
   __finally
   {
      SAFE_DELETE_ARRAY(pModeDescArray);
   }
}

void CreateGraphicePipeline()
{
   EffectiveWaterSimulation::WAVE wave[2];

   wave[0].vecWaveGeneratePosition = XMFLOAT4(1200.0f, 0.0f, 200.0f, 0);
   wave[0].fAmplitude = 10.0f;              // 振幅
   wave[0].fWavelength = 20.0f;             // 波長
   wave[0].fAngularVelocity = -0.001f;      // 角速度
   wave[0].fWaveEdge = 1.0f;                // 波のエッジ
   wave[0].fAngle = 0.0f;                   // 角度

   wave[1].vecWaveGeneratePosition = XMFLOAT4(-1200.0f, 0.0f, -400.0f, 0);
   wave[1].fAmplitude = 15.0f;
   wave[1].fWavelength = 50.0f;
   wave[1].fAngularVelocity = -0.002f;
   wave[1].fWaveEdge = 2.5f;
   wave[1].fAngle = 0.0f;

   g_pEffectiveWaterSimulation->Create(g_pDirect3D11->m_pD3DDevice, wave);
}

// メッシュを作成する
void CreateMesh()
{
   g_pPlaneMesh = NEW PlaneMesh();
   g_pPlaneMesh->CreateMesh(g_pDirect3D11->m_pD3DDevice, 10, 10);
}

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

   g_pEffectiveWaterSimulation = NEW EffectiveWaterSimulation();

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

   // Direct3Dの作成
   CreateDirect3D(hInstance);

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

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

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

   // テッセレーション係数変更
   if (GetKeyState('V') & 0x8000)
   {
      g_fTessFactor += 0.01f;
   }
   if (GetKeyState('B') & 0x8000)
   {
      g_fTessFactor -= 0.01f;
      if (g_fTessFactor < 1.0f)
      {
         g_fTessFactor = 1.0f;
      }
   }

   g_pFPS->NextFrame();

   g_pPlaneMesh->NextFrame();

   TCHAR str[100];
   _stprintf_s(str, _T("%f\nV:Tessellation factor Up\nB:Tessellation factor Down\nM:Change Fill Mode"), g_fTessFactor);
   g_pDebugFont->NextFrame(str, &XMFLOAT2(-0.97f, 0.86f), &XMFLOAT4(1, 1, 1, 1));
}

// 描画処理
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_pEffectiveWaterSimulation->Begin(g_pDirect3D11->m_pD3DDevice, &g_VecLightPos, &g_MatCameraView, &g_MatCameraProj, g_FillMode);
   for (UINT i = 0; i<g_pEffectiveWaterSimulation->GetMaxPass(); i++)
   {
      g_pEffectiveWaterSimulation->BeginPass(g_pDirect3D11->m_pD3DDeviceContext, i);

      // 定数バッファを設定
      g_pEffectiveWaterSimulation->SetConstantBuffers(g_pDirect3D11->m_pD3DDeviceContext, g_pPlaneMesh->GetMatWorld(), g_fTessFactor, g_fTessFactor);

      // レンダリング
      g_pPlaneMesh->Render(g_pDirect3D11->m_pD3DDeviceContext, D3D11_PRIMITIVE_TOPOLOGY::D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST);

      g_pEffectiveWaterSimulation->EndPass(g_pDirect3D11->m_pD3DDeviceContext);
   }
   g_pEffectiveWaterSimulation->End();

   g_pFPS->Render(g_pDirect3D11->m_pD3DDeviceContext);
   g_pDebugFont->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