Win10 Normal Cone

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

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

プログラムの説明

  1. DirectX3D でコーンの座標と法線をプログラムで計算して描画します。
    Win10 Template を参照して DirectX 11 および XAML アプリ(ユニバーサル Windows)を生成して下さい。
    カラーキューブが回転しながら描画され、マウスをドラッグするとX座標に合わせてモデルが回転します。
  2. カラーキューブの頂点データは「頂点座標+カラー」で構成されています。
    今回は「頂点座標+法線ベクトル」のモデルなので Content\ に格納されている Shader 関係のファイルを書き換えて下さい。
    シェーダーの説明は Win10 Shader から「頂点座標+法線」を参照して下さい。
    Content\ShaderStructures.h には VertexPositionNorm を定義して下さい。
        struct VertexPositionNorm
        {
            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 VertexPositionNorm Vertices[KAKU * 2];
              // 座標が同じでも法線が変わると別データとして登録
              for(int slice=0; slice<KAKU; slice++)
              {
                  float v = (float)slice / (float)(KAKU-1);
                  float theta = v * 3.14f * 2;
                  Vertices[2 * slice + 0].pos = XMFLOAT3(sinf(theta), -0.7f, cosf(theta));
                  Vertices[2 * slice + 0].norm = XMFLOAT3(sinf(theta), 0.7f, cosf(theta));
                  Vertices[2 * slice + 1].pos = XMFLOAT3(0.0f, 0.7f, 0.0f);
                  Vertices[2 * slice + 1].norm = XMFLOAT3(sinf(theta), 0.7f, cosf(theta));
              }
              // Vertices 最後は先頭の座標と同じ
              Vertices[KAKU * 2 - 2].pos = Vertices[0].pos;
              Vertices[KAKU * 2 - 1].pos = Vertices[1].pos;
      
    4. 頂点 Index の定義です。
      「static const unsigned short cubeIndices [] = { ... }」 を削除して置き換えて下さい。
      三角ポリゴンを組み合わせてコーンのモデルを作成します。
              static uint16 Index[KAKU *3];
              for(int slice=0; slice<(KAKU-1); slice++)
              {
                  Index[3 * slice + 0] = slice * 2 + 0;
                  Index[3 * slice + 1] = slice * 2 + 1;
                  Index[3 * slice + 2] = slice * 2 + 2;
              }
              m_indexCount = (KAKU-1) * 6;    // Index Byte Size
      
    5. 頂点データの配列名を Vertices に、インデックスの配列名を Index に変えています。
      それに伴い cubeVertices, cubeIndices が使われている箇所を修正をして下さい。
  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 };
    

マウスで回転

  1. マウスでモデルを回転します。
    DirectXPage.xaml.cpp の OnPointerMoved() で X と Y を渡します。
    void DirectXPage::OnPointerMoved(Object^ sender, PointerEventArgs^ e)
    {   if (m_main->IsTracking())
        {   m_main->TrackingUpdate(e->CurrentPoint->Position.X, e->CurrentPoint->Position.Y);
        }
    }
    
  2. App1Main.h に m_pointerLocationY を追加して、TrackingUpdate() 関数で positionX と positionY を保存します。
        float m_pointerLocationX;
        float m_pointerLocationY;
    
        void TrackingUpdate(float positionX, float positionY)
        {   m_pointerLocationX = positionX;
            m_pointerLocationY = positionY;
        }
    
  3. App1Main.cpp の ProcessInput() 関数を修正します。
    void App1Main::ProcessInput()
    {   m_sceneRenderer->TrackingUpdate(m_pointerLocationX, m_pointerLocationY);
    }  
    
  4. Sample3DSceneRenderer の TrackingUpdate() で positionY の回転を追加します。
        void TrackingUpdate(float positionX, float positionY);
    
    void Sample3DSceneRenderer::TrackingUpdate(float positionX, float positionY)
    {
        XMMATRIX    mat;
        XMFLOAT4X4  f4x4;
        float       rx, ry;
    
        if (m_tracking)
        {   rx = XM_2PI*2.0f*positionX/m_deviceResources->GetOutputSize().Width;
            ry = XM_2PI*2.0f*positionY/m_deviceResources->GetOutputSize().Height;
            mat = XMMatrixRotationY(rx) * XMMatrixRotationX(ry);
            XMStoreFloat4x4(&f4x4, mat);
            m_constantBufferData.model = f4x4;
        }
    }
    
  5. これでマウス操作でモデルが自由に回転できるようになります。
    詳細は Win10 MouseRot を参照して下さい。
    ここで生成した Cone モデルの底には、ポリゴンが張り付けられていません。
    自動的に回転している分には問題ないのですが、マウスの操作で底から見ると透けてしまいます。 (^_^;)
    本来は Cone の底にもポリゴンを貼り付けなければならないのですが、挑戦してみて下さい。
  6. X2017 Norm Cone では、もう少し解りやすく説明しています。
    難しく感じる方はこちらを参照して下さい。
    1. シェーダのソースを掲載します。
    2. プログラムの修正が少なくて済むように cubeVertices, cubeIndices をそのまま使います。
    3. マウスの回転は自動生成されたY軸だけです。

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