Win10 Cube



Windows10 のカラーキューブを描画するプロジェクトを解析します。

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

サンプルプロジェクト

  1. Windows10(Store App) DirectX のカラーキューブを描画するプロジェクトを解析します。
    フォルダーの構成がシンプルで XAML が組み込まれていない DirectX 11 アプリ(ユニバーサル Windows)を例にします。
  2. Visual Studio 2015(Blend では無い)を起動して下さい。
    DirectX 11 アプリ(ユニバーサル Windows)を選びます。
    名前は規定値で App1 になります。

  3. 構築直後は赤色の下線でエラーが指摘されていますが、ヘッダーファイルの読み込みが完了するとエラーは消えます。
    (またはメニューバーの[ビルド]からコンパイルするとエラーは消えます。)
    コンパイル&実行してカラーキューブが回転しながら描画されるのを確認して下さい。
  4. Windows 画面の「スタート」ボタンから[すべてのアプリ]を選ぶと今作製したアプリ(App1)が登録されています。
    追加されたアイコンを右クリックしてアンインストールして下さい。
    プロジェクトを作成したフォルダーにもアプリ(App1 など)のフォルダーが作成されています。
    必要がなければフォルダーごと削除して下さい。
  5. プロジェクトを残しておく場合でも Debug\, ipch\, *.sdf は削除可能です。
    削除した状態で *.sln をダブルクリックすると Blend for Visual Studio 2015 が起動します。
    [緑色の右三角アイコン]をクリックするとコンパイル&実行が行われます。
    警告が表示されることがありますが、正常に実行されます。

