Win10 TextureModel

Windows10 DirectX3D で Texture Model を組み込んで描画します。

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

プロジェクトの作成

  1. Windows10 DirectX3D でプロジェクトに Texture Model を組み込んで描画します。
    Win10 ColorModel は「頂点座標+カラー」のモデルでした。
    Win10 NormModel は「頂点座標+法線」のモデルでした。
    今回は「頂点座標+法線+テクスチャ」で構成するモデルを描画します。
    頂点+法線+テクスチャは対になっていて、頂点データとして組み合わせて格納します。
        vector<float3> m_pos;           // 頂点座標
        vector<float3> m_norm;          // 法線ベクトル
        vector<float2> m_tex;           // テクスチャ
    
    Win10 Template を参照して DirectX 11 アプリ(ユニバーサル Windows)を構築して下さい。
    カラーキューブが回転しながら描画され、FPS が表示されます。
    プロジェクトの名前は App1 になっています。
  2. ページの後半を参照して、次のファイルを修正して下さい。
    Content\Sample3DSceneRenderer.h
    Content\Sample3DSceneRenderer.cpp
  3. シェーダは Texture を使うので Windows10 Shader から「頂点座標+法線+テクスチャ」の物に置き換えて下さい。
    新しく追加されるファイルは App1 を選択して[追加][既存の項目]からプロジェクトに追加します。
    Content\ShaderStructures.h
    Content\SamplePixelShader.hlsl
    Content\SampleVertexShader.hlsl
    Content\BasicReaderWriter.h
    Content\BasicReaderWriter.cpp
    Content\TextureLoader.h
    Content\TextureLoader.cpp
  4. 「頂点座標+法線ベクトル+テクスチャ座標」で構成される X-FILE(BoxP4TexAll.x) を X Model からダウンロードしてプロジェクトに追加します。
    BoxP4TexAll.x を右クリックしてコンテンツを True に設定して下さい。
    X-FILE の中でテクスチャ画像の名前(star.jpg)が定義されています。
    star.jpg をプロジェクトに格納します。
    名前が star.jpg であれば、画像は適当なもので構いません。
    コンパイル&実行すると各面に star.jpg が張り付けられた立方体が回転しながら描画されます。

ソースコード

  1. Sample3DSceneRenderer.h です。
    X-FILE を解析する関数のプロトタイプ宣言と領域が定義されています。
    m_pos が頂点座標の配列で、m_norm が法線ベクトルの配列で、m_tex がテクスチャ座標の配列です。
            ID3D11RasterizerState  *m_RasterizerState;
            vector<string>  VT;                 //X-FILE を行で切り分け
            int             VT_size;            //VT の大きさ
            vector<DirectX::XMFLOAT3> m_pos;    // 頂点座標
            vector<DirectX::XMFLOAT3> m_norm;   // 法線ベクトル
            vector<DirectX::XMFLOAT2> m_tex;    // テクスチャ座標
            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) の並び
            String^ m_texName;
            int     m_Line, m_Col, m_Top;
            string  Word;
    
            bool SetXMFLOAT3(char *key, vector<DirectX::XMFLOAT3> *f3);
            bool SetXMFLOAT2(char *key, vector<DirectX::XMFLOAT2> *f2);
            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();
        };
    }
    
  2. Sample3DSceneRenderer.cpp です。
    プロジェクトに組み込まれた X-FILE を解析してモデルデータを作成します。
    reader->ReadData("BoxP4TexAll.x") でモデルデータを取得しています。
    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_deviceResources->GetD3DDevice()->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 },
            };
    
            DX::ThrowIfFailed(
                m_deviceResources->GetD3DDevice()->CreateInputLayout(
                    vertexDesc, ARRAYSIZE(vertexDesc),
                    &fileData[0], fileData.size(), &m_inputLayout ));
        });
    
        auto createPSTask = loadPSTask.then([this](const std::vector<byte>& fileData) {
            DX::ThrowIfFailed(
                m_deviceResources->GetD3DDevice()->CreatePixelShader(
                    &fileData[0], fileData.size(), nullptr, &m_pixelShader ));
    
            CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer) , D3D11_BIND_CONSTANT_BUFFER);
            DX::ThrowIfFailed(
                m_deviceResources->GetD3DDevice()->CreateBuffer(
                    &constantBufferDesc, nullptr, &m_constantBuffer ));
        });
    
        //★ XFILE の解析
        int     num;
        int     pt,pw;
        byte    wk;
    
        BasicReaderWriter^ reader = ref new BasicReaderWriter();
        Platform::Array<byte>^ buf = reader->ReadData("BoxP4TexAll.x");
        // 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 (SetXMFLOAT3("Mesh ", &m_pos))
        {
            SetShort(&m_idxP);
        }
        else
        {
            OutputDebugString(L"Mesh File  Format Error");
            return;
        }
    
        // 法線を取得
        m_Line = m_Top;
        if (SetXMFLOAT3("MeshNormals ", &m_norm))
        {   SetShort(&m_idxN);  }
    
        // Texture 座標を取得
        m_Line = m_Top;
        if (SetXMFLOAT2("MeshTextureCoords ", &m_tex))
        {
            if (m_pos.size() != m_tex.size())
            {
                OutputDebugString(L"頂点座標の数 ≠ テクスチャ座標の数");
                return;
            }
        }
        else
        {
            OutputDebugString(L"MeshTextureCoords Error");
            return;
        }
    
        // Texture Name を取得
        m_Line = m_Top;
        if (Search("TextureFilename")==false)
        {
            OutputDebugString(L"TextureFilename Not found");
            return;
        }
        m_Line++;
        m_Col= 0;
        Token();
        Word = Word.substr(1, Word.size() - 2);
        WCHAR   work[256];
        MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, Word.data(), -1, work, 256);
        m_texName = ref new String(work);
    
        // N角ポリゴン ⇒ 3角ポリゴン
        PX_P3(m_idxP, &m_idxP3);
        PX_P3(m_idxN, &m_idxN3);
    
        auto createTask = (createPSTask && createVSTask).then([this] ()
        {   // 頂点データとインデックスデータを作成
            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]];
                Vertices[i].tex = m_tex[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);
    
            m_indexCount = m_idxP3.size();
    
            // メッシュを作成
            D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
            vertexBufferData.pSysMem = Vertices;
            vertexBufferData.SysMemPitch = 0;
            vertexBufferData.SysMemSlicePitch = 0;
            CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(VertexPosition)*m_indexCount, D3D11_BIND_VERTEX_BUFFER);
            DX::ThrowIfFailed(
                m_deviceResources->GetD3DDevice()->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_deviceResources->GetD3DDevice()->CreateBuffer(
                    &indexBufferDesc, &indexBufferData, &m_indexBuffer));
    
            // 領域の解放
            if (Vertices)   delete Vertices;
            if (Indices)    delete Indices;
        });
    
        createTask.then([this] ()
        {   m_loadingComplete = true;   // 描画準備完了
        });
    
        // テクスチャのロード
        TextureLoader^ loader =
            ref new TextureLoader(m_deviceResources->GetD3DDevice());
        loader->LoadTexture(m_texName, 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_deviceResources->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_deviceResources->GetD3DDevice()->CreateRasterizerState(
                &rasterizerDesc, &m_RasterizerState));
    }
    
    // ★X-FILE メソッド
    掲載されていない関数は Windows10 DirectX Library を参照して下さい。
    

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