フレームレートを制御する

Direct3Dに限った話ではありませんが、PCのアプリは、フレームレートを制御する必要があります。 ゲーム機のように、固定されたリフレッシュレートに合わせてフレームレートを決めることができる場合は、 VSyncを待つだけでフレームレートを制御できますが、PCのモニターはリフレッシュレートが様々なので、アプリ自身がフレームレートを制御する必要がでてきます。

Direct3D12で解像度とリフレッシュレートを設定する

ウィンドウモードの場合は解像度はウィンドウサイズを変更することで設定できます。(もちろん、RTVは作り直します。) しかし、ウィンドウ単位でリフレッシュレートは設定できません。

リフレッシュレートを変更するためには、フルスクリーンで動いている必要があります。 前回の記事で、フルスクリーンへの切り替え方法を書きましたので、今回はその続きになります。

Direct3D12でフルスクリーンに切り替える

ChatGPT先生に聞きながら、Direct3D12でフルスクリーンモードとウィンドウモードの切り替えを実装しました。 F11キーを押すことで切り替えるというものです。

SampleApp g_app;

extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    // ImGuiのウィンドウ処理
    if (ImGui_ImplWin32_WndProcHandler(hWnd, message, wParam, lParam)) {
        return true;
    }

    static bool isFullscreen = false;
    static bool isFullscreenInActive = false;
    static WINDOWPLACEMENT windowPlacement = { sizeof(WINDOWPLACEMENT) }; // ウィンドウモード時の位置とサイズを保存

    switch (message) {
    case WM_DESTROY:
        g_app.SetFullscreenState(FALSE);
        PostQuitMessage(0);
        return 0;
    case WM_KEYDOWN:
        if (wParam == VK_F11) { // F11キーで切り替え
            if (isFullscreen) {
                // ウィンドウモードに戻す
                g_app.SetFullscreenState(FALSE);
                SetWindowLong(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
                SetWindowPlacement(hWnd, &windowPlacement); // 以前のウィンドウの位置とサイズを復元
                SetWindowPos(hWnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
                isFullscreen = false;
            }
            else {
                // フルスクリーンモードにする
                GetWindowPlacement(hWnd, &windowPlacement); // 現在のウィンドウの位置とサイズを保存
                SetWindowLong(hWnd, GWL_STYLE, WS_POPUP | WS_VISIBLE); // ウィンドウの境界線とタイトルバーを削除
                SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
                //SetWindowPos(hWnd, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_FRAMECHANGED);
                g_app.SetFullscreenState(TRUE);
                isFullscreen = true;
            }
        }
        return 0;
    case WM_SIZE:
        if (wParam != SIZE_MINIMIZED) {
            UINT width = LOWORD(lParam);
            UINT height = HIWORD(lParam);

            g_app.SetScreenSize(width, height);
        }
        break;
    case WM_ACTIVATE:
        if (wParam == WA_INACTIVE) {
            // ウィンドウが非アクティブになった場合
            if (isFullscreen) {
                // フルスクリーンモードからウィンドウモードに戻す
                g_app.SetFullscreenState(FALSE);
                SetWindowLong(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
                SetWindowPlacement(hWnd, &windowPlacement); // 以前の位置とサイズを復元
                SetWindowPos(hWnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
                isFullscreenInActive = true;
            }
        }
        else if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) {
            // ウィンドウが再度アクティブになった場合
            if (isFullscreenInActive) {
                // 必要ならフルスクリーンに戻す
                SetWindowLong(hWnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
                SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
                g_app.SetFullscreenState(TRUE);
                isFullscreenInActive = false;
            }
        }
        return 0;
    default:
        break;
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}

	

Direct3D12でimguiを使ってみる

Direct3Dのアプリを書くには、デバッグ描画が必要です。デバッグ描画とは、例えば、画面上にフレームレートや様々な設定を描画するものです。 最終的な商品では使われないものなので、切り離してコンパイルできるように作りたいです。

Direct3D12アプリを書いてみる(3)

Direct3D12は、描画コマンドをコマンドリストにバッファリングして、まとめて実行するという形式となります。 毎フレーム実行する処理を簡易的に書くと以下のようになります。

{
    // コマンドリストの開始
    commandAllocator->Reset();
    commandList->Reset(commandAllocator.Get(), pipelineState.Get());

    // 様々な描画コマンドを実行して、コマンドリストを作成
    ...

    // バッファリングされたコマンドリストを実行
    commandList->Close();
    ID3D12CommandList* commandLists[] = { commandList.Get() };
    commandQueue->ExecuteCommandLists(_countof(commandLists), commandLists);

    // スワップチェーンの表示
    swapChain->Present(1, 0);
}

	

Direct3D12アプリを書いてみる(2)

まず、Direct3D12のプログラムを説明する前に、Windowだけを表示するプログラムを書きます。 基本的には、CreateWindowでWindowを生成し、メインループでメッセージを処理するだけです。

Direct3D12アプリを書いてみる(1)

まず、Direct3D12のアプリをビルドするには、Direct3D12のヘッダファイルをインクルードして、ライブラリファイルをリンクする必要があります。 以前であれば、DirectX SDK というものをダウンロードして、VisualStudioのインクルードとリンクの設定を書けばよかったのですが、 今は、DirectX SDKはなくなってしまい、Windows SDK に含まれているようです。

ホームページの作成

まず、3DCG関連の記事を書く前に、このホームページの作り方をまとめておこうと思います。

このホームページは、Hugoを使って作成しています。

Web系の技術には詳しくないので、WordPressやMovableTypeといったCMSを使ってホームページを作ろうと思っていました。しかし、調べてみると、自分なりにカスタマイズさせることが難しそうだったので、マークダウンで書いたものから静的なページを作成してくれるHugoを使ってみることにしました。テーマはとりあえずMainroadというものを選びました。

はじめに

はじめまして。

最初の記事となりますので、筆者の紹介をしておきます。

折本と申します。

長年、東京や大阪で3DCG関連のプログラマーとして働いてきましたが、2024年10月からは、広島に移住して業務委託という形でフルリモートの仕事をしつつ、この技術ブログを書いていきたいと思います。