[戻る]

ゲームの操作遅延問題について

注)2009/10/29 時点の情報に基づいた内容です。現状とは合致しない可能性があります。
ゲームの操作遅延とは、 コントローラ操作がモニタに反映されるまでのタイムラグのことです。 近年、操作遅延は増大傾向で、ゲーム性への悪影響が懸念されています。 本文書では、 操作遅延の発生要因、ゲーム性への影響、測定方法、ゲーム作成者側に求められる配慮、ユーザー側で可能な対策 などをまとめます。

操作遅延の発生源

  • コントローラのレベルで生じる遅延

  • 昨今の OS 環境では、コントローラ入力は瞬時にはゲームプログラムに伝えられません。 OS 層はコントローラ入力を定期的に読み取っています。 ゲームプログラムが取得できるのは、OS 層が直前に読み取った結果のコピーです。 そのため OS 層の読み取り間隔分の遅延が発生します。

    OS 層がコントローラ入力を定期的に読み取ることを「ポーリング」、 秒間読み取り回数を「ポーリングレート」と呼びます (「リフレッシュレート」と呼ぶこともあります)。

  • ゲームプログラムのレベルで生じる遅延

  • ゲームプログラムがコントローラ入力を取得してから グラフィクス描画処理を開始するまでに時間がかかる場合、 それだけ遅延が発生します。

  • グラフィクスアクセラレータの描画処理で生じる遅延

  • ゲームプログラム同様、 グラフィクスアクセラレータの描画処理にも時間がかかり、 遅延発生の原因となります。 加えて近年、グラフィクスのレンダリングパイプラインが深くなっており、 それだけ遅延量も増大しています。

  • モニタのレベルで生じる遅延

  • 現在主流の液晶系モニタには、大きな遅延があります。 特にハイエンドのモニタでは、 画質向上のため、 モニタ内部に複数のフレームをバッファリングして解析を行ったのち補正表示するため、 大きな遅延が発生することがあります。

  • OS/低レベル API 層で生じる遅延

  • ゲームプログラムからグラフィクスアクセラレータに発行された命令は、 即座には伝えられず一旦 OS/API 層がバッファリングすることがあります (このバッファ量は、先読みレンダリング量と呼ばれます)。 また、グラフィクスアクセラレータが生成した画像も、 即座にモニタに表示されず一旦 OS 層がバッファリングすることがあります (Windows Aero 利用時など)。 どちらも、遅延の原因となります。

操作遅延がプレイヤ操作に与える影響

  • 人間の最短応答時間 = 約 0.20 秒

  • 人間が、
    視覚で認識 → 判断 → 操作
    の一連の動作にかかる最短時間は、およそ 0.20 秒です。 これは、複数の被験者に対して行われたある実験の測定結果で、 ゲームのプレイスキルに関わらず、数字にはほとんど個人差がありません。 (ソースは、何かの NHK の検証番組です。 追試したいところですが、ここでは 0.20 秒という数字を信用することにします。)

  • モニタ 60Hz 時 1 フレーム遅延 = プレイヤの最短応答時間 8.3% 増大

  • モニタが 60Hz に設定されているとすると、 1 フレーム遅延するということは、 プレイヤの最短応答時間が 8.3% 増大することになります。 (0.20 秒から 16.7 ミリ秒増大する = 8.3% 増大)

  • コントローラ入力 10 ミリ秒遅延 = プレイヤの最短応答時間 5.0% 増大

  • USB 接続のコントローラでは、ポーリングレートはおよそ 100Hz です。 この場合、最大 10 ミリ秒の遅延があり、 プレイヤの最短応答時間は、最大で 5.0% 増大します。 (0.20 秒から 10 ミリ秒増大する = 5.0% 増大)

ギリギリの戦いを強いられるアクションゲームやシューティングゲームなどのジャンルを考えると、 8.3% だとか 5.0% だとかのオーダーは、到底許容できるものではありません。

