ColModel Picker

Color Model Picker

Windows10 でハードディスク上の X-FILE(頂点座標+法線+色)を入力して描画します。
(この画像は6角大王のページからダウンロードして変換した "C:\DATA\XFILE\gal2.x" です)

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

概説

  1. File Picker を使うと直接ハードディスクからファイルを選択して入力することが出来ます。
    X-FILE を解析してモデルデータを作成するので、初心者には難しいかも知れません。
    また X-FILE の解析は一朝一夕には出来ません。これまで説明した X-FILE や XLoader のページを参照して下さい。
    このプロジェクトでは、ハードディスクに格納されている X-FILE(頂点座標+法線+色)のモデルを入力して描画します。
    また法線が設定されていないモデルのときは、プログラムで法線ベクトルを計算します。
    色が設定されていないモデルのときは、モノクロで描画します。
    テクスチャには対応していないのでテクスチャモデルを選択してもテクスチャは描画されません。
  2. File Picker を使うプロジェクトは DirectX 11 および XAML アプリ(ユニバーサル Windows)から生成します。
    デザイン画面(DirectXPage.xaml)に Button を貼り付けて、Button_Click() のハンドラをコーディングします。
    ボタンのクリックで X-FILE を選択して読み込みます。
    X-FILE は普通 Shift_JIS でタイプされています。
    Text 文字列は String^(ワイドキャラクター)に変換して入力されます。
    このとき「全角文字(漢字,かな)」が含まれていて変換ミスが起きると、エラーで中断することがあります。
    全角文字を除くか、事前に utf-8 に変換しておく方法が考えられます。
    または Shift_JIS でそのまま読み込むと変換ミスが起こることはありません。
    Binary Data(Array<byte>) としてそのまま読み込むプログラムは Win10 OBJ Viewer を参照して下さい。
  3. DirectXPage.xaml Class にボタンを貼り付けてモデルを選択します。
    1. DirectXPage.xaml.cpp に次のソースを追加して下さい。
      #include <ppltasks.h>
      using namespace Windows::Storage::Pickers;
      using namespace Windows::Storage;
      using namespace Windows::Storage::Streams;
      
    2. DirectXPage.xaml.cpp では m_main(App1Main) を生成しています。
          m_main = std::unique_ptr<App1Main>(new App1Main(m_deviceResources));
      
    3. DirectXPage.xaml のデザイン画面に Button を貼り付けて、イベントハンドラを追加します。
      ボタンのクリックで X-FILE を選択する Button_Click() 関数です。
      X-FIILE の名前が StorageFile^ file で、そのソースが ReadTextAsync(file) で入力されます。
      m_text に入力したモデルデータ(String^ m_text) を引数にして m_main->SetString(m_text) を呼び出します。
      Button_Click() 関数の続きは Win10 Picker Texture を参照して下さい。
      Platform::String^       m_text;
      
      void App1::DirectXPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
      {
          auto open = ref new FileOpenPicker();
          open->SuggestedStartLocation = PickerLocationId::Desktop;
          open->FileTypeFilter->Clear();
          open->FileTypeFilter->Append(".x");
          create_task(open->PickSingleFileAsync()).then([this](StorageFile^ file)
          {   return FileIO::ReadTextAsync(file);
          }).then([this](task<String^> previousTask)
          {   try
          {
              m_text = previousTask.get();
              m_main->SetString(m_text);
          }
          catch (...)
          {
              OutputDebugString(L"X-FILE not found");
          }
          });
              ・
          // この後 DirectX 3D を起動する
              ・
      
    4. App1Main.cpp では m_sceneRenderer(X_Class) を生成しています。
      名前が X_Class に変わっていますが、Sample3DSceneRenderer に X-FILE の Load を組み込んだ Class です。
      App1Main::App1Main(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
          m_deviceResources(deviceResources), m_pointerLocationX(0.0f)
      {
          ・・・
          m_sceneRenderer = std::unique_ptr<X_Class>(new X_Class(m_deviceResources));
          ・・・
      }
      
      App1Main Class に SetString() 関数を追加して m_sceneRenderer->:SetString(text) を呼び出します。
      ここでは DirectXPage Class から受け取った text を m_sceneRenderer(X_Class) にリレーするだけです。
      void App1Main::SetString(Platform::String^ text)
      {
          m_sceneRenderer->SetString(text); 
      }
      
    5. X_Class.cpp で Model のソースを解析します。
      SetString() 関数で入力した X-FILE のソースを受け取って解析します。
      void X_Class::SetString(Platform::String^ text)
      {
          int num, pt, pw;
      
          // 領域の初期化
      
  4. Model のソースを受け取って解析する SetString() 関数です。
    ストアアプリの Stirng は機能が低く使い難いので STL の wstring に変換して行ごとに切り分けます。
    SetString(m_text) 関数で行ごとに切り分ける部分です。
    std::wstring    m_x;    //X-FILE TEXT
    vector<wstring> VT;     //X-FILE を行で切り分け
    
    void X_Class::SetString(Platform::String^ text)
    {
        int num, pt, pw;
    
        // 領域の初期化
    
        ・・・
    
        m_x = text->Data();
    
        // String を行で切り分ける(m_x⇒VT)
        num = m_x.size();
        for (pt = 0; pt<num;)
        {
            pw = pt;
            for (pt++; pt<num && m_x[pt] != L'\n'; pt++);
            if (pt >= num)  break;
            pt++;
            Word = Word.assign(m_x, pw, pt - pw);
            VT.push_back(Word);
        }
    
  5. モデルの色は MeshMaterialList と、その中に含まれる Material で定義されます。
    立方体の各面に色を設定したモデルの例です。
    最初の 6; が定義されている Material の数で、次の 6; が Face(面)の数です。
    続く 0, ・・・ 5;; が Face ごとの Index です。
    モデルの色は Face(面またはポリゴン)ごとに設定されます。
    Material { の最初の 1.000000;0.000000;0.000000;1.000000;; がモデルの色です。
    先頭から R(赤)G(緑)B(青)A(輝度) の順で、上の場合は赤色です。
    0.000000;1.000000;0.000000;1.000000;; は緑色です。
    Material(色)が省略されたときは、白に設定します。
     MeshMaterialList {
      6;
      6;
      0,
      1,
      2,
      3,
      4,
      5;;
    
      Material {
       1.000000;0.000000;0.000000;1.000000;;
       21.333333;
       0.000000;0.000000;0.000000;;
       0.000000;0.000000;0.000000;;
      }
      Material {
       0.000000;1.000000;0.000000;1.000000;;
       21.333333;
       0.000000;0.000000;0.000000;;
       0.000000;0.000000;0.000000;;
      }
      Material {
       0.000000;0.000000;1.000000;1.000000;;
       21.333333;
       0.000000;0.000000;0.000000;;
       0.000000;0.000000;0.000000;;
      }
      Material {
       1.000000;1.000000;0.000000;1.000000;;
       21.333333;
       0.000000;0.000000;0.000000;;
       0.000000;0.000000;0.000000;;
      }
      Material {
       0.000000;1.000000;1.000000;1.000000;;
       21.333333;
       0.000000;0.000000;0.000000;;
       0.000000;0.000000;0.000000;;
      }
      Material {
       1.000000;0.000000;1.000000;1.000000;;
       21.333333;
       0.000000;0.000000;0.000000;;
       0.000000;0.000000;0.000000;;
      }
     }
    
  6. Face(面)は Mesh の Index List で定義されます。
    Mesh { から頂点座標の定義が始まります。
    24; が頂点座標の数で、24個の三次元座標の定義が続きます。
    続く 6; が頂点データで構成する Face(ポリゴン)の数です。
    4;3,2,1,0;, の 4; は四角形ポリゴンで、3,2,1,0 が頂点座標の Index です。
    MeshNormals { から法線ベクトルの定義が始まります。
    法線ベクトルも頂点座標と同じように定義されていて Face の数も構成するポリゴンも同じです。
    MeshNormals は省略されることもあり、そのときはプログラムで計算します。
    Mesh {
     24;
     -1.0;1.0;-1.0;,
     1.0;1.0;-1.0;,
     1.0;1.0;1.0;,
     -1.0;1.0;1.0;,
     -1.0;-1.0;-1.0;,
     1.0;-1.0;-1.0;,
     1.0;-1.0;1.0;,
     -1.0;-1.0;1.0;,
     -1.0;-1.0;1.0;,
     -1.0;-1.0;-1.0;,
     -1.0;1.0;-1.0;,
     -1.0;1.0;1.0;,
     1.0;-1.0;1.0;,
     1.0;-1.0;-1.0;,
     1.0;1.0;-1.0;,
     1.0;1.0;1.0;,
     -1.0;-1.0;-1.0;,
     1.0;-1.0;-1.0;,
     1.0;1.0;-1.0;,
     -1.0;1.0;-1.0;,
     -1.0;-1.0;1.0;,
     1.0;-1.0;1.0;,
     1.0;1.0;1.0;,
     -1.0;1.0;1.0;;
    
     6;
     4;3,2,1,0;,
     4;4,5,6,7;,
     4;11,10,9,8;,
     4;12,13,14,15;,
     4;19,18,17,16;,
     4;20,21,22,23;;
    
  7. Face を管理するために Face 構造体を定義します。
    Num が Face を構成する頂点の数(N角ポリゴン)で、Pos, Norm が Index の並びです。
    Midx が Material(色)を定義するテーブルへの Index です。
    Material が使われていない時は -1 に設定します。
    // Face 構造体
    struct  Face
    {   int         Num;        // 頂点数
        vector<int> Pos;        // 頂点 Index の並び
        vector<int> Norm;       // 法線 Index の並び
        int         Midx;       // Material(MTBL) Index
    };
    vector<Face>    FTBL;       // Face Table
    
    Polygon3 構造体は Face 構造体を3角ポリゴンに変換した構造体です。
    // Polygon3 構造体
    struct  Pol3
    {   int     Pos[3];         // 頂点 Index の並び
        int     Norm[3];        // 法線 Index の並び
        int     Midx;           // Material(MTBL) Index
    };
    vector<Mat>    POL3;        // Polygon3 Table
    
  8. Material(色)を管理するために Material 構造体を定義します。
    matName は Material に付けられた名前で、次に説明します。
    faceColor が Face の色です。 power; specularColor; emissiveColor; は、今回は使いません。
    // Material 構造体
    struct  Mat
    {   string  matName;
        DirectX::XMFLOAT4 faceColor;
        float   power;
        DirectX::XMFLOAT3 specularColor;
        DirectX::XMFLOAT3 emissiveColor;
    };
    vector<Mat>    MTBL;       // Material Table
    
  9. Material は上記のように、MeshMaterialList の中で直接定義される場合と、名前を付けて宣言される場合があります。
    下記の例では Matred の名前で、赤色のマテリアルが宣言されています。
    また下記の例では a の名前で TextureFilename {"test.jpg";} をテクスチャとして使用します。
    テクスチャモデルは、次のバージョンを参照して下さい。
    今回は Material をキーにして、先頭から順に MTBL に登録します。
    MeshMaterialList に名前が指定されたときは、MTBL を検索して Index を設定します。
    無名のときは、MTBL の先頭から順に Index を割り当てます。
    名前付と無名を併用すると Index が正しく設定されないことがあるので避けて下さい。
    一般的なモデルでは、どちらかの方法が使われているので、問題なく描画されています。
    Material Matred {
     1.000000;0.000000;0.000000;1.000000;;
     21.333333;
     0.000000;0.000000;0.000000;;
     0.000000;0.000000;0.000000;;
    }
    Material a {
     1.000000;1.000000;1.000000;1.000000;;
     21.333333;
     0.000000;0.000000;0.000000;;
     0.000000;0.000000;0.000000;;
     TextureFilename {
      "test.jpg";
     }
    }
    
  10. Material の定義名を使ったときの MeshMaterialList の例です。
    最初の 5; が定義されている Material の数で、次の 25; が Face(面)の数です。
    続く 0, 1, ・・・ 4;; が Face ごとの Index です。
    {Matpi} などが Material の名前です。
     MeshMaterialList {
      5;
      25;
      0,
      1,
      ・・・
      4,
      4;;
      {Matpi}
      {Matred}
      {Matye}
      {Matbu}
      {Matgre}
     }
    
  11. VertexPosition の定義です。
    struct VertexPosition
    {
        DirectX::XMFLOAT3 pos;
        DirectX::XMFLOAT3 norm;
        DirectX::XMFLOAT4 color;
    };
    
  12. InputLayout(頂点データの形式)です。
        const D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
        {
            { "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 },
            { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 
        };
    
  13. シェーダーは[頂点座標+法線+4色]のものを使用して下さい。
    File Picker から選択した X-FILE(カラーモデル)が描画出来ることを確かめて下さい。
    色が設定されていないモデルも描画出来るので試して下さい。

プログラムの説明

  1. ファイル名が X_Class に変わっていますが、実質的には Sample3DSceneRenderer です。
    X-FILE は Shift_JIS でタイプされているのですが、File Picker で標準入力した場合は String^ に変換されます。
    そこで vector<wstring> VT; (string では無い)に行で切り分けて格納します。
    シェーダーは[頂点座標+法線+4色]のものを使っています。
  2. X-FILE を解析する主な領域です。
        std::wstring    m_x;                //X-FILE TEXT
        vector<wstring> VT;                 //X-FILE を行で切り分け
        int             VT_size;            //VT の大きさ
    
        vector<Face>    FTBL;               // Face Table
        vector<Pol3>    POL3;               // Polygon3 Table
        vector<Mat>     MTBL;               // Material Table
    
        vector<DirectX::XMFLOAT3> m_pos;    // 頂点座標
        vector<DirectX::XMFLOAT3> m_norm;   // 法線ベクトル
    
  3. メソッドの詳細は Win10 MaterialModel を参照して下さい。
  4. 説明の足らない所は Color Model 「ハードディスク上の X-FILE(頂点座標+法線+色)を描画します」も併せて参照して下さい。

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