Load_X Color

X-FILE を「頂点+3色」でロードする Class を作成します。
カラーが設定されていれば、法線の無いモデルやテクスチャが設定されているモデルもロードすることが出来ます。

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

プログラムの説明

  1. X_Loader Class はシェーダ関係や Draw() 関数まで含んでいるので、1体のモデルを描画するには最適ですが、モデルを組み合わせる場合には向いていません。
    そこで Win10 Create Color に準じて X-FILE を「頂点+3色」でロードする Load_X Class を作成することにします。
    テクスチャが設定されているモデルや法線が設定されている設定されているモデルも「頂点+3色」モードでロードされます。
    ソースコードは長いのですが、このページからコピー&ペーストするだけなので簡単です。
  2. 自動生成されるプロジェクトの Sample3DSceneRenderer に Load_X Class を組み込んで描画します。
    DirectX 11 アプリ(ユニバーサル Windows)のプロジェクトを生成して下さい。
    生成したアプリは「頂点+3色」のモデルを描画するプロジェクトなのでシェーダー関係はそのまま使えます。
    Load_X.h(.cpp) のソースコードはこの後に掲載します。
    プロジェクトを生成は Win10 Template を参照して下さい。
  3. "Ball.x" を直接プロジェクトに加えます。
    カラーが設定されていれば、モデル(X-FILE)は問わないので適当なものを調達してきて下さい。
    但し、X-FILE の仕様は多種多様で適合しない場合もあるので注意して下さい。
    X-FILE を右クリックしてコンテンツを True に設定します。
  4. Sample3DSceneRenderer.h で Load_X.h を組み込んで、Load_X Class の領域を定義します。
    #include "Load_X.h"
    
        Load_X  *model;
    
  5. Sample3DSceneRenderer.cpp の修正です。
    CreateDeviceDependentResources() 関数で X-FILE をロードします。
    「両方のシェーダーの読み込みが完了したら、メッシュを作成します。」以降を書き換えて下さい。
    プロジェクトに加えられた "Ball.x" をロードして &m_vertexBuffer, &m_indexBuffer, &m_indexCount に設定します。
    void Sample3DSceneRenderer::CreateDeviceDependentResources()
    {
        ・・・
    
        // 両方のシェーダーの読み込みが完了したら、メッシュを作成します。
        auto createCubeTask = (createPSTask && createVSTask).then([this] () {
            model = new Load_X(m_deviceResources);
            model->Load("Ball.x", &m_vertexBuffer, &m_indexBuffer, &m_indexCount);
        });
    
        // メッシュが読み込まれたら、オブジェクトを描画する準備が完了します。
        createCubeTask.then([this] () {
            m_loadingComplete = true;
        });
    }
    
  6. Rotate() 関数でモデルを回転しているのですが、修正する必要はありません。
    X-FILE ではポリゴンが裏返るので Render() 関数でカリングモードを設定して描画します。
    m_vertexBuffer, m_indexBuffer, m_indexCount にモデルがロードされているので、実行すれば描画されるはずです。
    モデルが大きすぎる(小さすぎる)ときは eye のZ座標で調整して下さい。
        // カリングを設定
        model->SetCullMode();
    
        // オブジェクトを描画します。
        context->DrawIndexed(m_indexCount, 0, 0);
    
  7. Load_X.h のソースコードです。
    X-FILE を解析してモデルのデータを作成するための関数や領域を定義します。
    色(マテリアル)はポリゴン(面)ごとに設定されていて結構解析が面倒です。
    float3 を使っていますが、これらの構造体は "BasicMath.h" で定義されています。
    "BasicMath.h" は Windows10 DirectX Library に掲載しているので参考にして下さい。
    #pragma once
    
    #include <vector>
    #include "..\Common\DeviceResources.h"
    #include "..\Common\StepTimer.h"
    #include "ShaderStructures.h"
    #include "BasicReaderWriter.h"
    #include "BasicMath.h"
    
    using namespace std;
    using namespace Platform;
    
    // Face 構造体(FTBL)
    struct  Face
    {   int         Num;        // 頂点数
        vector<unsigned short>  Pos;    // 頂点 Index の並び
        int         Midx;       // Material(MTBL) Index(-1:指定なし)
    };
    // Polygon3 構造体(POL3)
    struct  Pol3
    {
        unsigned short  Pos[3];     // 頂点 Index の並び
        int     Midx;               // Material(MTBL) Index
    };
    // Material 構造体(MTBL)
    struct  Mat
    {   string              matName;
        float3              faceColor;
        float               power;
        float3              specularColor;
        float3              emissiveColor;
    };
    
    namespace App1
    {
        class Load_X
        {
        public:
            Load_X(const std::shared_ptr<DX::DeviceResources>& deviceResources);
            void Load(
                _In_  Platform::String ^str,
                _Out_ ID3D11Buffer **vertexBuffer,
                _Out_ ID3D11Buffer **indexBuffer,
                _Out_ uint32 *indexCount);
            void SetCullMode();
    
        private:
            std::shared_ptr<DX::DeviceResources> m_deviceResources;
            ID3D11RasterizerState  *m_RasterizerState;
    
            //★ X-FILE の領域
            std::string     m_x;            // X-FILE TEXT
            vector<string>  VT;             // X-FILE を行で切り分け
            int             VT_size;        // VT の大きさ
            vector<Face>    FTBL;           // Face Table
            vector<Pol3>    POL3;           // Polygon3 Table
            vector<Mat>     MTBL;           // Material Table
    
            vector<float3> m_pos;           // 頂点座標
            int     m_Line, m_Col, m_Top;
            string  Word;
            bool    m_normflag;             // 法線の取得フラグ
    
            bool Search(char *key);
            void Token();
            bool LineToken();
            bool Setfloat3(char *key, vector<float3> *f3);
            bool SetFTBL();
            void Convt_3P(bool flg);
            void SetMTBL();
            void MatList();
        };
    }
    
  8. Load_X.cpp のソースコードです。
    Load() 関数でモデル(X-FILE)を解析して vertexBuffer, indexBuffer, indexCount に設定します。
    掲載されていない関数は Windows10 DirectX Library を参照して下さい。
    カラーモデル(X-FILE)の解析は Win10 ColorModel を参照して下さい。
    SetCullMode() はポリゴンが裏返るとき、カリングを設定する関数です。
    // Color モデル(pos + color)を描画
    #include "pch.h"
    #include "..\Common\DirectXHelper.h"
    #include "Load_X.h"
    
    using namespace App1;
    using namespace DirectX;
    using namespace Windows::Foundation;
    
    Load_X::Load_X(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
        m_deviceResources(deviceResources)
    {
    }
    
    // Load X-FILE
    void Load_X::Load(
        _In_ Platform::String ^str,
        _Out_ ID3D11Buffer **vertexBuffer,
        _Out_ ID3D11Buffer **indexBuffer,
        _Out_ uint32 *indexCount)
    {
        VT.clear();
        FTBL.clear();
        POL3.clear();
        MTBL.clear();
        m_pos.clear();
    
        // ★X-FILE を入力して解析
        BasicReaderWriter^ reader = ref new BasicReaderWriter();
        Array<byte>^ buf = reader->ReadData(str);
    
        int num, pt, pw;
        char *w;
    
        w = (char *)&(buf[0]);
        m_x = w;
    
        // String を行で切り分ける(m_x⇒VT)
        VT.clear();
        num = m_x.size();
        for (pt = 0; pt < num;)
        {
            pw = pt;
            for (pt++; pt < num && m_x[pt] != '\n'; pt++);
            if (pt >= num)  break;
            pt++;
            Word = Word.assign(m_x, pw, pt - pw);
            VT.push_back(Word);
        }
        VT.push_back("}\r\n");
        VT_size = VT.size();
    
        // Header Check("xof 0303txt 0032")
        m_Col = VT[0].find("xof");
        if (m_Col == -1)
        {
            return;
        }
        m_Col = VT[0].find("txt");
        if (m_Col == -1)
        {
            return;
        }
    
        // template をスキップ
        m_Line = 1;
        m_Col = 0;
        while (true)
        {
            Token();
            if (Word != "template") break;
            Search("}");
            m_Line++;
        }
        m_Top = m_Line;
    
        // Material(MTBL)を取得
        SetMTBL();
    
        // 頂点座標を取得
        m_pos.clear();
        m_Line = m_Top;
        if (Setfloat3("Mesh ", &m_pos))
        {
            SetFTBL();
        }
        else
        {
            OutputDebugString(L"Mesh File  Format Error\r\n");
            return;
        }
        // MeshMaterialList を取得
        MatList();
    
        // Face 構造体の FTBL ⇒ POL3
        Convt_3P(m_normflag);
    
        //★ pos, norm, color を組み合わせて、モデルの頂点座標を作成
        *indexCount = POL3.size() * 3;
        VertexPositionColor *Vertices = new VertexPositionColor[*indexCount];
        unsigned short *Indices = new unsigned short[*indexCount];
    
        for (unsigned i = 0; i < POL3.size(); i++)
        {
            for (unsigned j = 0; j < 3; j++)
            {
                Vertices[i * 3 + j].pos.x = m_pos[POL3[i].Pos[j]].x;
                Vertices[i * 3 + j].pos.y = m_pos[POL3[i].Pos[j]].y;
                Vertices[i * 3 + j].pos.z = m_pos[POL3[i].Pos[j]].z;
    
                // マテリアル(色)の設定(idx==-1 のときは未設定)
                int idx = POL3[i].Midx;
                if (idx != -1)
                {
                    Vertices[i * 3 + j].color.x = MTBL[idx].faceColor.x;
                    Vertices[i * 3 + j].color.y = MTBL[idx].faceColor.y;
                    Vertices[i * 3 + j].color.z = MTBL[idx].faceColor.z;
                }
                else
                {
                    Vertices[i * 3 + j].color.x = 1.0f;
                    Vertices[i * 3 + j].color.y = 1.0f;
                    Vertices[i * 3 + j].color.z = 1.0f;
                }
                Indices[i * 3 + j] = i * 3 + j;
            }
        }
    
        // メッシュを生成
        D3D11_SUBRESOURCE_DATA vertexBufferData = { 0 };
        vertexBufferData.pSysMem = Vertices;
        vertexBufferData.SysMemPitch = 0;
        vertexBufferData.SysMemSlicePitch = 0;
        CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(VertexPositionColor)*(*indexCount), D3D11_BIND_VERTEX_BUFFER);
        DX::ThrowIfFailed(
            m_deviceResources->GetD3DDevice()->CreateBuffer(
                &vertexBufferDesc, &vertexBufferData, vertexBuffer));
    
        // インデックスを生成
        D3D11_SUBRESOURCE_DATA indexBufferData = { 0 };
        indexBufferData.pSysMem = Indices;
        indexBufferData.SysMemPitch = 0;
        indexBufferData.SysMemSlicePitch = 0;
        CD3D11_BUFFER_DESC indexBufferDesc(sizeof(unsigned short)*(*indexCount), D3D11_BIND_INDEX_BUFFER);
        DX::ThrowIfFailed(
            m_deviceResources->GetD3DDevice()->CreateBuffer(
                &indexBufferDesc, &indexBufferData, indexBuffer));
    
        // 領域の解放
        if (Vertices)   delete Vertices;
        if (Indices)    delete Indices;
    
        // カリング設定
        D3D11_RASTERIZER_DESC rasterizerDesc;
        ZeroMemory( &rasterizerDesc, sizeof( D3D11_RASTERIZER_DESC ) );
        //rasterizerDesc.CullMode = D3D11_CULL_BACK;
        rasterizerDesc.CullMode = D3D11_CULL_FRONT;
        rasterizerDesc.FillMode = D3D11_FILL_SOLID;
        rasterizerDesc.DepthClipEnable = FALSE;
        rasterizerDesc.MultisampleEnable = TRUE;
        rasterizerDesc.DepthBiasClamp = 0;
        rasterizerDesc.SlopeScaledDepthBias = 0;
        DX::ThrowIfFailed(
            m_deviceResources->GetD3DDevice()->CreateRasterizerState(
                &rasterizerDesc, &m_RasterizerState));
    }
    
    //★ "Material" で始まる行を検索(先頭から順に並ぶ)
    void Load_X::SetMTBL()
    {   Mat     mat;
    
        MTBL.clear();
        m_Line= m_Top;
        while(m_Line<VT_size)
        {   Search("Material ");
            if (m_Col==-1)  break;
            LineToken();
            LineToken();        // 二回目で名前を取得
            mat.matName= Word;
            // "Material" に続く色を格納する
            m_Line++;
            m_Col= 0;
            Token();
            mat.faceColor.x= (float)atof(Word.data());
            Token();
            mat.faceColor.y= (float)atof(Word.data());
            Token();
            mat.faceColor.z= (float)atof(Word.data());
            Token();
            MTBL.push_back(mat);
        }
    }
    
    //★ "MeshMaterialList" で始まる行を検索
    void Load_X::MatList()
    {
        vector<int> fm;     // Face Material
        vector<int> midx;   // Material(MTBL) の Index
        int         fcnt,num,i;
        unsigned    j;
    
        m_Line= m_Top;
        Search("MeshMaterialList ");
        if (m_Col==-1)  return;
        m_Line++;
        m_Col= 0;
        Token();
        num= atoi(Word.data());
        Token();
        fcnt= atoi(Word.data());
        if (FTBL.size()!=fcnt)
        {   return;  }
        // Face に対応する Material番号を設定
        for(i=0; i<fcnt; i++)
        {   Token();
            fm.push_back(atoi(Word.data()));
        }
        // Material 名で検索して、Material Index を設定
        for(i=0; i<num; i++)
        {   Token();
            if (Word!="Material")
            {
                for(j=0; j<MTBL.size(); j++)
                {   if (MTBL[j].matName==Word)  break;
                }
                if (j<MTBL.size())  midx.push_back(j);
                else    midx.push_back(j);
            }
            else    midx.push_back(i);
            Search("}");
        }
    
        for(i=0; i<fcnt; i++)
        {   FTBL[i].Midx= midx[fm[i]];  }
    }
    
    //★ 頂点に続く Index を vector<Face> に格納する
    bool Load_X::SetFTBL()
    {
        Face    face;
        int     i,j,num;
        unsigned short wk;
    
        FTBL.clear();
        Token();
        num = atoi(Word.data());
        if (num<3)
        {   return false;   }
    
        face.Midx= -1;
        for(i=0; i<num; i++)
        {
            Token();
            face.Num= atoi(Word.data());
            face.Pos.clear();
            for(j=0; j<face.Num; j++)
            {
                Token();
                wk= atoi(Word.data());
                face.Pos.push_back(wk);
            }
            FTBL.push_back(face);
        }
        return true;
    }
    
    // vector<Face> FTBL ⇒ vector<Pol3> POL3  TRIANGLELIST に変換
    // bool flg は法線ベクトルが定義されているか否かの区別
    void Load_X::Convt_3P(bool flg)
    {   Pol3   pol3;
        int    i, j;
    
        for(i=0; i<(int)FTBL.size(); i++)
        {
            pol3.Midx= FTBL[i].Midx;
            switch(FTBL[i].Num)
            {   case 3:     //TRIANGLELIST
                    pol3.Pos[0]= FTBL[i].Pos[0];
                    pol3.Pos[1]= FTBL[i].Pos[1];
                    pol3.Pos[2]= FTBL[i].Pos[2];
                    POL3.push_back(pol3);
                    break;
                case 4:     //TRIANGLESTRIP 4
                    pol3.Pos[0]= FTBL[i].Pos[0];
                    pol3.Pos[1]= FTBL[i].Pos[1];
                    pol3.Pos[2]= FTBL[i].Pos[2];
                    POL3.push_back(pol3);
                    pol3.Pos[0]= FTBL[i].Pos[0];
                    pol3.Pos[1]= FTBL[i].Pos[2];
                    pol3.Pos[2]= FTBL[i].Pos[3];
                    POL3.push_back(pol3);
                    break;
                default:    //TRIANGLEFAN
                    for(j=0; j<=FTBL[i].Num-3; j++)
                    {
                        pol3.Pos[0]= FTBL[i].Pos[0];
                        pol3.Pos[1]= FTBL[i].Pos[j+1];
                        pol3.Pos[2]= FTBL[i].Pos[j+2];
                        POL3.push_back(pol3);
                    }
                    break;
            }
        }
    }
    
    // カリングの設定
    void Load_X:: SetCullMode()
    {
        auto context = m_deviceResources->GetD3DDeviceContext();
        context->RSSetState(m_RasterizerState);
    }
    

[Next Chapter ↓] X-FILE を親子で回転する
[Previous Chapter ↑] Win10 Men4 2Model

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