操作遅延を体感してみよう

  • 操作遅延体感 二重盲検テスト

  • 「そもそも 1/60 秒単位の差なんて人間に知覚できるわけない」
    と思われる方もいるかもしれません。しかし、
    「いや、体感できる」
    と反証しようにも、どう証明したものかという問題があります。

    そこで、人間が 1 フレーム単位の遅延を体感できるかどうかを 二重盲検法 により確認するプログラムを作成しました。
    Download(for Windows only)
    プログラムを起動したら、まず始めに遅延量を選択してください。 続いて、遅延有り無しの 2 つのサンプルが与えらるので、 space キーで 2 つのサンプルを切り替えながら、 ジョイスティックもしくはカーソルキーで操作し、 遅延有りと考えられる方のサンプルを enter キーで選択してください。 20 問解答すると的中率が表示されます。

    的中率が 50% 付近だと、遅延が全く体感できていないということを意味します。 徐々に遅延量を少なくして、どのあたりの遅延数まで体感できるかを確認してみてください。

  • 1/60 秒の遅延は確かに体感できる(但し個人差に左右される)

  • 二重盲検テストの結果、 被験者の個人差、テスト環境の PC の差、等々により数字にブレはありますが、 概ね以下のような結果が得られました。

    • 1 フレーム or 3 フレーム遅延 の識別は可能
    • 1 フレーム or 2 フレーム遅延 の識別は可能な人不可能な人が分かれる
    • 1 フレーム or 2 フレーム遅延 の識別で 100% 近い的中率を出す人も居る

    ここではザックリと、
    「1/60 秒の遅延は確かに体感できる(但し個人差に左右される)。」
    という結論が得られたことにして、話を進めます。

レトロゲームの復刻版をプレイすると操作感が違っている理由

昔やりこんだレトロゲームの復刻版をプレイすると、 プレイ感覚が違っていると感じることがあります。 昔ほどうまくプレイできないので、
「年を取ってウデが鈍ったのかな?」
と思うことがあります。 しかし実際には、その原因は遅延にある場合が多いです。 昔のゲームハードと現在のゲームハードで、 どのような違いが生じているのか比較してみます。
  • 昔のゲームハード = 遅延が少ない

  • コントローラは電気回路で直結で、 入力値は即座にゲームプログラムに伝えられます。 ゲームプログラムが発行した描画リクエストは、 即座にスプライトレジスタに伝えられます。 スプライトはラスタ方式のため、 そのフレーム中に画面に反映されます。 モニタはブラウン管方式のため、 表示遅延はほぼゼロです。

  • 現在のゲームハード = 遅延が大きい

  • コントローラ入力は、 OS 層が定期的に監視したものを API 越しで取得するスタイルです。 一般的な USB コントローラでは、 ここで 10 ミリ秒程度の遅延が発生します。 ゲームプログラムが発行した描画リクエストは、 フレームバッファの裏画面に描画されて、 次のフレームで実際に表示されます。 ここで約 1 フレームの遅延が発生します。 モニタは液晶方式のため、 遅延が少ないとされるモニタでも 1 フレームの遅延が発生しています。

    モニタが 60 Hz だとした場合、 合計すると少なく見積もっても 43.3 ミリ秒の遅延となります。 プレイヤの最短応答時間 = 約 0.20 秒とした場合、21.7% の応答時間増大となります (実際にはこの他の要因の影響により、遅延はさらに増大します)。

    というわけで、操作感覚が違うと感じた原因はプレイヤ自身のウデの衰えではありません。 よかったよかった。 じゃなくて、これは見過ごせない問題です。

とくにひどいのは液晶モニタの遅延

遅延の原因の中で、とくに目立つのが液晶モニタの表示遅延です。 2 フレーム以上の遅延がザラに起きているという無法地帯です。
  • 液晶の欠点 = 応答速度が低い

  • 液晶はもともと応答速度が低いという性質があります。 液晶モニタでは、 ピクセルがある色から別の色に移行するには結構な時間がかかります。 RGB 別に移行時間が異なることがあり、 残像が見えたり、 移行中に見えないはずの色が見えたりと、 アーキテクチャの特性が抱える様々な欠点があります。

  • 液晶の応答速度を上げると遅延は増大してしまう

  • 液晶の欠点を克服するため、 応答速度を向上させるオーバードライブと呼ばれる仕組みがあります。 これは、色の移行に時間がかかるピクセルに対して、 一時的に高い電圧をかけることで、 移行時間を短縮するというものです。

    オーバードライブ量を決定するため、液晶モニタは、 内部で過去のフレームで表示した絵と今回のフレームで表示する絵の差分を取って、 解析を行ったのち補正しながら表示を行います。 より高度な解析を行うため、複数フレームをバッファリングする例もあり、 遅延増大の主な原因になっています。

    (※2011/03/03 加筆:オーバードライブ処理をラスタ単位で行い、 即座にモニタに反映することで遅延を最小限に抑える機種が出て来ました。 オーバードライブ=遅い、と一概には言えなくなってきています。)

  • 「液晶の中間色応答が速い = 遅延が少ない」ではない

  • よくある誤解として、 中間色応答速度と表示遅延の混同がありますが、 これらは全く異なるものです。

    中間色応答速度が速いということは、 それだけ内部で複数フレームにまたがる高度な解析を行っている可能性があり、 遅延はむしろ増大すると考えられます。

    「中間色応答速度」というカタログスペックだけを頼りに液晶モニタを選択すると、 遅延が大きく、むしろゲームには不向きの製品を選んでしまう、という事が起こりえます。

    液晶モニタのカタログスペックとして、 中間色応答速度の表示はよく見かけますが、 遅延フレーム数が明らかにされているという事例はあまり見かけません。 中間色応答速度との両立が難しいため、 オープンにしにくいという事情があるのだと思います。

  • 中間フレーム生成を行うタイプの倍速 = 遅延が大きい

  • これまたよくある誤解なのですが、 「2 倍速(120fps)」や「4 倍速(240fps)」などの機能は、 映像をスムーズにはしますが、遅延を増大させます。

    メーカーの実装によって異なりますが、 倍速モードは概ね以下のようなアプローチで実現しています。

    1. 隣接するフレームの画像の動きを、動画圧縮アルゴリズムと似たブロックマッチングにより解析
    2. 解析結果に基づき、隣接するフレームを補間して表示

    したがって、 補間先の画像が得られて解析が終了してから補間元の絵が表示され始めることとなり、 最低でも(60fps 換算で)1 フレーム + ブロックマッチング解析時間の遅延が発生します。

