2017/01/12

ゲーミングデバイスが1680万色に光る理由

ゲーミングデバイスって1680(書き方によっては1677万色)に光りますが,なぜ1680万色なのでしょうか?
これはゲーミングデバイス内のMCU(マイコン)の都合だったりします.

ゲーミングデバイスのLED制御

一般的に,ゲーミングデバイスではLEDの明るさをパルス幅変調(PWM)を用いて変えています.
PWMは,ONとOFFを切り替えることで時間あたりの平均的な電力を変える方法です.

つまり,フィラメント電球を使った理科の実験のように電圧を上下させてLEDの明るさを変えるのではなく,人間の目では知覚できない速さでON/OFFを切り替えることで明るさを変えるわけですね.人間の目では明るかったり暗かったり色々な色に見えているわけですが,マイコン的にはとても素早くLEDを点滅させているだけなのです.ここで,明るさの度合いは,ONとOFFの比率(デューティー比)を変えることで調整しています.


G302のLEDの点滅の様子をハイスピード撮影で見てみましょう.動画の撮影は1200fpsで行い,30fpsで再生しています.
まずは暗いときの場合です.


次に明るい時の場合です.

このように,LEDは目に見えない速度で点滅しています.また,点灯する時間を変えることで,見かけ上の明るさを調整していることがわかります.

PWMと色の関係

さて,PWMで明るさを変えるにはデューティー比を変えれば良いことが分かりましたが,デューティー比はマイコンでどのように設定しているのでしょうか.

よくあるのは8bitの変数を使ってデューティー比を表現する場合です.16bitやそれ以上のbit数もマイコンによっては可能だったりしますが,bit数を増やすとマイコンのリソースを使います.所詮は装飾ですし,人の目はそんなに細かく色を見分けられないので,デューティー比は8bitが多いでしょう.
8bitの変数は,(正負の区別をしない場合)0から255の値をとることができます.つまり,0から255のデューティー比で明るさを表現できます※1

そしてRGBな製品の場合,光の三原色である赤(Red,R),緑(Green,G),青(Blue,B)の3色のLEDを搭載しています.そこで,LED1色ごとに256パターンで明るさを表現して,3色合わせると256の3乗になります.つまり,256の3乗で16777216パターン,約1680万色ということになります.


※1
「1色あたり0~100とかのほうが分かりやすいのでは?」と思う方も多いと思いますが,マイコンは基本的に2進数で物を考えており,特に8bit単位(例: 8,16,32bit)でマイコン内部の機能を制御したがります.無理やり0~100などの10進法的にキリの良い数字で制御することもできますが,内部の機能は8bit単位の値しか受け付けないので,それに直すために余計な計算が必要になりますし,プログラマ的には特に意味がないので,8bitで制御することが多いようです.

2017/01/04

2017年

あけましておめでとうございます.今年も#LogicalGaming#LogicalGamingGlobal@systema_ をよろしくお願いします.

ブログを立ち上げてから3年が経ちましたが,徐々にページビューやTwitterのフォロワーが増えてきて,望外の喜びです.いつもRT/Favなどなどありがとうございます.


2016年のまとめ

毎年恒例ですが,昨年1年間を簡単に振り返ります.

マウスのスクロールホイールを3Dプリントする

http://logical-gaming.blogspot.jp/2016/02/3d.html
マウスの部品を3Dプリントして使ってみたという記事です.やってることはモデルデータを作って外注しているだけなので技術的にはまったく難しくありませんが,「可能であるということを実証した」ということに意義を見出しています.言うだけなら簡単ですが,実際に可能かどうかというのは別問題なので.
この記事では単一の部品を出力したわけですが,マウス全体の出力に適用するには,課題が存在しているかもしれません.


マウスパッド表面評価のためのセンサー可視化デバイス

http://logical-gaming.blogspot.jp/2016/04/adns-3090adns-9800framecapture.html
このブログを立ち上げた直後から取り組んでいる「ゲーミングマウス向けセンサの制御」の集大成的な記事です.ADNS-3090とADNS-9800というゲーミンググレードのセンサを制御できるようになりました.
また,ゲーミンググレードのセンサの視界を見える化することができたのは大きな進捗でしょう.これを使えばマウスパッドの良し悪しや,色々なことが分かるようになります.


DPIと振り向きとセンシティビティ

http://logical-gaming.blogspot.jp/2016/05/dpi.html
一般のゲーマー向けに書いた記事です.400DPI+センシティビティ2.0より,800DPI+センシティビティ1.0の方が理論上は優れているという話です.この記事には続きがあるので,いつか続きを上げたいですね.


描画遅延とデバイスの出力周期の関係に関する一考察

http://logical-gaming.blogspot.jp/2016/12/blog-post.html
ポーリングレートやフレームレートが変わると遅延の期待値が変化する,というのを理論的?に説明した記事です.この記事では,ポーリングレートなりフレームレートは高ければ高いほど良いということを示しました.
よく「モニタのリフレッシュレート以上にフレームレートが出てれば十分」,「マウスのポーリングレートは何でも良い」などと言いますが,実際には高ければ高いほど有利になるということが分かりました.皆さんもGTX1080で最低設定+640x480でプレイしましょう().


ゲーミングマウス向けのUSB HIDディスクリプタ

