Load_X Norm

Load_X Normal

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

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

プログラムの説明

  1. Load_X Color に続いて X-FILE を「頂点+法線」でロードする Class を作成します。
    頂点座標だけのモデルやテクスチャが設定されているモデルもロード出来るので大抵の X-FILE に対応しています。
    但し、X-FILE の仕様は多種多様で適合しない場合もあるので注意して下さい。
    Load_X Norm のソースコードは Load_X Color よりも簡単です。
    「頂点座標+法線」モデルの解析は X-FILE Loader_1 などを参照して下さい。
  2. 自動生成されるプロジェクトの Sample3DSceneRenderer に Load_X Class を組み込んで描画します。
    DirectX 11 アプリ(ユニバーサル Windows)のプロジェクトを生成して下さい。
    生成したアプリは「頂点+カラー」のモデルを描画するプロジェクトなのでシェーダー関係は「頂点+法線」の物に入れ替えます。
    X-FILE を解析する Load_X.h(.cpp) のソースコードはこの後に掲載します。
    プロジェクトを生成は Win10 Template を参照して下さい。
  3. X-FILE("gal2.x") をプロジェクトに加えます。
    "gal2.x" は X Model からダウンロードできます。
    X-FILE を右クリックしてコンテンツを True に設定します。
  4. Sample3DSceneRenderer.h に Load_X.h を組み込んで、Load_X Class の領域を定義します。
    #include "Load_X.h"
    
        Load_X  *model;
    
  5. 頂点データの定義を "COLOR" から "NORMAL" に変更して下さい。
            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 },
            };
    
  6. CreateDeviceDependentResources() 関数で X-FILE をロードします。
    「両方のシェーダーの読み込みが完了したら、メッシュを作成します。」以降を書き換えて下さい。
    プロジェクトに加えられた "gal2.x" をロードして &m_vertexBuffer, &m_indexBuffer, &m_indexCount に設定します。
    void Sample3DSceneRenderer::CreateDeviceDependentResources()
    {
        ・・・
    
        // 両方のシェーダーの読み込みが完了したら、メッシュを作成します。
        auto createCubeTask = (createPSTask && createVSTask).then([this] () {
            model = new Load_X(m_deviceResources);
            model->Load("gal2.x", &m_vertexBuffer, &m_indexBuffer, &m_indexCount);
        });
    
        // メッシュが読み込まれたら、オブジェクトを描画する準備が完了します。
        createCubeTask.then([this] () {
            m_loadingComplete = true;
        });
    }
    
  7. Rotate() 関数でモデルを回転して、Render() 関数で描画します。
    モデルが大きすぎる(小さすぎる)ときは eye のZ座標で調整して下さい。
    X-FILE ではポリゴンが裏返るのでカリングモードを設定して描画します。
        // カリングを設定
        model->SetCullMode();
    
        // オブジェクトを描画します。
        context->DrawIndexed(m_indexCount, 0, 0);
    
  8. Load_X.h のソースコードです。
    X-FILE を解析してモデルのデータを作成するための関数や領域を定義します。
    Color Model に比べてソースコードは簡単です。
    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;
    
    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<float3> m_pos;               // 頂点座標
            vector<float3>  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) の並び
            int     m_Line, m_Col, m_Top;
            string  Word;
            bool    m_normflag;                 // 法線の取得フラグ
    
            bool Setfloat3(char *key, vector<float3> *f3);
            bool SetShort(vector<unsigned short> *val);
            void PX_P3(vector<unsigned short> PX, vector<unsigned short> *P3);
            void ComputeNorm(VertexPosition *Vertices, int siz);
            bool Search(char *);
            void Token();
        };
    }
    
  9. Load_X.cpp のソースコードです。
    Load() 関数でモデル(X-FILE)を解析して vertexBuffer, indexBuffer, indexCount に設定します。
    掲載されていない関数は Windows10 DirectX Library を参照して下さい。
    Normal モデル(X-FILE)の解析は Win10 NormModel を参照して下さい。
    SetCullMode() はポリゴンが裏返るとき、カリングを設定する関数です。
    // Normal モデル(pos + norm)をロード
    #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)
    {
        //★ X-FILE を入力して解析
        int     num;
        int     pt,pw;
        byte    wk;
    
        VT.clear();
        m_pos.clear();
        m_norm.clear();
        m_idxP.clear();
        m_idxN.clear();
        m_idxP3.clear();
        m_idxN3.clear();
    
        BasicReaderWriter^ reader = ref new BasicReaderWriter();
        Platform::Array<byte>^ buf = reader->ReadData(str);
    
        // X-FILE を行で切り分けて vector<string> VT に格納
        num= buf->Length;
        for(pt=0; pt<num; )
        {   pw= pt;
            for(pt++; pt<num && buf->Data[pt]!=0x0A; pt++);
            if (pt>=num)    break;
            pt++;
            wk= buf->Data[pt];
            buf->Data[pt]= 0x00;
            VT.push_back((char *)buf->Data+pw);
            buf->Data[pt]= wk;
        }
        VT.push_back("}\r\n");
        VT_size= VT.size();
    
        // Header Check("xof 0303txt 0032")
        m_Col= VT[0].find("xof");
        if (m_Col==-1)
        {   OutputDebugString(L"Invalid  Mesh File");
            return;
        }
        m_Col= VT[0].find("txt");
        if (m_Col==-1)
        {   OutputDebugString(L"Mesh File  Format Error");
            return;
        }
    
        // template をスキップ
        m_Line= 1;
        m_Col= 0;
        while(true)
        {   Token();
            if (_strnicmp((char *)Word.data(),"template",8)!=0) break;
            Search("}");
            m_Line++;
        }
        m_Top= m_Line;
    
        // 頂点座標を取得
        m_Line = m_Top;
        if (Setfloat3("Mesh ", &m_pos))
        {
            SetShort(&m_idxP);
        }
        else
        {
            OutputDebugString(L"Mesh File  Format Error");
            return;
        }
    
        // 法線を取得
        m_Line = m_Top;
        if (Setfloat3("MeshNormals ", &m_norm))
        {   SetShort(&m_idxN);  }
    
        // N角ポリゴン ⇒ 3角ポリゴン
        PX_P3(m_idxP, &m_idxP3);
        PX_P3(m_idxN, &m_idxN3);
    
        // 頂点データとインデックスデータを作成
        unsigned vtx_size = m_idxP3.size();
        VertexPosition *Vertices = new VertexPosition[vtx_size];
        unsigned short *Indices = new unsigned short[vtx_size];
    
        for(unsigned i=0; i<vtx_size; 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;
        }
    
        // 法線ベクトルの計算
        if (m_idxN3.size()<vtx_size)
            ComputeNorm(Vertices, vtx_size);
    
        *indexCount = m_idxP3.size();
        // メッシュを生成
        D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
        vertexBufferData.pSysMem = Vertices;
        vertexBufferData.SysMemPitch = 0;
        vertexBufferData.SysMemSlicePitch = 0;
        CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(VertexPosition)*(*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));
    }
    
    // ★XLoader 解析メソッド
    // カリングの設定
    void Load_X:: SetCullMode()
    {
        auto context = m_deviceResources->GetD3DDeviceContext();
        context->RSSetState(m_RasterizerState);
    }
    
  10. 少女モデルの簡単な描画プロジェクトは X2017 X Model を参照して下さい。
    ここからはプロジェクトの開発に必要なファイル一式を圧縮形式で提供しています。

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