X2017 Norm Cone

Blend for Visual Studio Community 2017 でコーンの座標と法線をプログラムで計算します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. Visual Studio 2017 でコーンの座標をプログラムで計算して描画します。
    シェーダは入れ替えなければならないのですが、ソースコードの修正が短いので取り上げます。
  2. Visual Studio 2017 を起動して DirectX 11 および XAML アプリ(ユニバーサル Windows)を構築して下さい。
    テンプレートが表示されないときは Visual Studio 2017 DirectX を参照して下さい。
    カラーキューブが回転しながら描画され、マウスをドラッグするとX座標に合わせてモデルが回転します。
  3. 自動生成したモデルは「頂点座標+カラー」ですが、今回のモデルは「頂点座標+法線ベクトル」で構成します。
    従って Shader 関係のファイルを書き換える必要があります。
    \Content\ に格納されている SampleVertexShader.hlsl と SamplePixelShader.hlsl と ShaderStructures.h を次のように修正して下さい。
    SampleVertexShader.hlsl, SamplePixelShader.hlsl は Shift-JIS でタイプして下さい。
    シェーダ関係の説明は Windows10 Shader を参照して下さい。
    1. Content\SampleVertexShader.hlsl のソースコードです。
      cbuffer ModelViewProjectionConstantBuffer : register(b0)
      {
          matrix model;
          matrix view;
          matrix projection;
      };
      
      struct VertexShaderInput
      {
          float3 pos : POSITION;
          float3 norm : NORMAL;
      };
      
      struct VertexShaderOutput
      {
          float4 pos : SV_POSITION;
          float3 norm : NORMAL;
      };
      
      VertexShaderOutput main(VertexShaderInput input)
      {
          VertexShaderOutput output;
          float4 pos = float4(input.pos, 1.0f);
      
          // Transform the vertex position into projected space.
          pos = mul(pos, model);
          pos = mul(pos, view);
          pos = mul(pos, projection);
          output.pos = pos;
      
          float4 norm = float4(normalize(input.norm), 0.0f);
          norm = mul(norm, model);
          output.norm = normalize(norm.xyz);
          return output;
      }
      
    2. Content\SamplePixelShader.hlsl のソースコードです。
      struct PixelShaderInput
      {
          float4 pos : SV_POSITION;
          float3 norm : NORMAL;
      };
      
      float4 main(PixelShaderInput input) : SV_TARGET
      {
          float3 lightDirection = normalize(float3(1, -1, 0));
          float lightMagnitude = 0.8f * saturate(dot( input.norm, -lightDirection)) + 0.2f;
          return float4(1,1,0.2,1) * lightMagnitude;
          //return float4(1,0.2,0.2,1) * lightMagnitude;
      }
      
    3. Content\ShaderStructures.h のソースコードです。
      #pragma once
      
      namespace App1
      {
      	// MVP マトリックスを頂点シェーダーに送信するために使用する定数バッファー。
      	struct ModelViewProjectionConstantBuffer
      	{
      		DirectX::XMFLOAT4X4 model;
      		DirectX::XMFLOAT4X4 view;
      		DirectX::XMFLOAT4X4 projection;
      	};
      
      	// 頂点シェーダーへの頂点ごとのデータの送信に使用します。
      	struct VertexPosition
      	{
      		DirectX::XMFLOAT3 pos;
      		DirectX::XMFLOAT3 norm;
      	};
      }
      
  4. Content\Sample3DSceneRenderer.cpp のソースコードを修正します。
    1. KAKU はコーンの角の数で、19 ぐらいに設定すると角がとれてかなり滑らかになります。
      #define  KAKU  19  // (多角錐の数+1)
      
    2. D3D11_INPUT_ELEMENT_DESC を "COLOR" から "NORMAL" に修正します。
          //{ "COLOR",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0 },
          { "NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0 },
      
    3. 肝心のモデルの座標と法線の計算です。
      「static const VertexPositionColor cubeVertices[] = { ... }」 を削除して置き換えて下さい。
      Vertices[KAKU * 2]; が頂点データの配列で .pos がコーンの座標で .norm が法線ベクトルです。
      ループで計算したままでは、計算誤差のためわずかな隙間が生じます。
      後の2行でそれを補正しています。
          static VertexPosition cubeVertices[KAKU * 2];
          // 座標が同じでも法線が変わると別データとして登録
          for(int slice=0; slice<KAKU; slice++)
          {
              float v = (float)slice / (float)(KAKU-1);
              float theta = v * 3.14f * 2;
              cubeVertices[2 * slice + 0].pos = XMFLOAT3(sinf(theta), -0.7f, cosf(theta));
              cubeVertices[2 * slice + 0].norm = XMFLOAT3(sinf(theta), 0.7f, cosf(theta));
              cubeVertices[2 * slice + 1].pos = XMFLOAT3(0.0f, 0.7f, 0.0f);
              cubeVertices[2 * slice + 1].norm = XMFLOAT3(sinf(theta), 0.7f, cosf(theta));
          }
          // Vertices 最後は先頭の座標と同じ
          cubeVertices[KAKU * 2 - 2].pos = cubeVertices[0].pos;
          cubeVertices[KAKU * 2 - 1].pos = cubeVertices[1].pos;
      
    4. 頂点 Index の定義です。
      「static const unsigned short cubeIndices [] = { ... }」 を削除して置き換えて下さい。
      三角ポリゴンを組み合わせてコーンのモデルを作成します。
              static uint16 cubeIndices[KAKU *3];
              for(int slice=0; slice<(KAKU-1); slice++)
              {
                  cubeIndices[3 * slice + 0] = slice * 2 + 0;
                  cubeIndices[3 * slice + 1] = slice * 2 + 1;
                  cubeIndices[3 * slice + 2] = slice * 2 + 2;
              }
              m_indexCount = (KAKU-1) * 6;    // Index Byte Size
      
    5. VertexPositionColor が使われている箇所を VertexPosition に置き換えて下さい。
      (ShaderStructures.h で定義されていた VertexPositionColor を VertexPosition に変更しています)
  5. コンパイル&実行すると、ページ先頭の画像のように法線ベクトルが設定されたコーンが回転しながら描画されます。
    モデルのサイズが大きいようならカメラを引いて調整して下さい。
        //static const XMVECTORF32 eye = { 0.0f, 0.7f, 1.5f, 0.0f };
        static const XMVECTORF32 eye = { 0.0f, 0.7f, 3.0f, 0.0f };
    
  6. ここで生成した Cone モデルの底には、ポリゴンが張り付けられていません。
    自動的に回転している分には問題ないのですが、底から見ると透けてしまいます。 (^_^;)
    Visual Studio 2015 で作成したプロジェクトは Win10 Norm Cone を参照して下さい。

超初心者のプログラム入門(DirectX Store)