X2019 Norm Cone

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

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

プログラムの説明

  1. Visual Studio 2019 でコーンの座標をプログラムで計算して描画します。
    シェーダは入れ替えなければならないのですが、ソースコードの修正が短いので取り上げます。
    プロジェクトの作成は Visual Studio 2019 DirectX を参照して下さい。
    コンパイル&実行するとカラーキューブが回転しながら描画され FPS が表示されます。
    前回作成した App1.sln(App2.sln) をダブルクリックして起動することも出来ます。
  2. 自動生成したモデルは「頂点座標+カラー」ですが、今回のモデルは「頂点座標+法線ベクトル」で構成します。
    従って 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;
          };
      }
      
  3. 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;
      
          // 以下元のソースが続きます
          D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
             ・・・
      
    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
              
              // 以下元のソースが続きます
              D3D11_SUBRESOURCE_DATA indexBufferData = {0};
                  ・・・
      
    5. VertexPositionColor が使われている箇所を調べて VertexPosition に置き換えて下さい。
      (ShaderStructures.h で定義されている VertexPositionColor は VertexPosition になっています)
  4. コンパイル&実行すると、ページ先頭の画像のように法線ベクトルが設定されたコーンが回転しながら描画されます。
    モデルのサイズが大きいようならカメラを引いて調整して下さい。
        //static const XMVECTORF32 eye = { 0.0f, 0.7f, 1.5f, 0.0f };
        static const XMVECTORF32 eye = { 0.0f, 0.7f, 3.0f, 0.0f };
    
  5. ここで生成した Cone モデルの底には、ポリゴンが張り付けられていません。
    自動的に回転している分には問題ないのですが、底から見ると透けてしまいます。 (^_^;)
    裏面(底)にもポリゴンを張り付けて、蓋をしてみて下さい。

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