http://logical-gaming.blogspot.jp/2016/12/usb-hid.html
ゲーミングマウスのHIDディスクリプタのテンプレートとして作成しました.マイコンにHIDマウスの機能を持たせる記事は多いですが,マウスホイールと16bitのデータパスを持つ日本語の記事は無かったので,少しは貢献できたと考えています.


ゲーミングマウスのセンサとして電磁誘導方式を考える

http://logical-gaming.blogspot.jp/2016/12/blog-post_99.html
小ネタ記事です.今のゲーミングマウスは光学式一択の現状ですが,別な方式も考えてみませんか?という提案をしました.
光学式マウスの暗黙のメリットとして「マウスパッド無しでどこでも使える」というのがありますが,「ゲーミングマウスはマウスパッドの上だけでしか使われない」という点に着目しました.「滑走面が限定されても良い」という条件なら光学式にこだわる必要はなく,絶対値で座標が取得できる方式の方が正確にトラッキングできるのでは?という提案です.


遅延測定用のファームウェア公開

日本語の記事にはしていませんが,描画遅延ネタで使っているマイコンのファームウェアを公開しました.(英語記事)
ソースコード : https://github.com/systema-tic/input-lag-test-firmware
1500円で売ってるマイコンボードとハイスピード撮影ができるカメラがあれば,簡単に描画遅延を測定できます.詳しくはreadmeに書いてあります.


近況

デバイス

今はLogicool G300r + Razer Goliathus Control Editionです.Goliathus Controlはいいマウスパッドだと思います.G300はセンサー的に厳しいですが,乗り換え先が見つからないです.

2016年も色々見ましたが,ベストなマウスパッドはCOUGAR Control(2じゃなくて無印の方)だと考えています.マウスに関しては個人の手の大きさや持ち方に大きく依存するのでなんとも言えません.個人的にはG300系でセンサー改良版が出て欲しいです.


ゲーム

5月から秋まで,PC版OverwatchのチームであるHOT-Gamingのメインタンクとしてプレイしました.本当に楽しかったです.一緒にプレイしてくれたチームメイトに感謝したいです.
Overwatchは,どこかマンネリ化していたFPSのゲーム性に一石を投じましたが,これからどのような影響を及ぼすか要注目でしょう.

最近はMirror's Edge CatalystをOriginで買いました.セールで約1500円だったのでとても安かったです.シナリオと戦闘は評価が低いようですが,逆に言えばそれ以外は素晴らしいです.既に30時間ほどプレイしましたが,シングルプレイヤーのFPSを30時間プレイするのは最初で最後かもしれません.前作が好きな方におすすめです.


今年の抱負

そろそろこのブログもまとめの時期に入る必要がありますが,現状では「俺たちの戦いはこれからだ!」的な感じなので,どうオチをつけるかまだ決まっていません.ボチボチ頑張りたいと思います.

ソースコードが欲しいなどの要望や,ゲーミングデバイスに関する疑問点などがあればAboutに書いてある連絡先に連絡お願いします.

2016/12/30

ゲーミングマウスのセンサとして電磁誘導方式を考える

光学式マウスのセンサ

光学式(LED式,レーザー式)マウスのセンサの原理を大まかに説明すると,内部のカメラで高速撮影した画像の変化を見て,センサがの移動量を相対的に推測するものです.
移動量の推定 (画像はADNS-3090のFrame Capture)
しかし,この方式の精度はセンサが取得した画像の品質に大きく依存します.そのため,平滑面などのトラッキングに向かない面で動作させた場合,精度が大きく低下しトラッキングエラーが発生します.
また,マウスが高速に動いていたり加速度の変化が伴う場合にトラッキングエラーが発生することが知られています.
Logitech G300(125Hz,750DPI)のトラッキングデータとエラー箇所
トラッキングエラーについてはrafa様の記事が非常に参考になります.
rafalog: ゲーミングマウスのトラッキング特性簡易検証 Tracking characteristic test of gaming mice

光学式センサの性能は向上していますが,上で挙げた通り理想的な精度を出すのはまだ難しいという問題点があります.


電磁誘導方式

電磁誘導方式はペンタブレットなどに採用されているもので,アンテナコイル群と座標支持器を用いて座標支持器の位置を絶対値で検出するものです.
Wacom Bamboo Pen CTL-460/K0のトラッキングデータ
移動量を絶対値から検出できるため,上図のように理想的トラッキングが行われていることが分かります.そこで,ゲーミングマウス用のセンサとして電磁誘導方式を採用した場合のメリットとデメリットを考えます.

メリット

  • 高精度

デメリット

  • トラッキング面の広さは,アンテナコイル群のサイズに依存
  • 現行機種ではリフトオフディスタンス(LoD)が大きい
  • 高価(特にトラッキング面が大きいもの)
  • ポーリングレートが低い

課題

先程挙げたデメリットは電磁誘導方式のゲーミングマウスを実現するための課題になります.
そこで,いくつかの課題について議論します.

トラッキング面の制限

トラッキング面の制限ですが,現状のゲーミングマウスの使い方においては問題になりません.光学式マウスの暗黙的なメリットとして「どこでも使用できる」という特徴がありますが,ゲーミングマウスはゲーミングマウスパッドと一緒に使用されることが多く,センサが読み取る面はマウスパッドのみにほぼ限定されています.

LoDが大きい

現行機種ではLoDが数cmあります(ペンタブレットとしてはメリットです).マウス用途として考えるのなら,測距センサなどの非接触で接地検出できるセンサを用いることで,リフトオフを検出することができます.また,マウスソールの裏に圧力センサなどを取り付けることで,のリフトオフ検出も可能だと考えられます.


