Win10 ColorModel

Win10 ColorModel

Windows10 DirectX3D で X-FILE(Color Model) を組み込んで描画します。

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

プロジェクトの作成

  1. Windows10 で X FILE を直接組み込んでモデルを描画します。
    X FILE は DirectX の初期から使われている3Dモデルのファイル形式です。
    DirectX10 では sdkmesh が使われていたのですが、WindowsStore には専用のモデルファイルは存在しないようです。
    そこで私の WindowsStore DirectX のページでは X FILE を主として扱うことにします。
    これまでのページと違い、X FILE を解析してモデルデータを作成しなければならず、初心者には難しいかも知れません。 (^_^;)
    X-FILE の描画は Win10 XLoader のように Class XLoader を使う方法がお勧めです。
  2. Windows10 DirectX3D で Sample3DSceneRenderer に Color Model を組み込んで描画します。
    頂点+法線+テクスチャは対になっているのですが、色情報は MeshMaterialList で定義され、ポリゴン毎に設定されます。
    Face 構造体がポリゴンの定義で Midx; が Material(色情報)の設定です。
    // Face 構造体(FTBL)
    struct  Face
    {   int         Num;            // 頂点数
        vector<unsigned short>  Pos; // 頂点 Index の並び
        int         Midx;           // Material(MTBL) Index(-1:指定なし)
    };
    
    Midx からリンクする Material 構造体の faceColor がポリゴンの色です。
    // Material 構造体(MTBL)
    struct  Mat
    {   string              matName;
        float4              faceColor;
        float               power;
        float3              specularColor;
        float3              emissiveColor;
    };
    
    Win10 Template を参照して DirectX 11 アプリ(ユニバーサル Windows)を構築して下さい。
    カラーキューブが回転しながら描画され、FPS が表示されます。
    プロジェクトの名前は App1 になっています。
    CubeColor.x の頂点データは「頂点座標+カラー」なのでシェーダはそのまま使います。
  3. 次のファイルを Content\ のファイルに上書きして下さい。
    ソースコードは、このページの後半に掲載します。
    Content\Sample3DSceneRenderer.h
    Content\Sample3DSceneRenderer.cpp
  4. Win10 TextureBox から、次のファイルを Content\ に格納して下さい。
    App1 を選択して[追加][既存の項目]からプロジェクトに追加します。
    BasicReaderWriter はプロジェクトに組み込んだモデルのソースを取得するときに使います。
    Content\BasicReaderWriter.h
    Content\BasicReaderWriter.cpp
  5. X Model から CubeColor.x ダウンロードしてプロジェクトに組み込んで下さい。
    登録された X-FILE を右クリックしてコンテンツを True に設定して下さい。
    実は「頂点座標+カラー」で構成される X-FILE は珍しく、DirectX Store Program のために特別に作成したモデルです。
    また、このページのプログラムも CubeColor.x を描画するために新規に作成しました。
    一般的なカラーモデルは「頂点座標+法線ベクトル+カラー」で構成されています。
  6. ソースコードは長いのですが、プロジェクトの作成はこのページからコピー&ペーストするだけです。
    コンパイル&実行すると各面に色が設定された立方体が回転しながら描画されます。

