Win10 Model & Camera

Windows10 DirectX3D で Model と Camera を組み込んでマウスで回転します。
次に KeyDown, KeyUp を検出してモデルを回転します。

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

Model を組み込む

  1. DirectX 11 および XAML アプリ(ユニバーサル Windows)を生成します。
    XAML アプリには最初からマウスの操作でY軸回転する機能が組み込まれています。
    Normal Model(頂点+法線のモデル)を生成する Class CreateModel を組み込みます。
    モデルを描画する Class MyCamera を組み込みます。
  2. Content に次のファイルを格納します。
    ファイル 説明
    Shader 関係のファイル 頂点+法線のモデルを描画する Shader 関係のファイル
    Content\CreateModel.h CreateModel の Header File
    Content\CreateModel.cpp CreateModel の Program File
    Content\MyCamera.h MyCamera の Header File
    Content\MyCamera.cpp MyCamera の Program File
  3. Sample3DSceneRenderer.h を修正します。
    キーでモデルを操作する領域も含んでいます。
    #include "CreateModel.h"
    #include "MyCamera.h"
        CreateModel     *m_CreateMode;
        MyCamera        *my_camera = nullptr;
        float           m_x, m_y, m_z;
        float           m_dx, m_dy, m_dz;
    
  4. Sample3DSceneRenderer.cpp を修正してモデルを描画します。
        {"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0},
    
        // 両方のシェーダーの読み込みが完了したら、メッシュを作成します。
        auto createCubeTask = (createPSTask && createVSTask).then([this] () {
            m_CreateMode = new CreateModel(m_deviceResources);
            m_CreateMode->CreateCube(&m_vertexBuffer, &m_indexBuffer, &m_indexCount);
        });
    
  5. Create Model の 詳細は Win10 Create Model を参照して下さい。

MyCamera を組み込む

  1. Sample3DSceneRenderer.cpp で my_camera を生成します。
    Sample3DSceneRenderer::Sample3DSceneRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
        m_loadingComplete(false),
        m_degreesPerSecond(45),
        m_indexCount(0),
        m_tracking(false),
        m_deviceResources(deviceResources)
    {
        CreateDeviceDependentResources();
        CreateWindowSizeDependentResources();
        my_camera = new MyCamera(m_deviceResources);
    }
    
  2. CreateWindowSizeDependentResources() では Projection() を呼ぶだけです。
    void Sample3DSceneRenderer::CreateWindowSizeDependentResources()
    {
        if (my_camera!=nullptr) my_camera->Projection();
    }
    
  3. Rotate() 関数では Y軸回転を my_camera->m_model に設定します。
    void Sample3DSceneRenderer::Rotate(float radians)
    {
        XMStoreFloat4x4(&my_camera->m_model, XMMatrixTranspose(XMMatrixRotationY(radians)));
        //m_x += m_dx;
        //m_y += m_dy;
        //m_z += m_dz;
        //my_camera->View(m_x, m_y, m_z);
    }
    
  4. Render() では MyCamera のデータを m_constantBufferData に設定して描画します。
    void Sample3DSceneRenderer::Render()
    {
        // 読み込みは非同期です。読み込みが完了した後にのみ描画してください。
        if (!m_loadingComplete) {  return;  }
    
        auto context = m_deviceResources->GetD3DDeviceContext();
        m_constantBufferData.projection = my_camera->m_projection;
        m_constantBufferData.view = my_camera->m_view;
        m_constantBufferData.model = my_camera->m_model;
    
        // 定数バッファーを準備して、グラフィックス デバイスに送信します。
        ・・・
    
  5. MyCamera Class は、次の関数が定義されている Version を使って下さい。
    #pragma once
    #include "..\Common\DeviceResources.h"
    
    class MyCamera
    { public:
        MyCamera(std::shared_ptr<DX::DeviceResources>& deviceResources);
        void Projection();
        void Camera(DirectX::XMVECTOR eye, DirectX::XMVECTOR at, DirectX::XMVECTOR up);
        void Model(float rx, float ry, float rz);
        void View(float dx, float dy, float dz);
    
        DirectX::XMVECTOR   m_eye = { 0.0f, 0.7f, 1.5f, 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::XMFLOAT4X4 m_projection;
        DirectX::XMFLOAT4X4 m_view;
        DirectX::XMFLOAT4X4 m_model;
    
      private:
        std::shared_ptr<DX::DeviceResources> m_deviceResources;
    };
    
    void MyCamera::View(float dx, float dy, float dz)
    {   XMMATRIX    view, mat;
        view = XMMatrixTranspose(XMMatrixLookAtRH(m_eye, m_at, m_up));
        mat = XMMatrixRotationRollPitchYaw(dy, dx, dz);
        XMStoreFloat4x4(&m_view, mat * view);
    }
    

X軸,Y軸で回転

  1. MyCamera を使ってマウス操作でX軸とY軸で回転します。
    DirectXPage.xaml.cpp の OnPointerMoved() でX座標とY座標を渡します。
    void DirectXPage::OnPointerMoved(Object^ sender, PointerEventArgs^ e)
    {
        if (m_main->IsTracking())
        {
            m_main->TrackingUpdate(e->CurrentPoint->Position.X, e->CurrentPoint->Position.Y);
        }
    }
    
  2. App1Main.h でX座標とY座標を受け取って保存します。
        float m_pointerLocationX;
        float m_pointerLocationY;
    
        void TrackingUpdate(float positionX, float positionY)
        {
            m_pointerLocationX = positionX;
            m_pointerLocationY = positionY;
        }
    
  3. App1Main.cpp の Constructor で m_pointerLocationX と m_pointerLocationY をリセットします。
    これらの値は OnPointerMoved() から呼び出される m_main->TrackingUpdate() で更新されます。
    ProcessInput() 関数から m_sceneRenderer->TrackingUpdate() を呼ぶときにこれを渡します。
    App1Main::App1Main(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
        m_deviceResources(deviceResources),
        m_pointerLocationX(0.0f),
        m_pointerLocationY(0.0f)
    
    void App1Main::ProcessInput()
    {
        m_sceneRenderer->TrackingUpdate(m_pointerLocationX, m_pointerLocationY);
    }
    
  4. Sample3DSceneRenderer の TrackingUpdate() 関数 で my_camera->m_model に設定します。
        void TrackingUpdate(float positionX, float positionY);
    
    void Sample3DSceneRenderer::TrackingUpdate(float positionX, float positionY)
    {
        XMMATRIX    mat;
        XMFLOAT4X4  f4x4;
        float       rx, ry;
        if (m_tracking)
        {
            rx = XM_2PI*2.0f*positionX/m_deviceResources->GetOutputSize().Width;
            ry = XM_2PI*2.0f*positionY/m_deviceResources->GetOutputSize().Height;
            mat = XMMatrixRotationY(rx) * XMMatrixRotationX(ry);
            XMStoreFloat4x4(&f4x4, mat);
            my_camera->m_model = f4x4;
        }
    }
    
  5. Render() 関数では MyCamera のデータを m_constantBufferData に設定して描画します。
    回転の詳細は Win10 MouseRot を参照して下さい。

キーで操作する

  1. 次はマウスに加えてキーでモデルを操作します。
    まず KeyDown, KeyUp を検出して出力ウインドウにメッセージを表示します。
    DirectXPage.xaml.h に次の関数を定義して下さい。
        void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
        void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
    
  2. DirectXPage.xaml.cpp にイベントハンドラを設定します。
    DirectX 11 および XAML アプリ(ユニバーサル Windows) では、Window::Current->CoreWindow でウインドウのハンドルを取得することが出来ます。
    DirectXPage::DirectXPage():  m_windowVisible(true), m_coreInput(nullptr)
    {
        InitializeComponent();
        CoreWindow^ window = Window::Current->CoreWindow;
          ・・・
        window->KeyDown +=
            ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &DirectXPage::OnKeyDown);
        window->KeyUp +=
            ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &DirectXPage::OnKeyUp);
    }
    
  3. DirectXPage.xaml.cpp の OnKeyDown, OnKeyUp から App1Main の OnKeyDown, OnKeyUp を呼び出します。
    void DirectXPage::OnKeyDown(CoreWindow^ sender, KeyEventArgs^ args)
    {   if (!args->KeyStatus.WasKeyDown)
        {   m_main->OnKeyDown(args->VirtualKey);  }
    }
    
    void DirectXPage::OnKeyUp(CoreWindow^ sender, KeyEventArgs^ args)
    {   m_main->OnKeyUp(args->VirtualKey);  }
    
  4. App1Main.h に OnKeyDown, OnKeyUp を定義して下さい。
        void OnKeyDown(Windows::System::VirtualKey key);
        void OnKeyUp(Windows::System::VirtualKey key);
    
  5. App1Main.cpp の OnKeyDown, OnKeyUp から出力ウインドウにメッセージを表示します。
    void App1Main::OnKeyDown(Windows::System::VirtualKey key)
    {   OutputDebugString(L"★Key Down\n");  }
    
    void App1Main::OnKeyUp(Windows::System::VirtualKey key)
    {   OutputDebugString(L"★Key Up\n");  }
    
  6. プログラムを実行して、キーボードをタイプするとメッセージが表示されることを確認して下さい。
    次にキーのタイプでモデルを操作します。
  7. Sample3DSceneRenderer.h に次の領域を定義して下さい。
    m_x, m_y, m_z が View(m_x, m_y, m_z) で回転する値です。
    m_dx, m_dy, m_dz は m_x, m_y, m_z に毎回加える値です。
        void KeyDown(Windows::System::VirtualKey key);
        void KeyUp(Windows::System::VirtualKey key);
        float   m_x, m_y, m_z;
        float   m_dx, m_dy, m_dz;
    
  8. App1Main.cpp の OnKeyDown, OnKeyUp から Sample3DSceneRenderer の関数を呼び出します。
    void App1Main::OnKeyDown(Windows::System::VirtualKey key)
    {   m_sceneRenderer->KeyDown(key);  }
    
    void App1Main::OnKeyUp(Windows::System::VirtualKey key)
    {   m_sceneRenderer->KeyUp(key);  }
    
  9. Sample3DSceneRenderer.h で KeyDown 関数と KeyUp 関数を定義して下さい。
        void KeyDown(Windows::System::VirtualKey key);
        void KeyUp(Windows::System::VirtualKey key);
    
  10. Sample3DSceneRenderer.cpp の KeyDown 関数でキーを調べて m_dx, m_dy, m_dz を設定します。
    void Sample3DSceneRenderer::KeyDown(Windows::System::VirtualKey key)
    {   switch (key)
        {   case Windows::System::VirtualKey::Right:
                m_dx = 0.01f;   break;
            case Windows::System::VirtualKey::Left:
                m_dx = -0.01f;  break;
            case Windows::System::VirtualKey::Down:
                m_dy = 0.01f;   break;
            case Windows::System::VirtualKey::Up:
                m_dy = -0.01f;  break;
            case Windows::System::VirtualKey::Space:
                m_dz = 0.01f;   break;
            case Windows::System::VirtualKey::Enter:
                m_dz = -0.01f;  break;
        }
    }
    
  11. Sample3DSceneRenderer.cpp の KeyUp 関数で m_dx, m_dy, m_dz をリセットします。
    void Sample3DSceneRenderer::KeyUp(Windows::System::VirtualKey key)
    {   m_dx = 0.0f;
        m_dy = 0.0f;
        m_dz = 0.0f;
    }
    
  12. Sample3DSceneRenderer.cpp の Rotate 関数で m_dx, m_dy, m_dz の値を m_x, m_y, m_z に加えて View で回転します。
    void Sample3DSceneRenderer::Rotate(float radians)
    {   m_x += m_dx;
        m_y += m_dy;
        m_z += m_dz;
        my_camera->View(m_x, m_y, m_z);
    }
    
  13. これでプログラムの完成です。
    モデルの自動回転が無くなり、マウスの操作でモデルが回転します。
    キーの操作で View(m_x, m_y, m_z); で回転します。
    ←→ Y軸で回転
    ↑↓ X軸で回転
    Space Enter Z軸で回転
  14. OnKeyDown の簡単なプロジェクトは[超初心者のプログラム入門(C/C++)]から[VC-2017 Key Count]を参照して下さい。
    GetAsyncKeyState() でキーを取得する方法は Win10 KeyRot を参照して下さい。

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