まとめ

本記事では,光学式センサの問題点と,新しいゲーミングマウスのセンサとしての電磁誘導方式について考えました.

現在,WacomはKC-100などのペンタブレット上で使用可能なマウスをリリースしていますが,ゲーミングを意識した製品ではないため,実際にゲーミングマウスとして運用するのは難しいと思います.また,ポーリングレートの低さや,価格などの問題も存在しているのも事実で,製品化するには様々な課題を解決する必要があるでしょう.

しかし,電磁誘導方式の精度の高さは素晴らしく,電磁誘導方式を採用したゲーミングマウスが出ると,ゲーミングマウスもさらに面白くなるのではないでしょうか.

ゲーミングマウス向けのUSB HIDディスクリプタ

前に3ボタンマウスのデータパスを16Bit化したHIDディスクリプタを紹介しました.
この時のディスクリプタは,3ボタンでX,Y変位がそれぞれ16bitなディスクリプタですが,スクロールホイールの情報は転送できません.

本記事では,そこにスクロールホイールを加えたディスクリプタを紹介します.
USB HID Descriptor (3 button, 16bit data-path, wheel)
これによって,3ボタン(左・中・右クリック),16bitのXY変位,スクロールホイールの変位を転送できることになり,ゲーミングマウスとして最低限必要な情報を転送できます.

送られる情報は8bit×6の配列で,各バイトの情報は以下のようになります.
  • 1バイト目 : ボタンのON/OFF情報
  • 2,3バイト目 : X変位
  • 4,5バイト目 : Y変位
  • 6バイト目 : スクロールホイールの変位

実はこのディスクリプタを使ってポインティングデバイスを開発しました.

この記事もそのデバイス(と市販のキーボード)を使いながら書いています.自前でファームウェアを開発することで,機能の追加や微妙なチューニングができ,とても便利です.入力機器は様々な種類を経て拘りはじめると,「結局自分で作るしか無いじゃん」という展開になりがちですね.
この話を始めるととても長くなるので,またいずれ(書けるといいですが・・・).

2016/12/03

描画遅延とデバイスの出力周期の関係に関する一考察

はじめに

描画遅延(入力遅延とも言います)は,競技ゲームにおけるプレイヤーのパフォーマンスに大きく影響します.本記事は,ゲーミングシステムを構成するゲーミングデバイスやプログラムの出力周期に着目して,描画遅延の定式化を行い,描画遅延を減らすために要求されるシステム要件について議論します.

記事が長いので,「理屈はどうでも良い」という方は最後のまとめの項だけ参照してください.

出力周期

ゲーミングシステムは,ヒューマンインタフェースからの入力を,ゲームエンジンが受け取り,その情報に基いてディスプレイに描画します.これらのデバイスやプログラムはそれぞれ出力周期を持っています.

以下にそれぞれのデバイス,プログラムの一般的な出力周期とその名称を示します.

  • マウス,キーボード,コントローラ
    • レポートレート : 125Hz~1000Hz
  • ゲームエンジン(ゲームプログラム)
    • フレームレート : 30fps~500fps
  • ディスプレイ
    • リフレッシュレート : 60Hz~240Hz

遅延時間の見積もり

単純化した例

遅延時間も見積もるために,単純化した例で議論します.まず,マウスからの入力がリフレッシュレートが1Hzのディスプレイに出力された例を考えます.この時,入力された情報はデバイスやプログラムには即時反映されるものとします.

図1 リフレッシュレート1Hzの場合の遅延時間

図1に,リフレッシュレートが1Hzの場合の遅延時間について,最良・最悪・平均(期待値)の3パターンの入力と描画のタイミングを示します.

図1のように,入力の直後にディスプレイがリフレッシュされる場合,入力結果がディスプレイに即反映されるため,遅延時間は0sとなります.一方,リフレッシュ直後に入力がされる場合,入力結果は1s後にディスプレイに反映されるため,遅延時間は1sとなります.

プレイヤーによる入力のタイミングはランダムであるため,入力のタイミングは一様に分布することになります.したがって,遅延時間の期待値は,0s~1sの中間の0.5sとなります.

このように,遅延時間の期待値はディスプレイの出力周期に依存します.例えば,リフレッシュレートが100Hzの場合,最短の遅延時間は0sであり,最長の遅延時間は0.01sとなります.つまり,遅延時間の期待値は0s~0.01sの中間である0.005sとなります.

以上を踏まえると,1つの出力周期をもつシステムの場合,遅延時間の期待値t[s]は出力周期r[Hz]を用いて以下の式で表すことができます.
t = 1/2r


複数の出力周期が存在する場合

次に,複数のシステムが連なった時の例を考えます.レポートレートが1Hzのマウスとリフレッシュレートが1Hzのディスプレイで構成されている場合を考えます.
レポートレート1Hz,リフレッシュレート1Hzの場合の遅延時間


図2に,リフレッシュレートが1Hzのディスプレイとレポートレートが1Hzのマウスから成るシステムの場合の遅延時間について,最良・最悪の2パターンの入力と描画のタイミングを示します.
それぞれのデバイスは同期をしていないため,それぞれの出力(描画)タイミングはランダムになります.