ソースコード

  1. X FILE の描画を組み込んだ Sample3DSceneRenderer.h です。
    モデルから入力したソースを vector<string> VT; に行で切り分けて格納します。
    CubeColor.x のソースコードを見れば解るように、色(マテリアル)はポリゴン(面)ごとに設定されていて、結構解析が面倒です。
    この関係を解析するために Face 構造体, Material 構造体を使います。
    Polygon3 構造体は、多角形ポリゴンを三角形ポリゴンに変換するときに使用します。
    // 頂点+カラーのモデルを組み込んで描画する
    #pragma once
    
    #include "..\Common\DeviceResources.h"
    #include "..\Common\StepTimer.h"
    #include "ShaderStructures.h"
    #include "BasicReaderWriter.h"
    #include <vector>
    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;
        DirectX::XMFLOAT3       faceColor;
        float                   power;
        DirectX::XMFLOAT3       specularColor;
        DirectX::XMFLOAT3       emissiveColor;
    };
    
    namespace App1
    {
        class Sample3DSceneRenderer
        {
        public:
            Sample3DSceneRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources);
            void CreateDeviceDependentResources();
            void CreateWindowSizeDependentResources();
            void ReleaseDeviceDependentResources();
            void Update(DX::StepTimer const& timer);
            void Render();
            void StartTracking();
            void TrackingUpdate(float positionX);
            void StopTracking();
            bool IsTracking() { return m_tracking; }
    
        private:
            void Rotate(float radians);
    
        private:
            std::shared_ptr<DX::DeviceResources> m_Resources;
            ID3D11Device1           *m_Device;
            ID3D11DeviceContext1    *m_Context;
    
            // キューブ ジオメトリの Direct3D リソース。
            Microsoft::WRL::ComPtr<ID3D11InputLayout>   m_inputLayout;
            Microsoft::WRL::ComPtr<ID3D11Buffer>        m_vertexBuffer;
            Microsoft::WRL::ComPtr<ID3D11Buffer>        m_indexBuffer;
            Microsoft::WRL::ComPtr<ID3D11VertexShader>  m_vertexShader;
            Microsoft::WRL::ComPtr<ID3D11PixelShader>   m_pixelShader;
            Microsoft::WRL::ComPtr<ID3D11Buffer>        m_constantBuffer;
    
            ID3D11RasterizerState  *m_RasterizerState;
    
            // キューブ ジオメトリのシステム リソース。
            ModelViewProjectionConstantBuffer   m_constantBufferData;
            uint32  m_indexCount;
    
            // レンダリング ループで使用する変数。
            bool    m_loadingComplete;
            float   m_degreesPerSecond;
            bool    m_tracking;
    
            //★ 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<DirectX::XMFLOAT3> m_pos;    // 頂点座標
            int     m_Line, m_Col, m_Top;
            string  Word;
    
            void X_Byte(Array<byte>^ buf);
            void X_Model();
            bool Search(char *key);
            void Token();
            bool LineToken();
            bool SetXMFLOAT3(char *key, vector<DirectX::XMFLOAT3> *f3);
    
            void Debug(String^ msg, int n);
            void Debug(char *str);
    
            bool SetFTBL();
            void Convt_3P();
            void SetMTBL();
            void MatList();
        };
    }
    
  2. X FILE の描画を組み込んだ Sample3DSceneRenderer.cpp です。
    プロジェクトに組み込まれた X-FILE を解析してモデルデータを作成します。
    掲載されていない関数は Windows10 DirectX Library を参照して下さい。
    reader->ReadData("CubeColor.x") でモデルデータを取得しています。
    BasicReaderWriter は DirectX の基本入出力で、バイナリ(Byte)形式で読み込みます。
    一般的に X-FILE は Shift_jis でタイプされているので、buf には Shift_jis の TEXT DATA が読み込まれます。
        BasicReaderWriter^ reader = ref new BasicReaderWriter();
        Array<byte>^ buf = reader->ReadData("CubeColor.x");
        X_Byte(buf);
    

    // 頂点+カラーのモデルを組み込んで描画する
    #include "pch.h"
    #include "Sample3DSceneRenderer.h"
    #include "..\Common\DirectXHelper.h"
    #include <strsafe.h>
    
    using namespace App1;
    using namespace DirectX;
    using namespace Windows::Foundation;
    using namespace concurrency;
    using namespace Windows::Storage;
    
    Sample3DSceneRenderer::Sample3DSceneRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
        m_loadingComplete(false),
        m_degreesPerSecond(45),
        m_indexCount(0),
        m_tracking(false),
        m_Resources(deviceResources)
    {
        CreateDeviceDependentResources();
        CreateWindowSizeDependentResources();
        m_Device = m_Resources->GetD3DDevice();
        m_Context = m_Resources->GetD3DDeviceContext();
        BasicReaderWriter^ reader = ref new BasicReaderWriter();
        Array<byte>^ buf = reader->ReadData("CubeColor.x");     //モデルデータを取得 
        X_Byte(buf);
    }
    
    void Sample3DSceneRenderer::CreateWindowSizeDependentResources()
    {
        Size outputSize = m_Resources->GetOutputSize();
        float aspectRatio = outputSize.Width / outputSize.Height;
        float fovAngleY = 70.0f * XM_PI / 180.0f;
    
        if (aspectRatio < 1.0f)
        {   fovAngleY *= 2.0f;  }
    
        XMMATRIX perspectiveMatrix = XMMatrixPerspectiveFovRH(
            fovAngleY,
            aspectRatio,
            0.01f,
            100.0f
            );
    
        XMFLOAT4X4 orientation = m_Resources->GetOrientationTransform3D();
    
        XMMATRIX orientationMatrix = XMLoadFloat4x4(&orientation);
    
        XMStoreFloat4x4(
            &m_constantBufferData.projection,
            XMMatrixTranspose(perspectiveMatrix * orientationMatrix)
            );
    
        //static const XMVECTORF32 eye = { 0.0f, 0.7f, 2.0f, 0.0f };
        static const XMVECTORF32 eye = { 0.0f, 2.0f, 4.0f, 0.0f };
        static const XMVECTORF32 at = { 0.0f, -0.1f, 0.0f, 0.0f };
        static const XMVECTORF32 up = { 0.0f, 1.0f, 0.0f, 0.0f };
    
        XMStoreFloat4x4(&m_constantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up)));
    }
    
    void Sample3DSceneRenderer::Update(DX::StepTimer const& timer)
    {
        if (!m_tracking)
        {
            float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond);
            double totalRotation = timer.GetTotalSeconds() * radiansPerSecond;
            float radians = static_cast<float>(fmod(totalRotation, XM_2PI));
    
            Rotate(radians);
        }
    }
    
    void Sample3DSceneRenderer::Rotate(float radians)
    {
        //更新されたモデル マトリックスをシェーダーに渡す準備をします
        XMStoreFloat4x4(&m_constantBufferData.model, XMMatrixTranspose(XMMatrixRotationY(radians)));
    }
    
    void Sample3DSceneRenderer::StartTracking()
    {
        m_tracking = true;
    }
    
    void Sample3DSceneRenderer::TrackingUpdate(float positionX)
    {
        if (m_tracking)
        {
            float radians = XM_2PI * 2.0f * positionX / m_Resources->GetOutputSize().Width;
            Rotate(radians);
        }
    }
    
    void Sample3DSceneRenderer::StopTracking()
    {
        m_tracking = false;
    }
    
    // 頂点とピクセル シェーダーを使用して、1 つのフレームを描画します。
    void Sample3DSceneRenderer::Render()
    {
        if (!m_loadingComplete)
        {   return;  }
    
        // レンダー ターゲットを画面に設定します。
        ID3D11RenderTargetView *const targets[1] = { m_Resources->GetBackBufferRenderTargetView() };
        m_Context->OMSetRenderTargets(1, targets, m_Resources->GetDepthStencilView());
    
        // 定数バッファーを準備して、グラフィックス デバイスに送信します。
        m_Context->UpdateSubresource(
            m_constantBuffer.Get(),
            0,
            NULL,
            &m_constantBufferData,
            0,
            0
            );
    
        UINT stride = sizeof(VertexPositionColor);
        UINT offset = 0;
        m_Context->IASetVertexBuffers(
            0,
            1,
            m_vertexBuffer.GetAddressOf(),
            &stride,
            &offset
            );
    
        m_Context->IASetIndexBuffer(
            m_indexBuffer.Get(),
            DXGI_FORMAT_R16_UINT,
            0
            );
    
        // カリング設定
        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_Device->CreateRasterizerState(
                &rasterizerDesc, &m_RasterizerState));
    
        m_Context->RSSetState(m_RasterizerState);
    
        m_Context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    
        m_Context->IASetInputLayout(m_inputLayout.Get());
    
        // 頂点シェーダーをアタッチします。
        m_Context->VSSetShader(
            m_vertexShader.Get(),
            nullptr,
            0
            );
    
        // 定数バッファーをグラフィックス デバイスに送信します。
        m_Context->VSSetConstantBuffers(
            0,
            1,
            m_constantBuffer.GetAddressOf()
            );
    
        // ピクセル シェーダーをアタッチします。
        m_Context->PSSetShader(
            m_pixelShader.Get(),
            nullptr,
            0
            );
    
        // オブジェクトを描画します。
        m_Context->DrawIndexed(
            m_indexCount,
            0,
            0
            );
    }
    
    void Sample3DSceneRenderer::ReleaseDeviceDependentResources()
    {
        m_loadingComplete = false;
        m_vertexShader.Reset();
        m_inputLayout.Reset();
        m_pixelShader.Reset();
        m_constantBuffer.Reset();
        m_vertexBuffer.Reset();
        m_indexBuffer.Reset();
    }
    
    void Sample3DSceneRenderer::CreateDeviceDependentResources()
    {
        // シェーダーを非同期で読み込みます。
        auto loadVSTask = DX::ReadDataAsync(L"SampleVertexShader.cso");
        auto loadPSTask = DX::ReadDataAsync(L"SamplePixelShader.cso");
    
        // 頂点シェーダー ファイルを読み込んだ後、シェーダーと入力レイアウトを作成します。
        auto createVSTask = loadVSTask.then([this](const std::vector<byte>& fileData) {
            DX::ThrowIfFailed(
                m_Device->CreateVertexShader(
                    &fileData[0],
                    fileData.size(),
                    nullptr,
                    &m_vertexShader
                    )
                );
    
            static const D3D11_INPUT_ELEMENT_DESC vertexDesc [] =
            {
                { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
                { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
            };
    
            DX::ThrowIfFailed(
                m_Device->CreateInputLayout(
                    vertexDesc,
                    ARRAYSIZE(vertexDesc),
                    &fileData[0],
                    fileData.size(),
                    &m_inputLayout
                    )
                );
        });
    
        // ピクセル シェーダー ファイルを読み込んだ後、シェーダーと定数バッファーを作成します。
        auto createPSTask = loadPSTask.then([this](const std::vector<byte>& fileData) {
            DX::ThrowIfFailed(
                m_Device->CreatePixelShader(
                    &fileData[0],
                    fileData.size(),
                    nullptr,
                    &m_pixelShader
                    )
                );
    
            CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer) , D3D11_BIND_CONSTANT_BUFFER);
            DX::ThrowIfFailed(
                m_Device->CreateBuffer(
                    &constantBufferDesc,
                    nullptr,
                    &m_constantBuffer
                    )
                );
        });
    }
    
    //★ 入力したモデルデータ(Byte 形式)を受け取って解析
    void Sample3DSceneRenderer::X_Byte(Array<byte>^ buf)
    {
        int     num;
        int     pt,pw;
        byte    wk;
    
        // X-FILE(buf) を行で切り分けて vector<string> VT に格納
        VT.clear();
        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();
    
        X_Model();
    }
    
    // VT[] のモデル(行で切り分けられたソース)を解析する
    void Sample3DSceneRenderer::X_Model()
    {
        // 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;      //モデルデータの先頭
    
        // Material(MTBL)を取得
        SetMTBL();
    
        // 頂点座標を取得
        m_pos.clear();
        m_Line = m_Top;
        // m_Line から "Mesh " を検索
        if (SetXMFLOAT3("Mesh ", &m_pos))
        {
            SetFTBL();
        }
        else
        {
            OutputDebugString(L"Mesh File  Format Error\r\n");
            return;
        }
    
        // MeshMaterialList を取得
        MatList();
    
        // Face 構造体の FTBL ⇒ POL3
        Convt_3P();
    
        //★ pos, color を組み合わせて、モデルの頂点座標を作成
        m_indexCount = POL3.size() * 3;
        VertexPositionColor *Vertices = new VertexPositionColor[m_indexCount];
        unsigned short *Indices = new unsigned short[m_indexCount];
    
        for (unsigned i = 0; i < POL3.size(); i++)
        {
            for (unsigned j = 0; j < 3; j++)
            {
                Vertices[i * 3 + j].pos = m_pos[POL3[i].Pos[j]];
                int idx = POL3[i].Midx;
                if (idx != -1)
                    Vertices[i * 3 + j].color = MTBL[idx].faceColor;
                else
                    Vertices[i * 3 + j].color = XMFLOAT3(1.0f, 1.0f, 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)*m_indexCount, D3D11_BIND_VERTEX_BUFFER);
        DX::ThrowIfFailed(
            m_Device->CreateBuffer(
                &vertexBufferDesc, &vertexBufferData, &m_vertexBuffer));
    
        // インデックスを作成
        D3D11_SUBRESOURCE_DATA indexBufferData = { 0 };
        indexBufferData.pSysMem = Indices;
        indexBufferData.SysMemPitch = 0;
        indexBufferData.SysMemSlicePitch = 0;
        CD3D11_BUFFER_DESC indexBufferDesc(sizeof(unsigned short)*m_indexCount, D3D11_BIND_INDEX_BUFFER);
        DX::ThrowIfFailed(
            m_Device->CreateBuffer(
                &indexBufferDesc, &indexBufferData, &m_indexBuffer));
    
        // 領域の解放
        if (Vertices)   delete Vertices;
        if (Indices)    delete Indices;
    
        m_loadingComplete = true;   // 描画準備完了
    //  Debug(L"SetText OK", 0);
    }
    
    //★ X-FILE 解析関数
    // Line, Col から次の Token を取得 ⇒ Word に設定(Line 行だけ検索)
    bool Sample3DSceneRenderer::LineToken()
    {
        int wk;
        Word= (char *)"";
        if (m_Col>=(int)VT[m_Line].size())  return false;
        wk= VT[m_Line].find_first_not_of(" ,;{}\r\n", m_Col);
        m_Col= wk;
        wk= VT[m_Line].find_first_of(" ,;}\r\n", m_Col);
        if (wk>m_Col)
        {   Word= Word.assign(VT[m_Line], m_Col, wk-m_Col);
            m_Col= wk + 1;
            return true;
        }
        return false;
    }
    
    //★ "Material" で始まる行を検索(先頭から順に並ぶ)
    void Sample3DSceneRenderer::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((char *)Word.data());
            Token();
            mat.faceColor.y= (float)atof((char *)Word.data());
            Token();
            mat.faceColor.z= (float)atof((char *)Word.data());
            Token();
            //mat.faceColor.w= (float)atof((char *)Word.data());
            MTBL.push_back(mat);
        }
    }
    
    //★ "MeshMaterialList" で始まる行を検索
    void Sample3DSceneRenderer::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((char *)Word.data());
        Token();
        fcnt= atoi((char *)Word.data());
        if (FTBL.size()!=fcnt)
        {   return;  }
        // Face に対応する Material番号を設定
        for(i=0; i<fcnt; i++)
        {   Token();
            fm.push_back(atoi((char *)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("}");
        }
        // fm, midx を参照して Face ごとの Midx を設定
        for(i=0; i<fcnt; i++)
        {   FTBL[i].Midx= midx[fm[i]];
        }
    }
    
    //★ 頂点に続く Index を vector<Face> に格納する
    bool Sample3DSceneRenderer::SetFTBL()
    {
        Face    face;
        int     i,j,num;
        unsigned short wk;
    
        FTBL.clear();
        Token();
        num = atoi((char *)Word.data());
        if (num<3)
        {   return false;   }
    
        face.Midx= -1;
        for(i=0; i<num; i++)
        {
            Token();
            face.Num= atoi((char *)Word.data());
            face.Pos.clear();
            for(j=0; j<face.Num; j++)
            {
                Token();
                wk= atoi((char *)Word.data());
                face.Pos.push_back(wk);
            }
            FTBL.push_back(face);
        }
        return true;
    }
    
    // vector<Face> FTBL ⇒ vector<Pol3> POL3  TRIANGLELIST に変換
    void Sample3DSceneRenderer::Convt_3P()
    {   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;
            }
        }
    }
    

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