Microsoft Visual Express 2013 for Desktop C++
 Direct3D 11.0( SM 5.0 )
 DirectXTex texture processing library
 XMLLite

■Direct3D11 Gerstner Waves Prev Top Next
関連ページ:Direct3D11 自作ライブラリ


今回も波生成です。海面の鋭い波を表現します。調べてみるとガルストナー波の波形はトロコイド曲線となるようですので、特に難しいことはないでしょう。
説明は特にしませんが、元のドキュメントはここにありますので参照してください。

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

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

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


---GerstnerWaves_Pass0.hlsl---  ↑

// ************************************************************
// Gerstner Waves
// ************************************************************

// 定数バッファ
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:角度
};

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 GerstnerWaves_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 GerstnerWaves_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("GerstnerWaves_Pass0_ConstantHS")]      // 対応するハルシェーダーのパッチ定数フェーズのメイン関数
CONTROL_HS_OUT_DS_IN GerstnerWaves_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 len = length( waveGeneratePos - localPos );
   return amplitude * sin( len / wavelength + angle );
}

// *****************************************************************************************
// ドメインシェーダー
// *****************************************************************************************
[domain("tri")]
DS_OUT_PS_IN GerstnerWaves_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 = 1.0f;   // 適当に設定
   float dx, dz, 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++ )
   {
      // 頂点と波の生成座標の距離
      float len = length( g_vecWaveGeneratePosition[i].xyz - p );
      
      // トロコイドの動円上の描画点の角度
      float a = len / g_vecWaveParameters[i].y + g_vecWaveParameters[i].z;

      // 波の高さを計算
      totalh += getHeight( g_vecWaveGeneratePosition[i].xyz, p, g_vecWaveParameters[i].x, g_vecWaveParameters[i].y, g_vecWaveParameters[i].z );
      
      // x座標
      p.x += dot( float3( -1, 0, 0 ), normalize( g_vecWaveGeneratePosition[i].xyz - p ) ) * 
                 g_vecWaveParameters[i].x * cos( a );
      
      // y座標
      p.z += dot( float3( 0, 0, -1 ), normalize( g_vecWaveGeneratePosition[i].xyz - p ) ) *
                 g_vecWaveParameters[i].x * cos( a );

      // 高さを合計する
      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 );
      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 );
      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 );
      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 );
   }

   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 = 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 GerstnerWaves_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;
}

ドメインシェーダー以外前回と一緒です。今回は、トロコイド曲線となるためx,z方向にも頂点移動します。

---GerstnerWaves.h---  ↑


#pragma once

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

// XNAMath
#include "../Common/XNAMath/xnamath.h"

class GerstnerWaves
{
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:角度
      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;             // 角速度
   }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:
   GerstnerWaves();
   virtual ~GerstnerWaves();
   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; };
};

---GerstnerWaves.cpp---  ↑


#include "../../Header/Shader/GerstnerWaves.h"
#include "../../HLSL/GerstnerWaves_Pass0_VS_Main.h"
#include "../../HLSL/GerstnerWaves_Pass0_HS_Main.h"
#include "../../HLSL/GerstnerWaves_Pass0_DS_Main.h"
#include "../../HLSL/GerstnerWaves_Pass0_PS_Main.h"

GerstnerWaves::GerstnerWaves()
{
   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;
}

GerstnerWaves::~GerstnerWaves()
{
   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 GerstnerWaves::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/GerstnerWaves_Pass0.hlsl"), "GerstnerWaves_Pass0_VS_Main", layout, _countof(layout));
   m_pGraphicsPipeline[0]->CreateHullShaderFromFile(pD3DDevice, _T("../HLSL/GerstnerWaves_Pass0.hlsl"), "GerstnerWaves_Pass0_HS_Main");
   m_pGraphicsPipeline[0]->CreateDomainShaderFromFile(pD3DDevice, _T("../HLSL/GerstnerWaves_Pass0.hlsl"), "GerstnerWaves_Pass0_DS_Main");
   m_pGraphicsPipeline[0]->CreatePixelShaderFromFile(pD3DDevice, _T("../HLSL/GerstnerWaves_Pass0.hlsl"), "GerstnerWaves_Pass0_PS_Main");
#else
   m_pGraphicsPipeline[0]->CreateVertexShaderFromMemory(pD3DDevice, (LPBYTE)g_GerstnerWaves_Pass0_VS_Main, sizeof(g_GerstnerWaves_Pass0_VS_Main), layout, _countof(layout));
   m_pGraphicsPipeline[0]->CreateHullShaderFromMemory(pD3DDevice, (LPBYTE)g_GerstnerWaves_Pass0_HS_Main, sizeof(g_GerstnerWaves_Pass0_HS_Main));
   m_pGraphicsPipeline[0]->CreateDomainShaderFromMemory(pD3DDevice, (LPBYTE)g_GerstnerWaves_Pass0_DS_Main, sizeof(g_GerstnerWaves_Pass0_DS_Main));
   m_pGraphicsPipeline[0]->CreatePixelShaderFromMemory(pD3DDevice, (LPBYTE)g_GerstnerWaves_Pass0_PS_Main, sizeof(g_GerstnerWaves_Pass0_PS_Main));
#endif

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

void GerstnerWaves::Begin(ID3D11Device* pD3DDevice, XMFLOAT4* pVecLightPos, XMMATRIX* pMatCameraView, XMMATRIX* pMatCameraProj, D3D11_FILL_MODE FillMode)
{
   if (m_Pass != -2)
   {
      throw(UException(-1, _T("GerstnerWaves::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 GerstnerWaves::BeginPass(ID3D11DeviceContext* pD3DDeviceContext, UINT Pass)
{
   if (m_Pass != -1)
   {
      throw(UException(-1, _T("GerstnerWaves::BeginPass()はCreate()またはEndPass()実行後に使用してください")));
   }

   m_Pass = (int)Pass;

   switch (m_Pass)
   {
   case 0:
   {

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

   if (m_Pass == -1)
   {
      throw(UException(-1, _T("GerstnerWaves::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("GerstnerWaves::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。")));
      }
      GerstnerWaves::CBUFFER_HS* cbuffer_hs = (GerstnerWaves::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("GerstnerWaves::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。")));
      }
      GerstnerWaves::CBUFFER_DS* cbuffer_ds = (GerstnerWaves::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;
      }
      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("GerstnerWaves::SetConstantBuffers()でエラーが発生しました。Map()が失敗しました。")));
      }
      GerstnerWaves::CBUFFER_PS* cbuffer_ps = (GerstnerWaves::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 GerstnerWaves::EndPass(ID3D11DeviceContext*)
{
   switch (m_Pass)
   {
   case 0:
      break;
   }

   m_Pass = -1;
}

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

---main.cpp---  ↑


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

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

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

GerstnerWaves* 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(200.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()
{
   GerstnerWaves::WAVE wave[2];

   wave[0].vecWaveGeneratePosition = XMFLOAT4(3200.0f, 0.0f, 200.0f, 0);
   wave[0].fAmplitude = 30.0f;              // 振幅
   wave[0].fWavelength = 60.0f;             // 波長
   wave[0].fAngularVelocity = -0.001f;      // 角速度
   wave[0].fAngle = 0.0f;                   // 角度

   wave[1].vecWaveGeneratePosition = XMFLOAT4(-200.0f, 0.0f, 3000.0f, 0);
   wave[1].fAmplitude = 20.0f;
   wave[1].fWavelength = 70.0f;
   wave[1].fAngularVelocity = -0.002f;
   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, 5, 5);
}

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

   g_pEffectiveWaterSimulation = NEW GerstnerWaves();

   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