Bone 3

W10 Bone 3

3体のモデル(Bone)を組み合わせて関節のように回転します。

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

プログラムの説明

  1. Windows10 で CreateModel と MyCamera を組み込んで、3体のモデルを組み合わせて関節のように回転します。
    3体のモデルを組み合わせたとき、なかなか追随しなかったのですが、ようやく動くようになりました。
    Bone 2 を参照して2体のモデルを組み合わせて回転するプロジェクトを作成して下さい。
  2. Sample3DSceneRenderer.cpp の CreateDeviceDependentResources() 関数で3体のモデルを生成します。
        // 両方のシェーダーの読み込みが完了したら、メッシュを作成します。
        auto createCubeTask = (createPSTask && createVSTask).then([this] () {
            model = new CreateModel(m_deviceResources);
            model->CreateBone(5.0f, &m_vertexBuffer[0], &m_indexBuffer[0], &m_indexCount[0]);
            model->CreateBone(4.0f, &m_vertexBuffer[1], &m_indexBuffer[1], &m_indexCount[1]);
            model->CreateBone(3.0f, &m_vertexBuffer[2], &m_indexBuffer[2], &m_indexCount[2]);
        });
    
  3. モデル1の new MyCamera() では、第2引数に nullptr を渡します。
    モデル2の new MyCamera() では、第2引数に camera[0] を渡して連鎖します。
    モデル3の new MyCamera() では、第2引数に camera[1] を渡して連鎖します。
    モデル2の m_pivot に f3(0.0f, -5.0f, 0.0f) を設定して、モデル1に対してY座標を -5.0f 移動します。
    モデル3の m_pivot に f3(0.0f, -4.0f, 0.0f) を設定して、モデル2に対してY座標を -4.0f 移動します。
    m_pivot は回転軸の中心で、親モデルからの相対座標で指定します。
    Sample3DSceneRenderer::Sample3DSceneRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
        m_loadingComplete(false),
        m_degreesPerSecond(45),
        m_tracking(false),
        m_deviceResources(deviceResources)
    {
        m_indexCount[0] = 0;
        m_indexCount[1] = 0;
        m_indexCount[2] = 0;
        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 = Ft3(0.0f, -5.0f, 0.0f);
        camera[2]->m_pivot = Ft3(0.0f, -4.0f, 0.0f);
    }
    
  4. Sample3DSceneRenderer.cpp の Rotate() 関数ではモデル1を Rot で振り子運動をさせてみました。
    モデル2は、モデル1と逆方向に振り子運動をします。
    モデル3は、Y軸で回転します。
    親モデルと子モデルと孫モデルの回転を m_rot に設定します。
    m_rot に設定された回転情報は SetEnv() 関数で計算されます。
    void Sample3DSceneRenderer::Rotate(float radians)
    {
        if (rt > 0.5f)  dt = -0.005f;
        if (rt < -0.5f)  dt = 0.005f;
        rt += dt;
        camera[0]->m_rot = Ft3(0.0f, 0.0f, rt);
        camera[1]->m_rot = Ft3(0.0f, 0.0f, -rt);
        camera[2]->m_rot = Ft3(0.0f, radians, 0.0f);
    }
    
  5. Sample3DSceneRenderer.h では、モデル1, モデル2, モデル3と振り子運動の領域を定義して下さい。
            Microsoft::WRL::ComPtr<ID3D11Buffer>        m_vertexBuffer[3];
            Microsoft::WRL::ComPtr<ID3D11Buffer>        m_indexBuffer[3];
    
            uint32          m_indexCount[3];
            CreateModel     *model;
            MyCamera        *camera[3];
    
            // レンダリング ループで使用する変数。
            float       dt = 0.005f;
            float       rt = 0.0f;
    
  6. モデルの描画です。
    SetEnv(camera[i]) 関数でモデルの描画環境を計算して m_projection, m_view, m_model に設定します。
    m_projection, m_view, m_model の値は m_constantBufferData に格納されて描画します。
        UINT stride = sizeof(VertexPositionColor);
        UINT offset = 0;
    
        //☆モデルを描画
        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);
        }
    
  7. MyCamera.cpp の SetEnv() でモデルの姿勢を計算します。
    親モデル, 子モデル, 孫モデルの回転情報が、それぞれの MyCamera の m_rot に設定されています。
    pvt, pvt2 に回転座標の中心座標を計算して Camera(pvt); で設定します。
    これでようやく3体のモデルを組み合わせて、追随して回転するようになりました。
    void MyCamera::SetEnv(MyCamera *p)
    {   MyCamera *q, *r;
        float3  pvt, pvt2;
    
        Model(p->m_rot.x, p->m_rot.y, p->m_rot.z);
        if (p->m_link==nullptr) return;     //親の時
    
        pvt = f3(0.0f, 0.0f, 0.0f);
        for(q=p; q->m_link!=nullptr; q=q->m_link)
        {   r = q->m_link;
            pvt2 = MatRotate(q->m_pivot, r->m_rot);
            pvt.x += pvt2.x;
            pvt.y += pvt2.y;
            pvt.z += pvt2.z;
        }
        Camera(pvt);
    }
    
  8. SetEnv() から呼ばれる Camera(); 関数です。
    規定値の m_eye から f3 の座標をずらして m_camera に設定します。
    void MyCamera::Camera(float3 f3)
    {
        DirectX::XMVECTOR   eye;
        DirectX::XMVECTOR   at;
        eye = m_eye;
        at = m_at;
        eye.m128_f32[0] += f3.x;
        eye.m128_f32[1] += f3.y;
        eye.m128_f32[2] += f3.z;
        at.m128_f32[0] += f3.x;
        at.m128_f32[1] += f3.y;
        at.m128_f32[2] += f3.z;
        m_camera = XMMatrixTranspose(XMMatrixLookAtRH(eye, at, m_up));
        XMStoreFloat4x4(&m_view, m_camera);
    }
    
  9. 親モデルに追随して子モデルが、子モデルに追随して孫モデルが回転するので、組み合わせを変えて試してみて下さい。
    MyCamera のソースコードは Bone 2 を参照して下さい。
        // テスト1
        camera[0]->m_rot = Ft3(0.0f, radians, 0.0f);
        camera[1]->m_rot = Ft3(0.0f, 0.0f, rt);
        camera[2]->m_rot = Ft3(radians, 0.0f, 0.0f);
        // テスト2
        camera[0]->m_rot = Ft3(0.0f, 0.0f, rt);
        camera[1]->m_rot = Ft3(rt, 0.0f, 0.0f);
        camera[2]->m_rot = Ft3(0.0f, radians, 0.0f);
        // テスト3
        camera[0]->m_rot = Ft3(0.0f, 0.0f, rt);
        camera[1]->m_rot = Ft3(0.0f, 0.0f, -rt);
        camera[2]->m_rot = Ft3(0.0f, radians, 0.0f);
    

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