Texture Color Model Picker

Windows10 でハードディスク上の X-FILE(頂点座標+法線+Texture+カラー)を入力して描画します。

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

プログラムの説明

  1. File Picker を使うと直接ハードディスクからモデルを選択することが出来ます。
    テクスチャ画像のファイル名はモデルの中で定義されているのですが、一般的なファイルにアクセスすることが出来ません。
    幸いにしてモデルとテクスチャは独立していて、自由にテクスチャを切り替えることが出来ます。
    そこでテクスチャ画像も File Picker を使って入力することにしました。
    最初に File Picker を使ってモデルを入力すると、仮のテクスチャ画像(star.jpg)を張り付けて描画します。
    次に File Picker を使ってテクスチャ画像を入力すると本来のテクスチャ画像が張り付けられます。
    Win10 Picker Texture はカラーモデルには対応していませんでしたが、今回はテクスチャを張り付けたカラーモデルにも対応します。
  2. File Picker を使うプロジェクトは DirectX 11 および XAML アプリ(ユニバーサル Windows)から生成します。
    Win10 Picker Color を参照してプロジェクトを作成して下さい。
    File Picker で Color Model を入力するプロジェクトです。
    シェーダーは Windows10 Shader から「頂点座標+法線+Texture+4色カラー」を使って下さい。
  3. Win10 Picker Texture を参照して File Picker でモデルとテクスチャを選択する二個のボタンを貼り付けます。
    Class DirectXPage, Class App1Main, Class X_Class が関係します。
  4. モデルやテクスチャを入力して描画する Class X_Class のヘッダーファイル X_Class.h です。
    Material 構造体(MTBL) に Tnum を設定します。
    Tnum の値は Texture が一枚なので、テクスチャが設定されているときは0に、設定されていないときは-1が格納されます。
    SetString() が入力したモデルを描画する関数です。
    SetTexture() がテクスチャを入力する関数です。
    #pragma once
    
    #include "..\Common\DeviceResources.h"
    #include "..\Common\StepTimer.h"
    #include "ShaderStructures.h"
    #include "TextureLoader.h"
    #include <vector>
    using namespace std;
    using namespace Platform;
    
    // Face 構造体(FTBL)
    struct  Face
    {   int             Num;    // 頂点数(Num ポリゴン)
        vector<uint32>  Pos;    // 頂点(tex) Index の並び
        vector<uint32>  Norm;   // 法線 Index の並び
        int             Midx;   // Material(MTBL) Index(-1:指定なし)
    };
    // Polygon3 構造体(POL3)
    struct  Pol3
    {
        uint32  Pos[3];         // 頂点(Tex) Index の並び
        uint32  Norm[3];        // 法線 Index の並び
        int     Midx;           // Material(MTBL) Index(-1:指定なし)
    };
    // Material 構造体(MTBL)
    struct  Mat
    {   wstring                 matName;
        DirectX::XMFLOAT4       faceColor;
        float                   power;
        DirectX::XMFLOAT3       specularColor;
        DirectX::XMFLOAT3       emissiveColor;
        int     Tnum;           // Texture 番号(-1:指定なし)
    };
    
    namespace App1
    {
        class X_Class
        {
        public:
            X_Class(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; }
            void SetString(Platform::String^ text);
            void SetTexture(Platform::Array<byte>^ tex, Platform::String^ filename);
    
        private:
            void Rotate(float radians);
    
            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;
            Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> m_textureSRV;
            Microsoft::WRL::ComPtr<ID3D11SamplerState>  m_sampler;
    
            ID3D11RasterizerState  *m_RasterizerState;
    
            // キューブ ジオメトリのシステム リソース。
            ModelViewProjectionConstantBuffer   m_constantBufferData;
            uint32          m_indexCount;
    
            // レンダリング ループで使用する変数。
            float   m_degreesPerSecond;
            bool    m_tracking;
    
            //★ X-FILE の領域
            std::wstring    m_x;                //X-FILE TEXT
            vector<wstring> 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;    // 頂点座標
            vector<DirectX::XMFLOAT3> m_norm;   // 法線ベクトル
            vector<DirectX::XMFLOAT2> m_tex;    // テクスチャ
            int     m_Line, m_Col, m_Top;
            wstring Word;
            bool    m_loadingComplete;
            bool    m_normflag;     // 法線の取得フラグ
            bool    m_texall;       // テクスチャ ALL のフラグ
    
            bool Search(String^ key);
            void Token();
            bool LineToken();
            bool SetXMFLOAT3(String^ key, vector<DirectX::XMFLOAT3> *f3);
            bool SetXMFLOAT2(String^ key, vector<DirectX::XMFLOAT2> *f2);
            void ComputeNorm(VertexPosition *Vertices, uint32 siz);
    
            bool SetFTBL();
            bool SetNorm();
            void Convt_3P(bool flg);
            void SetMTBL();
            void MatList();
        };
    }
    
  5. テクスチャをロードする SetTexture() 関数です。
    void X_Class::SetTexture(Platform::Array<byte>^ tex, Platform::String^ filename)
    {
        TextureLoader^ loader = ref new TextureLoader(m_Resources->GetD3DDevice());
        loader->LoadTexture(tex, filename, nullptr, &m_textureSRV);
    }
    
  6. 3D描画環境を設定する CreateDeviceDependentResources() 関数です。
    初期のテクスチャとして "star.jpg" を使うのでプロジェクトに加えて下さい。
    void X_Class::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 },
                { "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
                { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
                { "COLOR",    0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 32, 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
                    )
                );
        });
    
        // テクスチャのロード
        TextureLoader^ loader = ref new TextureLoader(m_Resources->GetD3DDevice());
        loader->LoadTexture("star.jpg", nullptr, &m_textureSRV);
    
        // create the sampler
        D3D11_SAMPLER_DESC samplerDesc;
        ZeroMemory(&samplerDesc, sizeof(D3D11_SAMPLER_DESC));
        samplerDesc.Filter = D3D11_FILTER_ANISOTROPIC;
        samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
        samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
        samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
        samplerDesc.MipLODBias = 0.0f;
        samplerDesc.MaxAnisotropy = 2;
        samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
        samplerDesc.BorderColor[0] = 0.0f;
        samplerDesc.BorderColor[1] = 0.0f;
        samplerDesc.BorderColor[2] = 0.0f;
        samplerDesc.BorderColor[3] = 0.0f;
        samplerDesc.MinLOD = 0;
        samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
    
        DX::ThrowIfFailed(
            m_Resources->GetD3DDevice()->CreateSamplerState(
                &samplerDesc, &m_sampler) );
    
        // カリング設定
        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_Resources->GetD3DDevice()->CreateRasterizerState(
                &rasterizerDesc, &m_RasterizerState));
    }
    
  7. pos, norm, color を組み合わせて、モデルの頂点座標を作成するソースコードです。
    テクスチャが設定されていないときは 0.0f-0.0f に設定しているのですが、画像全体の色とカラーがブレンドされるようです。
        //★ pos, norm, color を組み合わせて、モデルの頂点座標を作成
        m_indexCount = POL3.size()*3;
        VertexPosition *Vertices = new VertexPosition[m_indexCount];
        unsigned short *Indices = new unsigned short[m_indexCount];
    
        for(unsigned i=0; i<POL3.size(); i++)
        {
            // 頂点座標
            Vertices[i*3].pos = m_pos[POL3[i].Pos[0]];
            Vertices[i*3+1].pos = m_pos[POL3[i].Pos[1]];
            Vertices[i*3+2].pos = m_pos[POL3[i].Pos[2]];
            // 法線ベクトル(未設定のときはプログラムで計算)
            if (m_normflag)
            {
                Vertices[i*3].norm = m_norm[POL3[i].Norm[0]];
                Vertices[i*3+1].norm = m_norm[POL3[i].Norm[1]];
                Vertices[i*3+2].norm = m_norm[POL3[i].Norm[2]];
            }
    
            // マテリアルを設定
            Vertices[i * 3].tex = XMFLOAT2(0.0f, 0.0f);
            Vertices[i * 3 + 1].tex = XMFLOAT2(0.0f, 0.0f);
            Vertices[i * 3 + 2].tex = XMFLOAT2(0.0f, 0.0f);
            Vertices[i * 3].color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
            Vertices[i * 3 + 1].color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
            Vertices[i * 3 + 2].color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
    
            int idx = POL3[i].Midx;
            if (m_texall || (idx!=-1 && (MTBL[idx].Tnum!=-1)))
            {   Vertices[i * 3].tex = m_tex[POL3[i].Pos[0]];
                Vertices[i * 3 + 1].tex = m_tex[POL3[i].Pos[1]];
                Vertices[i * 3 + 2].tex = m_tex[POL3[i].Pos[2]];
            }
            if (idx != -1)
            {   Vertices[i * 3].color = MTBL[idx].faceColor;
                Vertices[i * 3 + 1].color = MTBL[idx].faceColor;
                Vertices[i * 3 + 2].color = MTBL[idx].faceColor;
            }
            Indices[i*3] = i*3;
            Indices[i*3+1] = i*3+1;
            Indices[i*3+2] = i*3+2;
        }
    
  8. File Picker から選択した X-FILE(テクスチャ+カラーモデル)が描画出来ることを確かめて下さい。
    char.x も描画出来ますが、星型のポリゴンの色が黄色になりません。
    このモデルはちょっと変わっていて、星型のポリゴンだけはテクスチャが設定されていないのです。
    char.x を正常に描画するプログラムは XLoader Texture3 を参照して下さい。
    説明の足らない所は Win10 TextureModelXLoader Texture Color を併せて参照して下さい。

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