Hand Model

インクレディブル婦人の腕を組み合わせます。

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

プログラムの説明

  1. インクレディブル婦人の腕(上腕, 下腕, 手首)を組み合わせます。
    X-FILE(arm_upperL.x, arm_lowerL.x, handL.x)から3体のテクスチャモデルをロードして組み合わせます。
    DirectX 11 アプリ(ユニバーサル Windows)のプロジェクトを生成して下さい。
    生成したアプリは「頂点+カラー」のモデルを描画するプロジェクトなのでシェーダー関係は「頂点+法線+テクスチャ」の物に入れ替えます。
    Content\ のフォルダーに Load_X と MyCamera を格納して、テクスチャモデルを描画します。
    Load_X のソースコードは Load_X Texture から取得して下さい。
    MyCamera(Ver-2.0)は W10 Bone 2 から取得して下さい。
    プロジェクトの作成は Win10 Template を参照して下さい。
  2. プロジェクトに X-FILE(arm_upperL.x, arm_lowerL.x, handL.x, TexUX.jpg)を格納します。
    X-FILE を右クリックしてコンテンツを True に設定します。
  3. Sample3DSceneRenderer.h で3体のモデルとカメラの領域を配列で定義します。
        #include "Load_X.h"
        #include "MyCamera.h"
    
        Microsoft::WRL::ComPtr<ID3D11Buffer>        m_vertexBuffer[3];
        Microsoft::WRL::ComPtr<ID3D11Buffer>        m_indexBuffer[3];
        uint32      m_indexCount[3];
        MyCamera    *camera[3];
        Load_X      *model;
    
        float   dt = 0.05f;
        float   rt = 0.0f;
    
  4. Sample3DSceneRenderer.cpp の Constructor でカメラを生成します。
    m_pivot はモデルを組み立てるためのモデルの移動量(回転軸の中心)です。
    Sample3DSceneRenderer::Sample3DSceneRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
        m_loadingComplete(false),
        m_degreesPerSecond(45),
        m_tracking(false),
        m_deviceResources(deviceResources)
    {
        CreateDeviceDependentResources();
        CreateWindowSizeDependentResources();
        camera[0] = new MyCamera(m_deviceResources, nullptr);
        camera[1] = new MyCamera(m_deviceResources, camera[0]);
        camera[2] = new MyCamera(m_deviceResources, camera[1]);
        camera[1]->m_pivot = camera[1]->f3(-4.0f,0.0f,0.0f);
        camera[2]->m_pivot = camera[2]->f3(-5.0f,0.0f,0.0f);
    }
    
  5. Rotate() 関数では下腕(モデル2)を上下に動かします。
    void Sample3DSceneRenderer::Rotate(float radians)
    {
        if (rt > 1.0f)  dt = -0.01f;
        if (rt < -1.0f) dt = 0.01f;
        rt += dt;
        camera[1]->m_rot= camera[1]->f3(0.0f, 0.0f, rt);
    }
    
  6. CreateDeviceDependentResources() 関数では、3体のモデルを読み込みます。
    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));
        });
    
        // 両方のシェーダーの読み込みが完了したら、メッシュを作成します。
        auto createCubeTask = (createPSTask && createVSTask).then([this] () {
            model = new Load_X(m_deviceResources);
            model->Load("arm_upperL.x", &m_vertexBuffer[0], &m_indexBuffer[0], &m_indexCount[0]);
            model->Load("arm_lowerL.x", &m_vertexBuffer[1], &m_indexBuffer[1], &m_indexCount[1]);
            model->Load("handL.x", &m_vertexBuffer[2], &m_indexBuffer[2], &m_indexCount[2]);
        });
    
        // メッシュが読み込まれたら、オブジェクトを描画する準備が完了します。
        createCubeTask.then([this] () {  m_loadingComplete = true;  });
    }
    
  7. Render() 関数でモデルを描画します。
    void Sample3DSceneRenderer::Render()
    {
        ・・・
    
        // テクスチャを設定
        model->SetTex();
        // カリングを設定
        model->SetCullMode();
        //☆モデルを描画
        for(int i=0; i<3; i++) 
        {   camera[i]->SetEnv(camera[i]);
            m_constantBufferData.projection = camera[i]->m_projection;
            m_constantBufferData.view = camera[i]->m_view;
            m_constantBufferData.model = camera[i]->m_model;
    
            context->UpdateSubresource(m_constantBuffer.Get(), 0, NULL, &m_constantBufferData, 0, 0);
            context->IASetVertexBuffers(0, 1, m_vertexBuffer[i].GetAddressOf(), &stride, &offset);
            context->IASetIndexBuffer(m_indexBuffer[i].Get(), DXGI_FORMAT_R16_UINT, 0);
            context->DrawIndexed(m_indexCount[i], 0, 0);
        }
    }
    
  8. CreateWindowSizeDependentResources() 関数からは Projection() を呼び出すだけです。
    下腕(モデル2)の動きに合わせて、上腕, 下腕, 手首がスムースに動きます。
    void Sample3DSceneRenderer::CreateWindowSizeDependentResources()
    {
        for(int i=0; i<3; i++) 
            if (camera[i]!=nullptr) camera[i]->Projection();
    }
    

[Next Chapter ↓] Anime Camera

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