Win10 NormModel

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

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

プロジェクトの作成

  1. Windows10 DirectX3D でプロジェクトに Norm Model を組み込んで描画します。
    Win10 ColorModel は「頂点座標+カラー」のモデルでしたが今回は「頂点座標+法線」のモデルです。
    プロジェクトに X-FILE を組み込むときは XLoader Class を使う方が解り易く簡単です。
    XLoader Class を使う方法は XLoader Norm を参照して下さい。
    Win10 Template を参照して DirectX 11 アプリ(ユニバーサル Windows)を構築して下さい。
    カラーキューブが回転しながら描画され、FPS が表示されます。
    プロジェクトの名前は App1 になっています。
  2. ページの後半を参照して、次のファイルを修正して下さい。
    Content\Sample3DSceneRenderer.h
    Content\Sample3DSceneRenderer.cpp
  3. Win10 TextureBox から、次のファイルを Content\ に格納して下さい。
    BasicReaderWriter はプロジェクトに組み込んだモデルのソースを取得するときに使います。
    新しく追加されるファイルは App1 を選択して[追加][既存の項目]からプロジェクトに追加します。
    Content\BasicReaderWriter.h
    Content\BasicReaderWriter.cpp
  4. シェーダーは Win10 Shader から「頂点座標+法線」の物に置き換えて下さい。
    Content\ShaderStructures.h
    Content\SamplePixelShader.hlsl
    Content\SampleVertexShader.hlsl
  5. Box_4PNorm.x を X Model からダウンロードしてプロジェクトに追加します。
    コンパイル&実行すると法線が設定された立方体が回転しながら描画されます。
    XLoader Norm でも XLoader を使った Normal Model の描画を説明しています。

ソースコード

  1. Sample3DSceneRenderer.h に X FILE を解析して描画する領域を組み込みます。
    X-FILE を解析する関数のプロトタイプ宣言と領域が定義されています。
    VT は STL の string(wstring では無い)を使っています。
    m_pos が頂点座標の配列で、m_norm が法線ベクトルの配列です。
    m_idxP3, m_idxN3 は3角形ポリゴンに変換したときの Index の並びです。
            ID3D11RasterizerState  *m_RasterizerState;
            vector<string>  VT;                 //X-FILE を行で切り分け
            int             VT_size;            //VT の大きさ
            vector<DirectX::XMFLOAT3> m_pos;    // 頂点座標
            vector<DirectX::XMFLOAT3> 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 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. プロジェクトに組み込まれた X FILE を解析して描画するように Sample3DSceneRenderer.cpp を修正します。
    掲載されていない関数は Windows10 DirectX Library を参照して下さい。
    Platform::Array<byte>^ buf = reader->ReadData("Box_4PNorm.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 },
            };
    
            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("Box_4PNorm.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);  }
    
        // 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]];
                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;   // 描画準備完了
        });
    
        // カリング設定
        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)