モニタの遅延を測定する方法

  • 遅延測定方法の必要性 「測定されないものは改善されない」

  • ゲームにとって遅延がこれだけ問題となるにも関わらず、 それに関して議論されることや、 改善しようという動きはあまり見られません。

    「測定されないものは改善されない」という言葉があります。 体感量でしか測定できないパラメータが、 定量的に測定できる手段が確立されて初めて、 あいまいな議論を回避し、 改善に向けた考察が可能になります。 なによりまず必要なのは、確実な遅延測定方法です。

  • 液晶モニタの遅延測定方法

  • ローテクですが、良い方法があります。 デスクトップをデュアルモニタ設定にして、 液晶モニタとブラウン管モニタに同じ絵を表示できる状態にします。 そしてスロットマシンのようなアニメーションを表示し、 デジカメでスクリーンショットを取り比較します。

    この用途で、良いツールがあります。
    LCD Delay Checker で検索
    最近では、 このツールで様々なモニタを測定した結果のまとめ wiki なども充実しているようです。

    しかしこの方法ではまだ不完全かもしれません。 モニタ出力にドライバ層が介在しており、 液晶モニタとブラウン管モニタに、 全く同じタイミングで映像が送信されているとは限りません。

  • コントローラの遅延測定

  • マウス入力については、遅延を測定する良いツールがあります。
    DirectX mouserate checker で検索
    キーボードないしジョイスティック対応のものを探しているのですが、 この文書執筆時点では見つかりませんでした。

  • 遅延測定 究極の方法

  • ドライバ層の影響さえも完全に回避しつつ計測したいケースでは、 コントローラ入力とモニタに出力された映像を直接サンプリングする装置を利用するなど、 ハードウェア寄りのアプローチが必要です。 ここでは割愛します。