図2のように,最良のケースでは入力の直後にマウスがレポート,その直後にディスプレイが描画することになり,遅延時間は0sとなります.一方最悪のケースでは,マウスのレポートの直後に入力が起き,1s後に入力された情報をレポートし,さらに1s後にディスプレイが描画するため,遅延時間は2sとなります.
したがって,それぞれのデバイスの同期タイミングと物理的な入力のタイミングを加味すると,遅延時間の期待値は1sとなります.

ゲームエンジンについて考えると,図2のマウスとディスプレイの間にゲームエンジンのタイミングが追加されます.この場合は,ゲームエンジンの出力周期に応じて描画遅延の期待値は増加します.つまり,ゲームエンジンの出力周期(フレームレート)を上げれば,描画遅延の期待値は減少し,フレームレートが下がれば期待値は増加することになります.

以上ように,複数のデバイス/プログラムが出力周期をもつ場合,全体の遅延時間はそれぞれのデバイス/プログラムの遅延時間の期待値の合計になります.


遅延時間の定式化

以上を踏まえると,出力周期に基づいた遅延時間の期待値は以下のように見積もることができます.全体の遅延時間をT[s]とし,それぞれの出力周期をr[Hz]とすると,Tはシステムを構成するデバイスとプログラムの遅延時間tの合計値となるため,以下のようになります.
T = Σ(1/2r)


実際のシステム構成の場合

マウスのレポートレートが1000Hz,ゲームエンジンのフレームレートが200fps,ディスプレイのリフレッシュレートが120Hzである場合は,以下のように遅延時間を見積もることができます.
T = (1/(2*1000))+(1/(2*200))+(1/(2*120)) = 0.00716[s] = 7.2[ms]


出力周期以外の遅延時間(オーバヘッド)

今までの例は,入力された情報をそれぞれのデバイス/プログラムがすぐに次のデバイス/プログラムに渡せる場合を考えてきました.しかし,実際のシステムにおいては,出力周期以外の遅延時間(本記事ではオーバヘッドと呼びます)が存在しています.
今回は以前行った測定データ(図3)から,それらのオーバヘッドを見積もることにします.

図3 ゲームタイトルごとの描画遅延
※測定方法/環境については当該記事参照

まずは,Baselineのプログラムについて考えます.このBaselineのプログラムは4300fps程度で動作します.したがって,出力周期から見積もれる遅延時間は,
T = (1/(2*1000))+(1/(2*4300))+(1/(2*120)) = 0.00478[s] = 4.8[ms]
となります.しかし,実際に測定された描画遅延の時間は8.4msです.したがって,残りの3.6msはUSBホストコントローラ,OS,OpenGLのAPI,グラフィックカード,ディスプレイなどがもつオーバヘッドであるといえます.

次に,CS:GOのSource Engine自体がもつオーバヘッドについて考えます.CS:GOのde_dust2は私の環境ではおよそ200fps程度で動作していたと思うので(うろ覚えですいません),出力周期から見積もれる遅延時間は,
T = (1/(2*1000))+(1/(2*200))+(1/(2*120)) = 0.00716[s] = 7.2[ms]
となります.ここに測定環境のオーバヘッド3.6msを足した10.8msが出力周期とシステムのオーバヘッドから予想できる描画遅延ですが,実際は15.7msとなっています.この差のゲームエンジン自体のオーバヘッドである4.9msは,OSから受け取ったマウスの変位からカメラの姿勢計算などを行い,グラフィックカードへのデータ転送,グラフィックカードが描画処理(ラスタライズ,シェーディング,ポストプロセスなど)を行うための時間だと考えられます.

CS1.6はフレームレートの制限があり,全体の描画遅延はCS:GOと大きく変わりませんが,フレームレート制限の分を加味すると,ゲームエンジン自体のオーバヘッドはCS:GOと比較して小さいと言えます.この差は,CS1.6からCS:GOでグラフィックがリッチになった影響で,グラフィックパイプラインがより深くなり,ゲーム内の内部処理もより複雑になったためだと考えられます.

ゲームエンジンの高度化,グラフィックのリッチ化は多くの一般的なプレイヤーにとって利益になります.しかし,コンペティティブなタイトルでは描画遅延の増加というトレードオフも存在しており,競技性を意識したタイトルでは慎重に調整するべきだと思います.


遅延を減らすためにプレイヤーができること

遅延時間を少なくするためには,それぞれの出力周期を上げる必要があります.
つまり,マウスに関して言えば,レポートレートをできるだけ高くすることです.デバイスの設定によって1000Hzや,設定できるのならそれ以上の値に設定します.
また,プロセッサとメモリを高速なものに移行することと,ゲーム内設定をできるだけ低負荷なものにすることでフレームレートを上げるのも有効です.
そして,リフレッシュレートの高いディスプレイに置き換えることも有効でしょう.
デバイスやディスプレイを買い換える場合は,余計な遅延が発生するようなものは避けることが必要です.

特に,フレームレートはゲームの設定を調整するだけで容易に改善できます.フレームレートを上げるには,レンダリング解像度やテクスチャ解像度,シェーディングなどの設定を下げるとよいでしょう.グラフィック設定は基本全部低設定にして,視認性に影響を与えない範囲でレンダリング解像度を下げるというのがよいでしょう.


まとめ

