Bone 2

W10 Bone 2

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

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

プログラムの説明

  1. Windows10 で CreateModel と MyCamera を組み込んで、2体のモデルを組み合わせて関節のように回転します。
    m_rot に設定された回転(自転)情報は constantBufferData.model に設定されます。
    親モデル(Rot) ⇒ 子モデル(Rot)で回転したとき、追随しなかったのですがようやく解決です。
    Win10 Model 2 を参照して2体のモデルを描画するプロジェクトを作成して下さい。
  2. Sample3DSceneRenderer.cpp の CreateDeviceDependentResources() 関数で2体のモデルを生成します。
    CreateBone() は Version_2 で追加された Bone のモデルです。
    多角錐の回転の中心はモデルの中央に設定されていますが、Bone では関節に相当する蓋の部分に設定されています。
    1番目のパラメータは Bone の長さで、Bone を骨に見立てて組合せて回転することを想定しています。
        // 両方のシェーダーの読み込みが完了したら、メッシュを作成します。
        auto createCubeTask = (createPSTask && createVSTask).then([this] () {
            model = new CreateModel(m_deviceResources);
            model->CreateBone(5.0f, &m_vertexBuffer1, &m_indexBuffer1, &m_indexCount1);
            model->CreateBone(3.0f, &m_vertexBuffer2, &m_indexBuffer2, &m_indexCount2);
        });
    
  3. モデル1の new MyCamera() では、第2引数に nullptr を渡します。
    モデル2の new MyCamera() では、第2引数に camera1 を渡して連鎖します。
    モデル2の m_pivot に f3(0.0f, -5.0f, 0.0f) を設定して、モデル1に対してY座標を -5.0f 移動します。
    m_pivot は回転軸の中心で、親モデルからの相対座標で指定します。
    これによりモデル1の先端でモデル2が回転します。
    Sample3DSceneRenderer::Sample3DSceneRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
        m_loadingComplete(false),
        m_degreesPerSecond(45),
        m_indexCount1(0),
        m_indexCount2(0),
        m_tracking(false),
        m_deviceResources(deviceResources)
    {
        CreateDeviceDependentResources();
        CreateWindowSizeDependentResources();
        camera1 = new MyCamera(m_deviceResources, nullptr);
        camera2 = new MyCamera(m_deviceResources, camera1);
        camera2->m_pivot = camera2->f3(0.0f, -5.0f, 0.0f);
    }
    
  4. Sample3DSceneRenderer.cpp の Rotate() 関数ではモデル1を Rot で振り子運動をさせてみました。
    親モデルと子モデルの回転を 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;
        //camera1->m_rot = camera1->f3(rt, 0.0f, 0.0f);
        //camera1->m_rot = camera1->f3(0.0f, rt, 0.0f);
        camera1->m_rot = camera1->f3(0.0f, 0.0f, rt);
        //camera2->m_rot = camera2->f3(radians, 0.0f, 0.0f);
        //camera2->m_rot = camera2->f3(0.0f, radians, 0.0f);
        camera2->m_rot = camera2->f3(0.0f, 0.0f, radians);
    }
    
  5. Sample3DSceneRenderer.h では、モデル1, モデル2と振り子運動の領域を定義して下さい。
            Microsoft::WRL::ComPtr<ID3D11Buffer>        m_vertexBuffer1;
            Microsoft::WRL::ComPtr<ID3D11Buffer>        m_vertexBuffer2;
            Microsoft::WRL::ComPtr<ID3D11Buffer>        m_indexBuffer1;
            Microsoft::WRL::ComPtr<ID3D11Buffer>        m_indexBuffer2;
    
            uint32          m_indexCount1;
            uint32          m_indexCount2;
            CreateModel     *model;
            MyCamera        *camera1 = nullptr;
            MyCamera        *camera2 = nullptr;
    
            // レンダリング ループで使用する変数。
            float       dt = 0.005f;
            float       rt = 0.0f;
    
  6. モデルの描画です。
    SetEnv(camera1) 関数でモデルの描画環境を計算して m_projection, m_view, m_model に設定します。
        UINT stride = sizeof(VertexPositionColor);
        UINT offset = 0;
    
        //☆モデル1を描画
        camera1->SetEnv(camera1);
        m_constantBufferData.projection = camera1->m_projection;
        m_constantBufferData.view = camera1->m_view;
        m_constantBufferData.model = camera1->m_model;
    
        context->UpdateSubresource(m_constantBuffer.Get(), 0, NULL, &m_constantBufferData, 0, 0);
        context->IASetVertexBuffers(0, 1, m_vertexBuffer1.GetAddressOf(), &stride, &offset);
        context->IASetIndexBuffer(m_indexBuffer1.Get(), DXGI_FORMAT_R16_UINT, 0);
        context->DrawIndexed(m_indexCount1, 0, 0);
    
        //☆モデル2を描画
        camera2->SetEnv(camera2);
        m_constantBufferData.projection = camera2->m_projection;
        m_constantBufferData.view = camera2->m_view;
        m_constantBufferData.model = camera2->m_model;
    
        context->UpdateSubresource(m_constantBuffer.Get(), 0, NULL, &m_constantBufferData, 0, 0);
        context->IASetVertexBuffers(0, 1, m_vertexBuffer2.GetAddressOf(), &stride, &offset);
        context->IASetIndexBuffer(m_indexBuffer2.Get(), DXGI_FORMAT_R16_UINT, 0);
        context->DrawIndexed(m_indexCount2, 0, 0);
    
  7. MyCamera.cpp の SetEnv() でモデルの姿勢を計算します。
    親モデル, 子モデルの回転情報が、それぞれの MyCamera の m_rot に設定されています。
    m_pivot が回転座標の中心(親からの相対位置)です。
    親モデルを回転したときの回転軸の中心を MatRotate() 関数で求め Camera(); 関数で設定します。
    親を回転したとき、子が追随しなかったのですが、ようやく追随するようになりました。
    MatRotate() 関数の説明は Rotate 3D を参照して下さい。
    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);
    }
    

  1. MyCamera.h のソースコードです。
    *m_link が複数モデルを描画するときの MyCamera のリンクです。
    m_camera がカメラ設定の変換行列です。
    m_pivot; がモデルの回転軸の中心(親からの相対位置)です。
    float3 MatRotate(float3 pos, float3 rt); が三次元座標の回転関数です。
    m_eye では複数モデルを組み合わせるために、カメラを少し引いています。
    // MyCamera Program File  Ver 2.0  前田 稔
    #pragma once
    #include "..\Common\DeviceResources.h"
    //#include "BasicMath.h"
    struct float3
    {
        float   x;
        float   y;
        float   z;
    };
    
    class MyCamera
    { public:
        MyCamera(std::shared_ptr<DX::DeviceResources>& deviceResources, MyCamera *pt);
        void Projection();
        void Camera(DirectX::XMVECTOR eye, DirectX::XMVECTOR at, DirectX::XMVECTOR up);
        void Camera(float dx, float dy, float dz);
        void Camera(float3 f3);
        void View(float dx, float dy, float dz);
        void Model(float rx, float ry, float rz);
        float3 MatRotate(float3 pos, float3 rt);
        float3 f3(float x, float y, float z);
        void SetEnv(MyCamera *p);
    
        // 3Dモデルの描画環境
        DirectX::XMFLOAT4X4 m_projection;
        DirectX::XMFLOAT4X4 m_view;
        DirectX::XMFLOAT4X4 m_model;
    
        // カメラの姿勢(Camera で規定値から修正)
        DirectX::XMVECTOR   m_eye = { 0.0f, 0.7f, 20.0f, 0.0f };
        DirectX::XMVECTOR   m_at = { 0.0f, -0.1f, 0.0f, 0.0f };
        DirectX::XMVECTOR   m_up = { 0.0f, 1.0f, 0.0f, 0.0f };
        DirectX::XMMATRIX   m_camera;
    
        MyCamera    *m_link;
        float3      m_pivot;    // 回転軸の中心
        float3      m_rot;      // 回転
    
    private:
        std::shared_ptr<DX::DeviceResources> m_deviceResources;
    };
    
  2. MyCamera.cpp のソースコードです。
    SetEnv() でモデルの姿勢を計算します。
    /*******************************************/
    /* MyCamera Program File  Ver 2.0  前田 稔 */
    /*******************************************/
    #pragma once
    
    #include "pch.h"
    #include "..\Common\DirectXHelper.h"
    #include "MyCamera.h"
    
    using namespace DirectX;
    using namespace Windows::Foundation;
    
    void Debug(float val)
    {
        wchar_t str[80];
        swprintf(str, 80, L"★%f\n\n", val);
        OutputDebugString(str);
    }
    
    // Constructor で規定値に設定
    MyCamera::MyCamera(std::shared_ptr<DX::DeviceResources>& deviceResources, MyCamera *pt)
    {
        m_deviceResources = deviceResources;
        m_link = pt;
        Projection();
        m_camera = XMMatrixTranspose(XMMatrixLookAtRH(m_eye, m_at, m_up));
        XMStoreFloat4x4(&m_view, m_camera);
        XMStoreFloat4x4(&m_model, XMMatrixIdentity());
        m_pivot = f3(0.0f, 0.0f, 0.0f);
        m_rot = f3(0.0f, 0.0f, 0.0f);
    }
    
    // カメラの Projection を設定
    void MyCamera::Projection()
    {
        Size outputSize = m_deviceResources->GetOutputSize();
        float aspectRatio = outputSize.Width / outputSize.Height;
        float fovAngleY = 70.0f * XM_PI / 180.0f;
        if (aspectRatio < 1.0f)
        {   fovAngleY *= 2.0f;  }
        XMMATRIX perspectiveMatrix = XMMatrixPerspectiveFovRH(
        fovAngleY, aspectRatio, 0.01f, 100.0f);
    
        XMFLOAT4X4 orientation = m_deviceResources->GetOrientationTransform3D();
        XMMATRIX orientationMatrix = XMLoadFloat4x4(&orientation);
        XMStoreFloat4x4(&m_projection, XMMatrixTranspose(perspectiveMatrix * orientationMatrix));
    }
    
    // m_eye, m_at, m_up を規定値から変更
    void MyCamera::Camera(DirectX::XMVECTOR eye, DirectX::XMVECTOR at, DirectX::XMVECTOR up)
    {
        m_eye = eye;
        m_at = at;
        m_up = up;
        m_camera = XMMatrixTranspose(XMMatrixLookAtRH(m_eye, m_at, m_up));
        XMStoreFloat4x4(&m_view, m_camera);
    }
    
    // 規定値から m_eye, m_at を補正してカメラを設定
    void MyCamera::Camera(float dx, float dy, float dz)
    {
        m_pivot.x = dx;
        m_pivot.y = dy;
        m_pivot.z = dz;
        m_eye.m128_f32[0] += dx;
        m_eye.m128_f32[1] += dy;
        m_eye.m128_f32[2] += dz;
        m_at.m128_f32[0] += dx;
        m_at.m128_f32[1] += dy;
        m_at.m128_f32[2] += dz;
        m_camera = XMMatrixTranspose(XMMatrixLookAtRH(m_eye, m_at, m_up));
        XMStoreFloat4x4(&m_view, m_camera);
    }
    
    // 規定値から移動して 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);
    }
    
    // モデルのジョイントを設定
    void MyCamera::View(float dx, float dy, float dz)
    {   XMMATRIX    mat;
        mat = XMMatrixRotationRollPitchYaw(dx, dy, dz);
        XMStoreFloat4x4(&m_view, mat * m_camera);
    }
    
    // モデルの回転
    void MyCamera::Model(float rx, float ry, float rz)
    {   XMMATRIX    mat;
        mat = XMMatrixRotationRollPitchYaw(rx, ry, rz);
        XMStoreFloat4x4(&m_model, mat);
    }
    
    // 中心点を 0,0,0 として、座標 pos を rt で回転する
    float3 MyCamera::MatRotate(float3 pos, float3 rt)
    {
        XMMATRIX    mat;
        XMVECTOR    vect;
        vect = XMVectorSet(pos.x, pos.y, pos.z, 0.0f);
        mat = XMMatrixRotationRollPitchYaw(-rt.x, -rt.y, -rt.z);
        vect = XMVector3TransformNormal(vect, mat);
        return f3(XMVectorGetX(vect), XMVectorGetY(vect), XMVectorGetZ(vect));
    }
    
    float3 MyCamera::f3(float x, float y, float z)
    {
        float3 wf3;
        wf3.x = x;
        wf3.y = y;
        wf3.z = z;
        return wf3;
    }
    
    // モデルの描画環境を計算
    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);
    }
    

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