Surface Vision 2.0

某イベント会場にて Surface Pro3 を48台使った展示をしました。横12列・縦4列に並べたSurfaceが同期して1つのスクリーンになる仕組みです。


原理

一昨年にも某ショールームで似たような展示をしており、そのときは横4列・縦8列計32台のSurfaceで、『Surface Vision』と名付けられました。
開発中、誰もいないオフィスで勝手に横一列32台並べ、グラ○ィウスもどきのバカ長いレーザーを表示して遊んだりしてましたが、安定したネットワークが使えない現場の制約から、時計合わせで同期(?)するという安直な荒技に及んでおり、案の定ちょくちょく表示がズレていたものです。

laser

“Surface32台でレーザー射ってみた”。アップしたムービーがちょっとバズってクライアントにバレた。当時は定期的な音や光で同期しようとも考えたが物理的に適わず

今回はすべての端末を有線LAN接続してマルチキャストで同期しており、ズレの心配はありません。プロトコルはOSC。
プログラムはいつものようにUnityで開発。同期された共有仮想空間を端末ごとに異なるビューで表示するという、原理的にはネットゲームのような作りです。

演出

展示の内容は、48台の端末それぞれに異なるコンテンツが表示されており、ある端末のコンテンツをタッチすると、その詳細が表示されると同時に、それに関連するコンテンツが隣り合う端末にも表示されるというものです。
ただし、その関連コンテンツの表示のされ方は、ただパッと切り替わるのではなく、もともとそのコンテンツがどこか離れた端末に表示されていたとして、そこから一旦バラバラの破片になって飛んでくる、というやや込み入ったもの。

しかし共有仮想空間の仕組みにおいては、破片が地点AからBへ飛ぶ、という情報を同期するだけで簡単に実現できます。全端末で同じ破片を生成し移動させ、各々のビューでレンダリングすれば必然的に、破片が端末のあいだを横切っていく様子となって見えるわけです。ランダムな挙動も、全端末で乱数シードを合わせればちゃんと一致します。

fig2

仮想空間内にはこのように実際のSurface配置同様に表示コンテンツが並んでおり、その状態は破片含め全端末で同期されている。各端末はこのうちひとつのコンテンツ枠を正面から画面一杯に表示するようビュー(カメラ)を設定する

GPU並列処理

さて、同時にあちこちタッチされる可能性を考えると、破片も相当数が同時に表示されると考えねばなりません。一枚の破片は単純な三角形としても、地点AからBへある程度バラついた軌道でイージングする計算を行い、それぞれを個別にレンダリングするとなると、けっこうな負荷がかかります。

そこで、コンピュートシェーダとジオメトリシェーダを使うことにしました。コンピュートシェーダで破片の動きを、ジオメトリシェーダで動きに応じた破片の変化を、GPUに一括して処理させます。
GPUで処理するのとそうでないのとでは、まったく比較にならないくらいの差が出ました。CPUでは破片を粗めに設定しても表示数が少々増えるだけでアップアップしてたのが、GPUだと粉々の破片が余裕でヌルヌル飛び回る。実際の演出ではそこまでしませんが、なにしろ余裕があり安心です。

fig3

やや粉々にしてみた例

Surface最適化

いざ Surface Pro3 実機でプログラムを動かしてみると、始めこそ快調に動いているものの、必ず数分のうちに、60fpsから45, 30, 20fps前後にまで段階的にフレームレートが落ちていく現象が発生。

端末を触ってみると、熱い。どうやらオーバーヒート防止のためのクロック低下機能、いわゆるサーマルスロットリングが働いているようです。あわてて調べてみると、Surface Pro3 は冷却が弱いため敏感にサーマルスロットリングが働き、i7機においてはなんとi5機に劣るまで性能が落ちてしまうベンチマーク結果もあるとのこと。意味ないじゃん…。

仕方ないのであまり負荷をかけないよう演出やコード、レンダリング解像度など見直しつつ、並行してSurfaceの設定をいろいろ変えて実験してみた結果、「画面のリフレッシュレート」を48Hzにするとそこそこのパフォーマンスを保ちつつフレームレートを維持できる(48fpsですが)ことがわかりました。プログラム側でフレームレートを低く設定するより安定するようです。

fig4

展示の裏側には空気循環用に数台のファンを備えた

ちなみにこのシステムの端末はiPadでも良さそう、というかもともとクライアントにはそれを希望されたのですが、iPadでは有線イーサネット接続が裏ワザ的にしかできず、それも不安定だったり給電と両立できなかったりで結局Surfaceを採用、という経緯があります。Wi-Fiはただでさえやや不安定で同期には不向きなうえ、大勢のお客さんのいる現場ではつながらなくなる恐れすらあるため使えないのです。
しかしSurfaceはSurfaceで上記の問題のあったことに加え、画面端スワイプでやたら余計なものが出てくるWindows8の仕様にも参りました…。

Kinect

この展示にはもうひとつ、鑑賞者が端末に近づくにつれ画面の様子が変化するというギミックがあります。
天井から吊るしたKinect v2(Unity用プラグインが公式提供されており便利)による俯瞰の深度情報から鑑賞者のシルエットを検出し、端末位置から飛ばした仮想のレイと何本どれだけの距離で干渉したかを判定することにしました。
この方法はシンプルで速度効率が良く、設置するSurfaceの位置や向きも自在です(今回設置する壁は湾曲している)。

fig1

壁の端末配列から飛ばしたレイ(赤線)を人体が遮る。レーザーセンサみたいで見ているとおもしろい。ちなみにこの可視化、テクスチャへの描画ではなく、瞬間的に消えるパーティクルを毎フレーム生成して描いている

完成

冒頭の映像はいわばテストモードで、単色の破片がただ画面外へ飛び去るだけのものです。実際のコンテンツの様子は大人の事情でアップ・掲載できず。

タッチ音のピッチはランダムで、当初無段階に変化させていたのですが、「なんか落ち込む」との苦情を受け、とりあえず白鍵の周波数に限定しました。ランダムではなく端末毎に固定すれば楽器みたいで楽しいかも。

今回は同じSurfaceを平面に均等に整列させただけなので、よくあるマルチスクリーンとあまり変わり映えがしませんが、原理上個々の画面サイズや配置は自由です。位置さえ把握できれば端末は動いていても構わないし、もちろんインタラクティブ。立体的・動的な展示にしたらもっと面白いでしょう。
クラタスのときも原理は同様で、あれは仮想空間上のクラタスモデル/エフェクトを取り巻くようにビューが設定されており、それを実物に投影することで3Dプロジェクションマッピングを実現していました。

 
じつはしばらく充電期間をもらっていたため、このブログも間が空いていました。が、復帰早々当案件の突貫地獄、おかげさまでさっそく書くネタができました、ありがとうございます…。