まとめます.

  • 出力周期に基づく描画遅延時間の期待値はΣ(1/2*出力周期)で表すことができる
    • 遅延時間はそれに加えて,プログラムの計算時間やデータ転送時間などの要素で増加する
  • 出力周期を小さくすることで描画遅延時間を小さくできる
    • デバイス
      • デバイスのレポートレートを上げる
      • レポートレートの高いデバイスを買う
    • ゲーム(エンジン)のフレームレートを上げる
      • CPU・メモリ・GPUを高速なものに買い換える
      • グラフィックの設定(解像度,その他)をできる限り下げる
    • ディスプレイのリフレッシュレートを上げる
    • リフレッシュレートの高いディスプレイに買い換える
  • 描画遅延の中でオーバヘッドが占める割合は大きく,プレイヤーが出力周期を上げることで対応できる範囲は小さい
    • 描画遅延を極限まで小さくするには,より小さいオーバヘッドのシステムを考える必要がある
      • 今までのソフトウェア資産を失うことになるため,システムのアーキテクチャ自体を大きく変える事はとても難しい
      • オーバヘッドの小さいゲームエンジンを高く評価するような雰囲気づくりが必要

2016/08/23

Overwatchのウィンドウモードごとの遅延


先日Twitterに書きましたが,Overwatchの描画遅延を測定しました.この検証により,どのウィンドウモードでプレイするのが「最も強いのか」ということを解き明かしました.
また,Windows10にアップデートしたので,ゲーマーにおけるWindows 10の最大のテーマ「Aero 3フレーム遅延説」についても簡単に議論します.


測定方法

測定方法は今までの記事と同様で,視点を左右に動かすようなデータをHID Device経由で送信すると同時に,LEDを点灯させます.ここで,LEDの点灯(HID Deviceのモーション送信)からディスプレイの映像が実際に動き始める時間を描画遅延とします.LED点灯からディスプレイの映像が動き始めるまでは数十msしかないので,Nikon1 V1のスローモーション撮影機能を用いて1200fpsで撮影しておきます.撮影されたスローモーション映像をPCでコマ送りで確認することで,描画遅延の時間を測定します.

この手順で,フルスクリーン・枠なしウィンドウ(フルスクリーンウィンドウ)・ウィンドウの3種のウィンドウモードの描画遅延を測定します.


評価環境 Experimental Setup

評価環境の概要は以下のようになります.OSとHID Deviceが変更になりました.
  • PC
    • OS : Microsoft Windows 10 Home
    • CPU : Intel Core i7 2600 (HT Enable)
    • GPU : NVIDIA GeForce GTX670
    • Display : BenQ XL2410T (120Hz)
  • Camera : Nikon1 V1 with 1 NIKKOR 10mm F2.8
    • F : 2.8,SS : 1/1250s
  • HID Device : CY8CKIT-059 PSoC 5LP Prototyping Kit (CY8C5888LTI-LP097)
  • Overwatch Settings
    • Resolution : 1920x1080 120Hz
    • Render Scale : 50%
    • Graphic Settings : Low or OFF
    • V-Sync : OFF


評価結果 Experimental Results

まず,測定したデータを時系列にまとめたものを図1に示します.
図1 時系列の遅延データ

図1のように,ディスプレイのリフレッシュレートが低いため描画遅延のフレーム数がバラけています.
また,Fullscreen(青線)では測定回が奇数の場合と偶数の場合で1フレームほど数値が異なります.
(※なぜこういう傾向になったのかは不明です.データは一発取りなのでもう少し詳しく測定する必要がありそうです.)

図1は描画遅延のフレーム数なので,わかりやすいようにミリ秒に換算し,平均値を出します.
Nikon1 V1のスローモーション撮影は1200fpsなので描画遅延の時間は,
描画遅延時間[ms] = 描画遅延のフレーム数×(1/1200)×1000
となります.この描画遅延時間から平均値を出したものが図2になります.

図2 描画遅延の平均時間

また,奇数/偶数を考慮した場合の平均値は図3のようになります.

図3 奇数/偶数を考慮した描画遅延の平均時間
図2,3のように,フルスクリーンの時が最も描画遅延が少ないです.要するに,フルスクリーンのほうが敵が早く見える上に,マウスの動きと画面の動きのラグが少なくなるのでAimもしやすいということになります.


Aero 3フレーム遅延説@Windows10

いわゆるAeroが有効だと,この環境では2フレームの遅延の差があると言えます.
(奇数偶数を考慮しない場合は1フレームですが,おそらく考慮した方が正しいデータであると考えています.)
Windows 10はWindows 7のようにAeroを明示的に切ることができないので,コンペティティブなタイトルは基本的にフルスクリーンに設定するのが無難だと言えるでしょう.
Windows 7のようにAeroを切れるOSであれば,そこまで大きな遅延は発生しないのですが・・・(それでもフルスクリーンが最速です)

参考 : Win8.1で測定されたデータ http://www58.atwiki.jp/grassan/pages/17.html


Overwatchのゲームエンジンは低遅延なのか?

今回の測定にあたり,OSをWindows7 → Windows10へと変更したため,他のゲームエンジンとの描画遅延の優劣は比較できないと考えています.

ただ,Windows7の時のデータを参考に考えるとOverwatchのエンジンはSource Engineと比較して大きな差はなく,結構リッチなグラフィックである割に低遅延なエンジンであると言えます.


まとめ

まとめます.
  • この環境では,フルスクリーンが最良
  • Windows 10ではウィンドウモードでは2(?)フレーム遅延する
    • 他のタイトルでも調べる必要がある
  • Overwatchのゲームエンジンは低遅延な部類だと思われる
  • (コマ送りで動画を再生して確認するので,とてもめんどくさい)