ゲームプログラム側で可能な遅延対策

  • Windows Aero を OFF にする

  • Windows 限定の話になります。 VISTA 以降で搭載された機能である Aero を ON にしていると、 ティアリングの出ないウィンドウ表示を実現するため、 画面フリップのタイミングが OS 側でコントロールされます。 そのため遅延を生じることになります。

    プログラムから明示的に Aero を停止するには、 DwmEnableComposition 関数を、 引数 DWM_EC_DISABLECOMPOSITION を指定して呼び出す必要があります。 ただし、この関数は VISTA 以降でのみ利用可能であり、 この関数を実装している dwmapi.lib をリンクした実行ファイルは、 XP 以前の環境では実行できなくなってしまうので注意が必要です。 XP 以前の環境でも実行できるようにするには、 dwmapi.lib はリンクせず、dwmapi.dll を自力で読み込み、 成功したら DwmEnableComposition 関数のアドレスを取得し、 実行するようにします。 具体的には、以下のようなコードになります。
        #include <dwmapi.h>
        static HMODULE s_hDwmapiDll = NULL ;
        typedef HRESULT (WINAPI *pfuncDwmIsCompositionEnabled_t)( BOOL *pfEnabled );
        typedef HRESULT (WINAPI *pfuncDwmEnableComposition_t)( UINT uCompositionAction );
            :
            :
        printf( "Load dwmapi.dll ... " );
        s_hDwmapiDll = LoadLibrary( "dwmapi.dll" );
        if( s_hDwmapiDll != NULL ){
            printf( "OK.\n" );
            printf( "GetProcAddress ... " );
            pfuncDwmIsCompositionEnabled_t pfuncDwmIsCompositionEnabled
            =   (pfuncDwmIsCompositionEnabled_t) GetProcAddress(
                    s_hDwmapiDll , "DwmIsCompositionEnabled"
                );
            pfuncDwmEnableComposition_t pfuncDwmEnableComposition
            =   (pfuncDwmEnableComposition_t) GetProcAddress(
                    s_hDwmapiDll , "DwmEnableComposition"
                );
    
            if( pfuncDwmIsCompositionEnabled != NULL
            &&  pfuncDwmEnableComposition != NULL
            ){
                printf( "OK.\n" );
                BOOL bEnabled = FALSE ;
                if( (*pfuncDwmIsCompositionEnabled)( &bEnabled ) == S_OK ){
                    if( bEnabled ){
                        printf( "Disable Aero ... " );
                        HRESULT ret ;
                        ret = (*pfuncDwmEnableComposition)( DWM_EC_DISABLECOMPOSITION );
                        if( ret == S_OK ){
                            printf( "OK.\n" );
                        } else {
                            printf( "failed. result=0x%08X \n" , ret );
                        }
                    } else {
                        printf( "Aero is already disabled.\n" );
                    }
                }
            } else {
                printf( "failed.\n" );
            }
        } else {
            printf( "failed.\n" );
        }
    
    なお Aero の状態は、アプリケーション終了時に自動的に復帰されます。

  • Lock Unlock Flip のタイミング

  • Windows の DirectDraw 限定の話になります。 描画結果をサーフェスに転送するための Lock Unlock メソッド、 及び 描画用サーフェスと表示用サーフェスを交換する Flip メソッドが、 それぞれどのような負荷特性を持っているかを把握することで、 遅延を軽減することができます。

    一般的なセオリーに従うなら、 Lock〜Unlock の期間はなるべく短く保ちたいところなので、
    	for(;;){
    	    ゲーム処理
    	    Lock
    	    描画結果出力
    	    Unlock
    	    Flip
    	}
    
    という処理順序のループを組みますが、 これでは遅延が増大してしまいます。

    フルスクリーンモードの場合、 Flip メソッドは vsync を予約するだけで瞬時に完了します。 そして Lock メソッド実行時に、予約された vsync の完了待ちが発生します。 従って先の例では、ゲーム処理と描画結果出力の間で、 無駄に vsync 待ちを行うことになってしまいます (nVidia の GeForce 7xxx/8xxx 対応ドライバの実装で確認。 ビデオカードベンダ依存の振る舞いかもしれませんが)。

    この問題を回避するには、セオリーには従わず以下のようにします。
    	for(;;){
    	    Lock
    	    ゲーム処理
    	    描画結果出力
    	    Unlock
    	    Flip
    	}
    
    ただし、この処理順序を用いる場合、 ゲーム処理内でクラッシュ発生時にフルスクリーンモードから正しく復帰しなくなるなど、 様々な不都合が生じてしまいます。 それを覚悟の上で導入を検討する必要があります。

  • トリプルバッファリングを利用しない

  • 現在のフレームの描画結果を表示する表バッファと、 次のフレームの描画を行う裏バッファとは別に、 もう 1 枚緩衝用のバッファを用意する、 トリプルバッファリングと呼ばれる手法があります。

    トリプルバッファリングを利用すると、 vsync を取らず表画面と裏画面のフリップをしても、 ティアリングが発生しないというメリットがあります。 また、ゲーム画面表示を 1 フレーム遅延させておくことができ、 瞬間的に処理負荷が増大しても、 ゲーム表示側をフレーム落ちさせないという効果も期待できます。

    良い事ずくめのようなトリプルバッファですが、 遅延を増大させることになるので、 アクション性の高いゲームでは利用しない方が良いです。

  • 遅延の少ないレンダリングパイプラインを組み立てる

  • より豪華な絵を出すため、 凝ったレンダリングパイプラインを組むのは悪いことではありませんが、 手法によっては遅延が増大するので注意が必要です。

    プログラマが盲目的に技術を投入した結果、遅延が増大してしまい、 肝心のゲームプレイ体験の部分がスポイルされてしまっている という残念な事例が実際に存在します。

    技術を選択する際、対象とするゲームがどのような性質のものなのかを考慮して、 よく吟味する必要があります。

  • 遅延の大きな環境を前提としたバランス調整を行う

  • プレイヤの環境によって遅延量が異なるので、 ギリギリの反射速度を問うようなゲームデザインは控えた方が良いです。 身も蓋も無いですが、残念ながらこれが現実です。

    シューティングゲームなら、 高速な敵弾は抑え目にし、 弾幕密度で難易度調整するデザインが適しています。 アクションゲームなら、 エイミングなどのプレイヤ動作補正を積極的に導入して、 インタラクティブムービー仕上げにします。

    ビートマニアのようなリズムゲームの場合は、 遅延のキャリブレーション機能をゲーム内コンフィグなどに用意する必要があります。

    ゲームバランスの調整は遅延が大きめのモニタを基準に行います。 モニタの遅延は、 最大で 4 フレームぐらいを目安に考えた方が良いでしょう。

