X-FILE View

X-FILE View

プロジェクトに組み込んだ X-FILE を描画します。

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

X-FILE View

  1. DirectX9 までは、標準で X-FILE を入力する機能がサポートされていました。
    DirectX10 では、X-FILE が使えなくなった代わりに sdkmesh が使えるようになりました。
    ところが Windows8(8.1)では、このような標準モデルは存在しないようです。
    そこで X-FILE を入力して描画するプログラムを作成します。
  2. X-FILE の形式は多種多様で、一筋縄では行きません。
    このプログラムで描画出来るモデルは、DirectX9 などで自動的に生成される[頂点座標+法線]のモデルです。

プロジェクトの作成

  1. Windows8.1 で [DirectX アプリケーション] を自動生成します。
    TEXT 描画(2D描画)を削除して下さい。
  2. Content\ に格納されている次のファイルを修正して下さい。
    修正箇所は、この後に説明しています。
  3. X-FILE をプロジェクトに組み込みます。
    モデル(BOXP3.x ConePN.x gal2.x)は X-FILE Loader_1 からダウンロード出来ます。
    X-FILE はコンテンツとして認識されないので、プロパティから [コンテンツ/はい] に設定します。
  4. Shader を[頂点座標+法線]に対応したものに置き換えます。
    法線ベクトル を参照して SamplePixelShader.hlsl と SampleVertexShader.hlsl を修正して下さい。
    ShaderStructures.h に VertexPosition を追加して下さい。
  5. コンパイルして実行するとモデルが回転しながら描画されます。
    カラーモデルの描画は X-FILE Loader_2 を参照して下さい。
    モデルのサイズに合わせて、カメラの位置を調整して下さい。
        static const XMVECTORF32 eye = { 0.0f, 0.7f, 2.0f, 0.0f };
    

プログラムの説明

  1. X-FILE は普通 Shift_jis でタイプされています。
    X-FILE Loader_1 では Shift_jis をそのまま STL の string に入力しています。
    今回は X-FILE を STL の wstring に変換して入力しました。
    X-FILE はプログラムと同じインストールフォルダーに格納して StorageFile で入力します。
    入力した TEXT(String^ str) をパラメータにして SetText(str); を呼び出します。
        //★ ReadText X-FILE
        StorageFolder^ folder =
            Windows::ApplicationModel::Package::Current->InstalledLocation;
        //create_task(folder->GetFileAsync(L"BOXP3.x")).then([this](StorageFile^ file)
        create_task(folder->GetFileAsync(L"gal2.x")).then([this](StorageFile^ file)
        {
            return FileIO::ReadTextAsync(file);
        }).then([this](task<String^> previousTask)
        {
            try
            {
                String^ str = previousTask.get();
                SetText(str);
            }
            catch (...)
            {
                OutputDebugString(L"X-FILE not found");
            }
        });
    
    X-FILE の入力は C++ の install Folder Read を参照して下さい。
    STL の wstring は STL wstring を参照して下さい。
    このとき全角文字(漢字,かな)が含まれていると、エラーで中断します。
    必要ならば Text Editor の開発 を参照して UTF-8 に変換して下さい。
  2. SetText(str); では、渡された String^ str を行で切り分けて STL の vector<wstring> VT; に格納します。
        std::wstring    m_x;                //X-FILE TEXT
        vector<wstring> VT;                 //X-FILE を行で切り分け
        int             VT_size;            //VT の大きさ
    
    //★ 入力した X-FILE TEXT を受け取ってモデルを生成
    void Sample3DSceneRenderer::SetText(Platform::String^ text)
    {
        int num, pt, pw;
        m_x = text->Data();
    
        // String を行で切り分ける(m_x⇒VT)
        VT.clear();
        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);
        }
        VT.push_back(L"}\r\n");
        VT_size = VT.size();
    
  3. 次に Mesh { } と MeshNormals { } を解析してモデルを作成します。
    vector<DirectX::XMFLOAT3> m_pos;    // 頂点座標
    vector<DirectX::XMFLOAT3> m_norm;   // 法線ベクトル
    
    vector<unsigned short> m_idxP;      // 頂点 Index の並び(角付)
    vector<unsigned short> m_idxN;      // 法線 Index の並び(角付)
    vector<unsigned short> m_idxP3;     // 頂点 Index(3P) の並び
    vector<unsigned short> m_idxN3;     // 法線 Index(3P) の並び
    
    //★ 入力した X-FILE TEXT を受け取ってモデルを生成
    void Sample3DSceneRenderer::SetText(Platform::String^ text)
    {
           ・・・
    
        // 頂点座標を取得
        m_pos.clear();
        m_Line = m_Top;
        if (SetXMFLOAT3(L"Mesh ", &m_pos))
        {
            SetShort(&m_idxP);
        }
        else
        {   OutputDebugString(L"Mesh File  Format Error\r\n");
            return;
        }
    
        // 法線を取得
        m_norm.clear();
        m_Line = m_Top;
        if (SetXMFLOAT3(L"MeshNormals ", &m_norm))
        {
            SetShort(&m_idxN);
        }
    
        // N角ポリゴン ⇒ 3角ポリゴン
        PX_P3(m_idxP, &m_idxP3);
        if (m_idxN.size() > 2)
        {
            PX_P3(m_idxN, &m_idxN3);
        }
    
        unsigned i;
        // 頂点データとインデックスデータを作成
        m_indexCount = m_idxP3.size();
        VertexPosition *Vertices = new VertexPosition[m_indexCount];
        unsigned short *Indices = new unsigned short[m_indexCount];
    
        for(i=0; i<m_indexCount; i++)
        {
            Vertices[i].pos = m_pos[m_idxP3[i]];
            if (m_idxN3.size()>i)   Vertices[i].norm = m_norm[m_idxN3[i]];
            Indices[i]= i;  //IndexはVerticesの順番と一致
        }
    
           ・・・
    
  4. key を検索して f3 に三次元座標を設定する SetXMFLOAT3() 関数です。
    bool Sample3DSceneRenderer::SetXMFLOAT3(String^ key, vector<DirectX::XMFLOAT3> *f3)
    {
        int     num,i;
        float   x, y, z;
        DirectX::XMFLOAT3 wf3;
    
        if (Search(key)==false) return false;
        m_Line++;
        m_Col = 0;
        Token();
        num = _wtoi(Word.data());
        if (num<3)
        {   return false;
        }
    
        // 頂点座標を f3 に設定
        for (i = 0; i<num; i++)
        {
            Token();
            x = (float)_wtof(Word.data());
            Token();
            y = (float)_wtof(Word.data());
            Token();
            z = (float)_wtof(Word.data());
            wf3 = XMFLOAT3(x, y, z);
            f3->push_back(wf3);
        }
        return true;
    }
    
  5. 現在の位置から Index(unsigned short) を val に格納する SetShort() 関数です。
    説明が足らない所は Normal ConeX-FILE Loader_1 を参照して下さい。
    bool Sample3DSceneRenderer::SetShort(vector<unsigned short> *val)
    {
        int i,j,cn,num;
        unsigned short wk;
    
        Token();
        num = _wtoi(Word.data());
        if (num<3)
        {   return false;
        }
        for(i=0; i<num; i++)
        {
            Token();
            cn= _wtoi(Word.data());
            val->push_back(cn);
            for(j=0; j<cn; j++)
            {
                Token();
                wk = _wtoi(Word.data());
                val->push_back(wk);
            }
        }
        return true;
    }
    

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