Appendix

撮影した動画を掲載します.







2016/08/06

USB HIDマウスのデータパスの16bit化

前からPSoC Creatorの3-button Mouseのサンプルのソースコードを弄って色々(これとかこれ)やってましたが,このサンプルはデータパスが8bitなので1回のポーリングで-127~127の範囲の値しか送れませんでした.そこで,データパスを16bit化することにしました.
16bit化することにより,最近のゲーミングマウスと同レベルの値の範囲を使用することができるようになるので,色々と調査が捗るはずです.

しかし,USB HID Noobな私にとっては「どこを弄ればよいのかさっぱり・・・」という感じでネットの海を彷徨うこと数時間・・・
Zowie EC2 EVOのディスクリプタを参考にすることでなんとか解決しました.
参考 : Zowie mouse wheel scroll up/down not working
(このログを出したアナライザー欲しいんですけど1ライセンス$200なんですよね・・・とりあえずはUSBViewとMicrosoft Message Analyzerで誤魔化しています)

デバイスが応答しなくなる問題の対策

ディスクリプタを弄りながらデバイスを何度も接続していると,デバイスの反応がなくなることがありますが再起動すると治るようです.

HID ディスクリプタの設定

最終的なHID Descriptorの設定は以下のようになりました.
(PSoC Creatorの3-button Mouseのサンプルから変更した部分は青線で囲んだ部分だけです.)


ディスクリプタの簡単な解説

前半がボタン関係です.3-button Mouseなので,ボタンのUSAGE_PAGEが3つあり,USAGE_MINIMUMが1でUSAGE_MAXIMUMが3,REPORT_COUNTが1になります.
ボタンは0/1しか表現できないのでLOGICAL_MINIMUMが0,LOGICAL_MAXIMUMが1となり,REPORT_SIZEが1になります.
3ボタンマウスだと,ボタンの状態表現に3bitしか必要ないため,余った5bitをパディングします(中段).

後半がカーソル関係のディスクリプタで,USAGE_PAGEはGeneric Desktop Controls(0x01)になります.USAGEは0x20がX軸で0x21がY軸です.
データパスを16bit化するので,LOGICAL_MINIMUMを-(2^15-1) = -32767 (0x8001)にして,LOGICAL_MAXIMAMは2^15-1=32767(0x7FFF)になります.また,REPORT_SIZEを16にします.
ここで,REPORT_COUNTは変更の必要はなく,XとYの2軸なので2になります.
(ちなみに,データパスが8bitの場合はLOGICAL_MINIMUMが-127,LOGICAL_MAXIMUMが127,REPORT_SIZEが8になります.)

コード

ボタンの状態を1byte(3bit+5bitパディング),X軸で2byte,Y軸で2byteになるので,USBFS_LoadInEP()に渡す配列は5byteになります.
例 : uint8 mouseData[MOUSE_DATA_LEN] = {0u, 0u, 0u, 0u, 0u}
この場合だと,{ボタン,X軸下位8bit,X軸上位8bit,Y軸下位8bit,Y軸上位8bit}という風になります.

X軸の変位をdxとして場合はこんな感じで代入すれば良いと思います.(あまりオーバーフローとか考慮してないですが・・・)
mouseData[1] = (uint8)dx;
mouseData[2] = dx >> 8;


ポーリングごとにdxを1ずつ増やしたり減らしたりするようなコードを書くと,こんな感じの応答になりました.
図のように,8bitデータパスの限界値である±127を超えてデータを送ることができています.

※超絶初心者なので,この記事の記述は間違っている可能性があります.

2016/05/14

DPIと振り向きとセンシティビティ

DPI × sensitivity ∝ 振り向き
という関係は一般的に知られています.例えば,400 DPIのsensitivity 2と800 DPIのsensitivity 1は振り向きが等しいということになります.概ねこれは正しいのですが,一点だけ注意点があります.
それは,DPIを下げれば下げるほど,視点の回転が荒くなるという点です.

簡単な例を動画にしてみました.
まずは比較的一般的な1000 DPI,sensitivity1という設定です.

絶望的なまでのAimの悪さを除けばごくごく普通の視点操作ですね.

次に10 DPI,sensitivity 100という設定です.

非常にガクガクとした視点の移動ですね.特に動画の後半では,Aim出来る位置に頭がないので,Aimを合わせることができていません.


2つの動画は「ほぼ」振り向きの距離は同じですが,視点移動の粗さが大きく違うことが分かります.

これは非常に極端な例ですが,実際のもサブピクセル単位ではこれと同じ現象が起きています.つまり,ごくごく微小な範囲では,例と同様に低DPIだと欲しい角度に向くことが出来ていない可能性があるのです.
これが私がプロプレイヤーの中で一般的な400DPIという設定を倣わずに,750DPIや1000DPIに設定している理由です.

特にハイセンシなプレイヤの場合,400 DPIなどの低DPIにしてインゲームのsensitivityを上げるような設定は極力避けたほうが良いでしょう.

CS:GOの視点回転処理

CS:GO互換な視点回転をするアプリを書く時に考える必要があるのが「マウスからの変位1 countに対して,どれだけ視点が回転されるか?」というパラメタです.このパラメタが分かればCS:GOのsensitivityの設定と互換アプリのsensitivityの設定を合致させる事ができます.

