Win10 OBJ Preset Color Model

Windows10(Store) DirectX3D で OBJ Preset Color Model を描画します。

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

プログラムの説明

  1. Windows10(ストアアプリ)で Wavefront の「頂点+法線+色」が設定されたモデルを描画します。
    Win10 OBJ Model では頂点座標だけのモデルを描画しました。
    Win10 OBJ Normal Model では「頂点+法線」のモデルを描画しました。
    今回はポリゴン(面)に色が設定されたモデルを描画します。
  2. 「頂点+法線+色」のモデルを定義した cube.obj です。プロジェクトには cube.txt の名前で組み込みます。
    本来はマテリアル(色やテクスチャ)の設定は *.obj とは別のファイル(*.mtl)に記述します。
    今回は *.mtl を読み込まずに、16色カラーをプリセットしてカラーモデルを描画します。
    usemtl で指定された white, yellow などがポリゴン(面)の色設定です。
    # cube Color Model
    g
    v -1 -1 -1
    v 1 -1 -1
    v -1 1 -1
    v 1 1 -1
    v -1 -1 1
    v 1 -1 1
    v -1 1 1
    v 1 1 1
    
    g face1
    usemtl white
    f 1 3 4 2
    g face2
    usemtl yellow
    f 1 5 7 3
    g face3
    usemtl red
    f 2 4 8 6
    g face4
    usemtl green
    f 1 2 6 5
    g face5
    usemtl blue
    f 3 7 8 4
    g face6
    usemtl auua
    f 5 6 8 7
    
  3. マテリアル(色)を定義する構造体です。
    *.mtl ファイルには多くのアイテムが定義されているのですが、今回は matID と Kd だけを定義します。
    // Material 構造体(MTBL)
    struct  Mat
    {   string  matID;  //Mat ID
        float3  Kd;     //ディフューズ(ディフューズの色)
    };
    
  4. Constructor で Material 構造体に16色カラーをプリセットします。
    OBJ モデルの usemtl で指定される色は matID で登録されていなければなりません。
        vector<Mat>     MTBL;       // Material 構造体(MTBL)
        uint16          MT_num;     // 参照中の MT 番号
    
    Load_OBJ::Load_OBJ(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
        m_deviceResources(deviceResources)
    {
        MT_num = 0;
        Mat premat[16] = { { "white",  f3(1.0f, 1.0f, 1.0f) },
                           { "silver", f3(0.7f, 0.7f, 0.7f) },
                           { "grey",   f3(0.5f, 0.5f, 0.5f) },
                           { "black",  f3(0.0f, 0.0f, 0.0f) },
                           { "lime",   f3(0.0f, 1.0f, 0.0f) },
                           { "olive",  f3(0.5f, 0.5f, 0.0f) },
                           { "green",  f3(0.0f, 0.5f, 0.0f) },
                           { "teal",   f3(0.0f, 0.5f, 0.5f) },
                           { "auua",   f3(0.0f, 1.0f, 1.0f) },
                           { "red",    f3(1.0f, 0.0f, 0.0f) },
                           { "maroon", f3(0.5f, 0.0f, 0.0f) },
                           { "yellow", f3(1.0f, 1.0f, 0.0f) },
                           { "blue",   f3(0.0f, 0.0f, 1.0f) },
                           { "navy",   f3(0.0f, 0.0f, 0.5f) },
                           { "purple", f3(0.5f, 0.0f, 0.5f) },
                           { "fuchsia",f3(1.0f, 0.0f, 1.0f) } };
        MTBL.clear();
        for(uint16 k=0; k<16; k++)  MTBL.push_back(premat[k]);
    }
    
  5. このプログラムで面倒なのが usemtl を検出する毎に色を切り替えて頂点データを作成しなければならないことです。
    そこで m_Vertex と m_Index の領域を vector で定義して追加登録が出来るようにしています。
    AddVertex() 関数がマテリアルが切り替わったときに頂点データを追加する関数です。
        vector<VertexPosition>  m_Vertex;
        vector<uint16>          m_Index;
    
  6. OBJ ファイルの最後まで到達すると m_Vertex と m_Index を参照して CreateModel() 関数でモデルを生成します。
        CreateModel(vertexBuffer, indexBuffer, indexCount);
    
  7. プロジェクトには cube.txt(ページの最初に掲載した cube.obj)を格納して下さい。
    cube.txt を読み込むので BasicReaderWriter も組み込みます。
    今回描画するモデルは「頂点+法線+4色」モデルなので、Shader を入れ替えて下さい。
    また Sample3DSceneRenderer.cpp の vertexDesc [] も修正します。
        static 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 }, 
        };
    
  8. Load_OBJ Class のソースコードは Win10 OBJ Color Model を参照して修正して下さい。
    このプロジェクトは *.mtl ファイルを入力してマテリアルを設定しているのですが、参考になると思います。
  9. プログラムを作成するために補足説明をします。
    vector<Mat> で MTBL を定義します。
    m_Vertex と m_Index を vector で定義します。
    法線ベクトルはプログラムで計算するので、登録するのは頂点座標(v)と頂点 Index(f) だけです。
            vector<Mat>     MTBL;       // Material 構造体(MTBL)
            uint16          MT_num;     // 参照中の MT 番号
    
            vector<float3>  m_pos;      // 頂点座標
            vector<uint16>  m_idxP;     // 頂点 Index の並び(角付)
            vector<uint16>  m_idxP3;    // 頂点 Index(3P) の並び
    
            vector<VertexPosition>  m_Vertex;
            vector<uint16>          m_Index;
    
  10. OBJ ファイルで本当に処理しなければならないのは v 形式と f 形式と usemtl 形式だけです。
    v 形式のときは m_pos に追加します。
    f 形式のときは m_idxP に追加します。
    usemtl 形式が検出される毎に m_idxP に蓄積されたポリゴンを AddVertex() 関数で生成します。
    ChangeMat() がマテリアル(色)を切り替える関数です。
        for (m_pt = 0; m_pt < VT_size; m_pt++)
        {
            Token(VT[m_pt]);
            if (TK.size() < 1 || TK[0][0]=='#') continue;
    
            if (TK[0] == "g")
            {
                if (TK.size()>1)    m_group = TK[1];
            }
            else    if (TK[0] == "usemtl")
            {
                if (m_idxP.size()>0)
                {   AddVertex();
                    ChangeMat(TK[1]);
                }
            }
            else    if (TK[0] == "v")
            {
                wf3.x = (float)atof((char *)TK[1].data());
                wf3.y = (float)atof((char *)TK[2].data());
                wf3.z = (float)atof((char *)TK[3].data());
                m_pos.push_back(wf3);
            }
            else    if (TK[0] == "f")
            {
                uint32  nn;
                nn = TK.size() - 1;
                m_idxP.push_back(nn);
                for(unsigned j=1; j<=nn; j++)
                {
                    num = (unsigned short)atoi((char *)TK[j].data());
                    m_idxP.push_back(num);
                }
            }
            else    Debug((char *)VT[m_pt].data());
        }
        if (m_idxP.size()>0)
        {   AddVertex();
        }
        CreateModel(vertexBuffer, indexBuffer, indexCount);
    }
    
  11. m_idxP に蓄積されたポリゴンを生成する AddVertex() 関数です。
    // Vertex を追加
    void Load_OBJ::AddVertex()
    {
        // 4角ポリゴン ⇒ 3角ポリゴン
        PX_P3(m_idxP, &m_idxP3);
        // 頂点データとインデックスデータを作成
        uint32 vtx_size = m_idxP3.size();
        VertexPosition Vertex;
        uint16 bs = (uint16)m_Index.size();
    
        for(uint32 i=0; i<vtx_size; i++)
        {
            uint32  idx = m_idxP3[i]-1;
            if (idx<m_pos.size())
            {   Vertex.pos.x = m_pos[idx].x;
                Vertex.pos.y = m_pos[idx].y;
                Vertex.pos.z = m_pos[idx].z;
            }
            else    Debug(L"m_pos Index Error", idx);
    
            Vertex.color.x = MTBL[MT_num].Kd.x;
            Vertex.color.y = MTBL[MT_num].Kd.y;
            Vertex.color.z = MTBL[MT_num].Kd.z;
            Vertex.color.w = 1.0f;
    
            m_Vertex.push_back(Vertex);
            m_Index.push_back(bs + i);
        }
    }
    
  12. マテリアル(色)を切り替える ChangeMat() 関数です。
    見つからないときは MT_num を 0("white") に設定します。
    // マテリアルの切り替え
    void Load_OBJ::ChangeMat(string matname)
    {
        m_idxP.clear();
        m_idxP3.clear();
        for(MT_num=0; MT_num<MTBL.size(); MT_num++)
        {   if (MTBL[MT_num].matID == matname)  break;
        }
        if (MT_num>=MTBL.size())    MT_num = 0;
    }
    

[Previous Chapter ↑] Win10 OBJ Model

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