プロジェクトの解析

  1. まず最初に気になる3Dカラーキューブを描画する Class は、次のファイルで定義されています。
    モデルの定義は Windows 8.1 3Dプロジェクト を参照して下さい。
    App1\Content\Sample3DSceneRenderer.cpp
    App1\Content\Sample3DSceneRenderer.h
  2. FPS を表示する Class は、次のファイルで定義されています。
    FPS(Frame per second) とは、動画の1秒あたりの静止画枚数を表す数値で、一般的には 60fps(フロップス)です。
    App1\Content\SampleFpsTextRenderer.cpp
    App1\Content\SampleFpsTextRenderer.h
  3. 最初に制御が渡される main() 関数は App1\App.cpp で定義されています。
    main 関数は、IFrameworkView クラスを初期化する場合にのみ使用します。
    [Platform::MTAThread]
    int main(Platform::Array<Platform::String^>^)
    {
        auto direct3DApplicationSource = ref new Direct3DApplicationSource();
        CoreApplication::Run(direct3DApplicationSource);
        return 0;
    }
    
  4. Direct3DApplicationSource Class は App.h で定義されています。
    ここから CreateView(); を呼び出して IFrameworkView クラスを初期化します。
    ref class Direct3DApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
    {
    public:
        virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
    };
    
  5. IFrameworkView^ CreateView() 関数は App.cpp で定義されています。
    ref new App() で App Class が生成されます。
    IFrameworkView^ Direct3DApplicationSource::CreateView()
    {
        return ref new App();
    }
    
  6. Class App の Constructor に続いて App::Initialize() が呼び出されます。
    Initialize() で DeviceResources を生成します。
    void App::Initialize(CoreApplicationView^ applicationView)
    {
        ・・・
        // デバイスに依存するリソースを作成できます。
        m_deviceResources = std::make_shared<DX::DeviceResources>();
    }
    
  7. Class App の Initialize() に続いて SetWindows() が呼び出されます。
    イベントハンドラーを設定して DeviceResources の SetWindows() を呼び出します。
    void App::SetWindow(CoreWindow^ window)
    {
        ・・・
        m_deviceResources->SetWindow(window);
    }
    
  8. Load() 関数で App1Main() Class が生成されます。
    void App::Load(Platform::String^ entryPoint)
    {
        if (m_main == nullptr)
        {
            m_main = std::unique_ptr<App1Main>(new App1Main());
            //m_main = std::unique_ptr<App1Main>(new App1Main(m_deviceResources));
        }
    }
    
  9. App1\App.cpp の Run() 関数にメッセージループがあります。
    ここから App1Main Class の Update() と Render() を呼び出します。
    // このメソッドは、ウィンドウがアクティブになると、呼び出されます。
    void App::Run()
    {
        while (!m_windowClosed)
        {
            // ***メッセージループ***
                m_main->Update();
                ・・・
                if (m_main->Render())
        }
    }
    
  10. App1\App1Main.cpp の Constructor で Sample3DSceneRenderer と SampleFpsTextRenderer を生成します。
    // アプリケーションの読み込み時にアプリケーション資産を読み込んで初期化します。
    App1Main::App1Main(const std::shared_ptr<DX::DeviceResources>& deviceResources) :
        m_deviceResources(deviceResources)
    {
        // デバイスが失われたときや再作成されたときに通知を受けるように登録します
        m_deviceResources->RegisterDeviceNotify(this);
    
        // TODO: これをアプリのコンテンツの初期化で置き換えます。
        m_sceneRenderer = std::unique_ptr<Sample3DSceneRenderer>(new Sample3DSceneRenderer(m_deviceResources));
    
        m_fpsTextRenderer = std::unique_ptr<SampleFpsTextRenderer>(new SampleFpsTextRenderer(m_deviceResources));
    
        // TODO: 既定の可変タイムステップ モード以外のモードが必要な場合は、タイマー設定を変更してください。
        // 例: 60 FPS 固定タイムステップ更新ロジックでは、次を呼び出します:
        /*
        m_timer.SetFixedTimeStep(true);
        m_timer.SetTargetElapsedSeconds(1.0 / 60);
        */
    }
    
  11. Update() 関数で更新(回転)します。
    // アプリケーション状態をフレームごとに 1 回更新します。
    void App1Main::Update() 
    {
        // シーン オブジェクトを更新します。
        m_timer.Tick([&]()
        {
            // TODO: これをアプリのコンテンツの更新関数で置き換えます。
            m_sceneRenderer->Update(m_timer);
            m_fpsTextRenderer->Update(m_timer);
        });
    }
    
  12. m_sceneRenderer->Update() から呼び出される Sample3DSceneRenderer Class の Update() 関数です。
    m_tracking はマウスで回転するときのフラグです。
    DirectX 11 および XAML アプリ(ユニバーサル Windows) で生成したときに設定されます。
    void Sample3DSceneRenderer::Update(DX::StepTimer const& timer)
    {
        if (!m_tracking)
        {
            // 度をラジアンに変換し、秒を回転角度に変換します
            float radiansPerSecond = XMConvertToRadians(m_degreesPerSecond);
            double totalRotation = timer.GetTotalSeconds() * radiansPerSecond;
            float radians = static_cast<float>(fmod(totalRotation, XM_2PI));
    
            Rotate(radians);
        }
    }
    
  13. Render() 関数でレンダリングに関係する領域をリセットして描画の準備を整えます。
    実際の描画は m_sceneRenderer->Render(); で行われます。
    // 現在のアプリケーション状態に応じて現在のフレームをレンダリングします。
    // フレームがレンダリングされ、表示準備が完了すると、true を返します。
    bool App1Main::Render() 
    {
        // 初回更新前にレンダリングは行わないようにしてください。
        if (m_timer.GetFrameCount() == 0)
        {
            return false;
        }
    
        auto context = m_deviceResources->GetD3DDeviceContext();
    
        // ビューポートをリセットして全画面をターゲットとします。
        auto viewport = m_deviceResources->GetScreenViewport();
        context->RSSetViewports(1, &viewport);
    
        // レンダリング ターゲットを画面にリセットします。
        ID3D11RenderTargetView *const targets[1] = { m_deviceResources->GetBackBufferRenderTargetView() };
        context->OMSetRenderTargets(1, targets, m_deviceResources->GetDepthStencilView());
    
        // バック バッファーと深度ステンシル ビューをクリアします。
        context->ClearRenderTargetView(m_deviceResources->GetBackBufferRenderTargetView(), DirectX::Colors::CornflowerBlue);
        context->ClearDepthStencilView(m_deviceResources->GetDepthStencilView(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
    
        // シーン オブジェクトをレンダリングします。
        // TODO: これをアプリのコンテンツのレンダリング関数で置き換えます。
        m_sceneRenderer->Render();
        m_fpsTextRenderer->Render();
    
        return true;
    }
    
  14. m_sceneRenderer->Render() から呼び出される Sample3DSceneRenderer Class の Render() 関数です。
    context->DrawIndexed() で、グラフィックス デバイスに送信したモデルデータを描画します。
    void Sample3DSceneRenderer::Render()
    {
         ・・・
        // モデルデータをグラフィックスデバイスに送信して描画の準備を整える
         ・・・
        // オブジェクトを描画します。
        context->DrawIndexed(
            m_indexCount,
            0,
            0
            );
    }
    

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