というわけで実験してみましょう.
CS:GOでは,コンソールからcl_showposを1とすることで,自分の視点の角度を見ることが出来ます.
左上に位置情報と視点の回転角,速度が表示されています
小数点第2位まで表示されているので,有効数字4桁まで取れそうですね.
ちなみに-180~180までの値を取っているので単位はdegreeだということが分かりました.3D系のAPIって大体はradianだと思うのですが・・・ちょっと意外です.

sensitivityが1~10程度の低い値だと,1 countあたりの回転角が非常に小さいので有効数字を使い切るような計測ができません(本当はUSB HIDを作って1000countとか転送すれば良いんですけどね).
そこで,sensitivityを1000として設定して1 countだけ視点を動かします.

スタート地点
1countだけ水平方向に回転
7.44から27.44になりました.つまり,sensitivity 1000の状態では,1 countで20.00度回転することになります.また,sensitivity 1の場合では1countで0.02度回転します.
ちなみに垂直方向も同様の回転量でした.

以上より,大抵の3D APIはradianを使うことになるので,フレームあたりの回転量は,
フレームあたりの回転量 = sensitivity * 0.0003491 * フレームあたりのcount数
と求めることができますね.垂直方向に関しても同様の式で回転量を求める事ができます.

2016/04/22

マウスパッド表面評価のためのセンサー可視化デバイス

はじめに

ADNS-3090とADNS-9800というゲーミングマウスのセンサが、マウスパッドをどのように「見て」いるのか、というセンサの視界を人にも見える化するシステムを作りました。こういったシステムがあると、ソール厚に関する知識を深めたり特定のマウスパッドへの相性問題を解決したりモヤモヤした画像を見て悦に入ったりと色々なことが出来ます。
要するに、マウスとマウスパッドの間に問題が起きた時にデバッグしたり、更にマウスの性能を引き出したりする時に手助けとなる道具です。ただ闇雲にデバイスを買って試すのではなく、色々な道具を作って科学的/工学的な観点でデバイスを評価するのも私は良いと思うのです。

前の記事との差分としては、現役で活躍しているゲーミンググレードのレーザーセンサとLEDセンサの双方で「見る」ことが出来るようになったのは意義があるでしょう。記事のような色々なマウスパッドの表面画像についてはそのうちまとめます。

ハードウェア

まずはセンサとMCUについてハードウェアの面で説明します。

ADNS-9800

ADNS-9800は色々と訳あってセンサモジュールを購入しました。
ADNS-9800のセンサモジュール with ジャンパワイヤ
代理店を介さずにゲーミンググレードのセンサを購入できる場所は少ないです。結構探したのですがこのサイトしかありませんでした。送料が$60という恐ろしい数字だったので非常に痛い出費ですが、個人に売ってくれるだけありがたいです。
送料分を取り返すためにモジュールに加えてバニラなセンサとレンズのセットを数組購入しましたが、使用予定は・・・In progressということで。

センサモジュールはピンアサインがはっきりしているので説明通りに繋ぐだけで大丈夫です。
このモジュールは探せばArduinoのサンプルもあるので、Arduino持っていれば誰でも動かせると思います。

ADNS-3090

ADNS-3090はELECOM M-XG3Gのセンサを使用しました。
3000円程度で完動するセンサモジュールが手に入るのは素晴らしい・・・(とか考えてるのは日本で私くらいしか居ないのかもしれません。)

購入した時はマウス自体のMCUがセンサのマスタになっているので、データパスを切る必要があります。
ADNS-3090のSROMがなかなか見つからないのでデータパスを切る前にSROMを事前に吸い出す予定でしたが、「ADNS-3090は部品としては手に入らないセンサなのでSROMを持っておく必要もないのかな」と考えてデータパスをぶった斬りました。RIP。
データパス切断の図。中央の傷の部分でレジストごと配線を切っています。
切る必要があるのは、NCS、MISO、SCLK、MOSI、RESET、NPDです。
最近のマウスはほとんどが両面基板なのでビアを追うのが面倒ですが、センサ付近から追っていって切りやすい部分で切ればいいと思います。

外観はゴミを寄せ集めたみたいな手作り感溢れるアットホームな感じです。自分のMCUからの配線はセンサの足に直付けしています。こうすると基板の上側から配線を引き出せるので非常に便利です。
システム外観。

MCU

センサを制御してもらうMCUはいつものCY8CKIT-042 PSoC 4 Pioneer Kitです(上写真右の赤いボード)。
プログラマ不要の開発ボードで、秋月で税込み3000円で買えます。Arduinoみたいなピンアサインで、しかもリセットしてもCOMポートの接続が切れないのでとても便利です。
センサから生やしたジャンパワイヤをしかるべき所に繋ぐだけで準備完了。


ソフトウェアの実装

あんまり面白いことはしていないのですが、概要は下のようになります。
  1. MCUがセンサにFrameCaptureをリクエスト
  2. センサが画素データを返す
  3. MCUが画素データのバイナリをUART→USB経由でPCに転送
  4. ホストのアプリがバイナリを受け取り、グラフとして描画
  5. 1~4を繰り返す

ホスト(PC)のプログラム

ホスト側はネイティブアプリを書くのも面倒なのでPythonのserialモジュールと、matplotlibモジュールでお茶を濁していくスタイル。matplotlibは動画も撮れたり、画像の補完方法も豊富なので結構便利ですね。

MCUのファームウェア