ユーザー側で可能な遅延対策

  • モニタをゲームモードに設定する

  • ゲームモードを搭載しているモニタの場合、 有効にすることで遅延を少なくすることができます。

  • モニタの解像度を適切に設定する

  • ゲーム画面(デスクトップ)の解像度と、 モニタの解像度が一致しない場合、モニタ内部で解像度変更処理が仲介し、 遅延が増大することがあります。 モニタの解像度はドットバイドットになるように設定したほうが良いでしょう。

  • フルスクリーンモードでなく Window モードを選択する

  • Windows 限定の話になります。 vsync 利用のフリップは、フルスクリーンモードでのみ可能です。 Window モードでは vsync が利用できないため、 それに由来する遅延が無くなります。 その代償としてティアリングが発生します。 遅延回避かティアリング回避かのトレードオフになります。

  • 先読みレンダリングを最小限にする

  • GPU に発行した描画リクエストは、直ちにフラッシュされず、 ある程度バッファリングされた後にフラッシュされ、解釈実行されます。 バッファリングする量が増えると、それだけ描画開始が遅れることになるので、 遅延の増大につながります。

    バッファリング量とその調整方法はビデオカードベンダ依存です。 小さくすると遅延も小さくなりますが、 逆に描画性能が低下してフレーム落ちによる遅延の元になるかも知れないので、 調整は慎重に行う必要があります。

  • コントローラのドライバを変更する

  • コントローラ入力のポーリングレートは、 ドライバを変更することで変更可能です。

    USB マウス用になりますが、 Direct Input Mouse Rate USB Mouserate Switcher というドライバがあります。 公式のものでは無いので、導入は自己責任で行ってください。 同様のドライバのキーボードないしジョイスティック対応のものを探しているのですが、 この文書執筆時点では見つかりませんでした。

  • その他

    • モニタ選び

    • 遅延の少ない液晶モニタ、もしくはブラウン管式のモニタを選択します。 液晶モニタの場合は、ゲームモードなどを搭載した機種を選びます。 遅延量の評価は、カタログスペックは信用せず、実測値で行います。

    • キーボード選び

    • パンタグラフ式などの、ストロークの浅いキーボードを選択します。 ポーリングレートの高い製品を選択します。

    • マウス選び

    • ドライバを変更することで、ポーリングレートを向上させます。 もしくは、ポーリングレートの高い製品を選択します。 主に FPS プレイヤを対象とした、 ゲーミングマウス と呼ばれるカテゴリの製品が多く発売されています。

    • ジョイスティック選び

    • 遊び(入力がニュートラルになる範囲)の少ないジョイスティックを選択します。 より少ない手の移動で入力を発生させるため、 軸が短いジョイスティックを選択します(シューティングゲーム用途なら、 セイミツ工業の LS-32-01 がオススメ)。 既製品ではなかなか良いものが無いので、基本的に自作の世界になります。

    • ジョイスティックの持ち方

    • かぶせ持ちよりはワイン持ちの方が、 より少ない手の移動で入力を発生させる事ができます。

最後に

  • 次世代モニタに期待

  • 有機 EL は遅延が少ない、 SED 方式は遅延がほぼゼロであると聞きます。 早くこれらのアーキテクチャのモニタを実用レベルに乗せて、 液晶モニタを淘汰して欲しいですね。

    しかし、モニタが次世代に移行しても、 古い世代の液晶モニタを利用しているユーザーは、 急には移行して来ないので、 彼らに対して配慮したゲームデザインにする必要性は依然と残り続けます。

    アクション性の高いゲームにとっては、 つらい時期がしばらく続きそうな気配です。

[戻る]