MCU側はフンハフンハ言いながら実装するとできます。いくつかセンサを触った経験から言うと、とりあえずProductIDを取得出来るようにする→大体の事は出来るようになる。という感じなのでデータシートをよく読みながら実装すればよいでしょう。

注意する点としては、ADNS系のセンサはNCSの扱いが特殊なので、そこに工夫が居る点です。
MCUからのレジスタアドレスとして1バイトの送信が終わってNCSをHIGHにしていまうと、うまく動きません。なので、NCUはMCUのSPIの処理とは別に制御する必要があります。
PSoCの場合は、SPIのNCS(SS)はSPIコンポーネントには接続せず、別にDigital Output Pinを用意すれば良いです。
基本となるRead/Write Operationsコードはこんな感じになります。ここでは、NCSとしてSSというピンを用意して、適宜HIGHにしたりLOWにしたりしています。
--------
void Write_Operation(uint8 address , uint8 value )
{
    address = address | 0b10000000; //MSBを1にしてWriteだと伝える
    SPIM_ClearRxBuffer(); //バッファクリア
    SPIM_ClearTxBuffer();
    SPIM_ClearFIFO();
    
    SS_Write(0); //NCSをLOWに。送信開始
    CyDelayUs(1); //ディレイが必要。時間はセンサによる。
    
    SPIM_WriteTxData(address); //書き込み先のレジスタアドレス送信
    
    SPIM_WriteTxData(value); //書き込み先のレジスタに書き込む値を送信
    while(!(SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE)){}; //終わるまで待つ
    CyDelayUs(1);
    SS_Write(1); //NCSをHIGHに。送信終了
    SPIM_ReadRxData(); //SPIのRxに入ったゴミデータを捨てる
    SPIM_ReadRxData(); //SPIのRxに入ったゴミデータを捨てる
    CyDelayUs(120u); //ディレイが必要。時間はセンサによる
}

uint8 Read_Operation(uint8 address)
{
    address = address | 0b00000000; //MSBを0にしてReadだと伝える
    SPIM_ClearRxBuffer(); //バッファクリア
    SPIM_ClearTxBuffer();
    SPIM_ClearFIFO();

    SS_Write(0); //NCSをLOWに。送信開始
    CyDelayUs(1); //ディレイが必要。時間はセンサによる

    SPIM_WriteTxData(address); //取得先のレジスタアドレス送信
    while(!(SPIM_ReadTxStatus() & SPIM_STS_TX_FIFO_EMPTY)){}; //送信が終わるまで待つ
    CyDelayUs(100); //ディレイが必要。時間はセンサによる

    SPIM_WriteTxData(0x00); //0x00を送る間にデータが帰ってくる
    while(!(SPIM_ReadTxStatus() & SPIM_STS_TX_FIFO_EMPTY)){}; //送信が終わるまで待つ
    while(!(SPIM_ReadRxStatus() & SPIM_STS_RX_FIFO_NOT_EMPTY )){}; //RxFIFOに1個目のデータが来るまで待つ
    SPIM_ReadRxData(); //一個目はゴミなので捨てる
    while(!(SPIM_ReadRxStatus() & SPIM_STS_RX_FIFO_NOT_EMPTY )){}; //RxFIFOに2個目のデータが来るまで待つ
    SS_Write(1); //NCSをHIGHに。送信終了
    CyDelayUs(120u); //ディレイが必要。時間はセンサによる
    return  SPIM_ReadRxData(); //レジスタから取得したデータを呼び出し元に返す
}
--------
弱いコードですが大目に見て下さい。
ちなみにFrameCaptureを動かすだけならSROMは必要ないので色々なセンサで試すことが出来るでしょう。


動かしてみた

画像や動画はCOUGAR Control Mouse Padの滑走面を撮影したものです。

ADNS-3090の画像

ADNS-3090は画素が0~63の値をとるようなので、ADNS-9800(0~127)の値から2倍になるようにしています。
ADNS-3090
ADNS-5090(下図)を高解像度化したような印象です。センサ素子がADNS-5090は19x19ですが、ADNS-3090は30x30になったためですね。視野の範囲などの考察はまたいずれ。
ADNS-5090


ADNS-3090の動画

動画にするとこんな感じです。適当に動かしています。後半でマウス全体を一度持ち上げていますが、3090ではシャッター値がMAXになると白飛びに近い状態になるようです。



ADNS-9800の画像

ADNS-9800はこんな感じに映ります。
ADNS-9800
見た印象だと全然同じマウスパッドに見えません。これはLED式センサと比較すると、見えている範囲がものすごく小さいためです。LED式センサでは「山」が2個くらい画面内に映るのですが、「山」ひとつでフレームアウトするような感じです。詳細な比較はまたいずれ。

また、ADNS-5090やADNS-3090のようなLEDセンサと比較すると、「のっぺり」とした印象になります。これは、レーザの射角が滑走面に対して深いためです。LED式センサではほぼ真横にLEDが付いていて、それをレンズで屈折させて滑走面を照射しており射角が浅いのですが、レーザ式の場合はセンサダイの真横にレーザ素子があり、そこから下図のようにレンズで屈折させて射角が深くなっています。射角が深いため、「影」となる部分が少なく、LED式と比較してコントラスト比が小さくなると考えれます。
Pixart ADNS-6190-002 データシートより
他にも「レーザースペックルがどうのだからDPIが・・・」みたいな考察もあるので、もう少し裏を取ってから別記事で上げたいと思います。