読者です 読者をやめる 読者になる 読者になる

凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

Maker Faire Tokyo 2015 にレゴ x ハードウェア x プロジェクションなシューティングゲーム LITTAI を出展してきた

Unity OpenCV Qt AR LITTAI C++
f:id:hecomi:20150805233244j:plain

はじめに

前回の記事で書いたように 8/1、8/2 に東京ビッグサイトにて開催された MFT 2015 へ友達と趣味で制作していた LITTAI というゲームを出展してきました。お越しくださった皆様、ありがとうございました!

LITTAI は Lit Table Interface の略の造語で、以下の様なコンセプトを掲げるゲームです。

  • テーブル上で実際にものを操作しながら遊ぶゲーム
  • 操作するものはリアルタイムにカスタマイズ可能
  • ハードウェアとゲームの世界が連動

基本的なコンセプトは以前出展した Mont Blanc Pj. とほぼ同じで、こういった技術を使いつつ遊び手に技術を意識されないようなゲームの新しい遊び方を模索するのが目的です。

製作期間はネタ出しで 1 ヶ月、実験・制作が 2 ヶ月半くらいです。私は認識部とゲーム部のソフトウェア全般を担当しました。ハードウェア全般は前作同様 id:jonki、展示用のランキング制作を id:AMANE にやってもらいまいした。そちらの詳細は彼らに任せることとして、本エントリでは LITTAI の全体の概要紹介と、私の担当部の認識・ゲーム部分の詳細について紹介したいと思います。

LITTAI とは

MFT 2015 でデモした内容は以下になります。

デモの流れとしては、最初はフリーモードで説明を行い、スコアの表示された丸い石を長押しするとゲームを開始します。ゲーム中は適宜ブロックをつけたり外したりしながら敵と戦う形となり、ハードウェアのボタンを押すと弾が発射され、発射される弾はブロックの付け方で変化してレーザになったりシールドになったりします。弾を打つのにエネルギーを消費するので、砲台をつけすぎるとすぐ弾切れになってしまったり、機体を大きくし過ぎると敵の攻撃を喰らい易くなるので適度にするのがコツです。

敵を倒したり弾を相殺したりアイテムを取ったりするとスコアが増え、逆に死んだり長押しをしてボムを打つとスコアを消費する感じです。スコアの表示された丸い石を打つとスコアが増えるので、適当な場所においてこいつを撃ちながら敵も倒していく、というのがハイスコアのコツで、何人かのお子さんは何回か遊びに来てハイスコアアタックしてくれました。

最後の獲得スコアが表示されて、ランキング表示用のパソコンにキャプチャした機体と一緒にスコアが表示され、はじめに戻る、という流れです。

筐体・機材

全体図はこんな感じです。

f:id:hecomi:20150805190514p:plain

f:id:hecomi:20150805173114j:plain

島忠や Amazon で仕入れた部材で組み立てました。プロジェクタは小型で持ち運びしやすく 500 lm な QUMI Q5 を利用しています。QUMI Q5 は上下 44 度、左右 36 度の画角のため、広い面積をカバーできるよう光路を稼ぐために、一度地面に設置したミラーで反射させてから上に映しています。スクリーンはアクリル板に 40 g の大型トレーシングペーパを貼ったものになっていて、比較的明るい場所でもリアプロジェクションされた光を綺麗に映してくれます。

f:id:hecomi:20150805171335j:plain

そしてこのスクリーン上に置かれた物体を下部から赤外線投光機で照らして赤外線カメラで観測します。これによりプロジェクタで投影された画を無視して純粋にスクリーン上の物体だけ見ることが出来ます。詳しくは後述しますが認識に利用している赤外線投光機・赤外線カメラはいろいろ試した結果、今回は Kinect v2 を利用しています。

ブロック

追記(2015/08/07)ハードウェア側のエントリも投稿されました:

www.jonki.net

ブロックは id:jonki が作ってくれていて、ハードウェアボタンを冠した 6x6 ポチの 3D プリントしたレゴの土台の中に TOCOS の TWE-Lite が入っていて、PC 側に取り付けられた親機(トコスティック)と無線で通信しています。

f:id:hecomi:20150727003743j:plain

TWE-Lite は私も部屋の状態を取得するセンサとして使用していて、大変安価で使いやすくてとても便利です。詳細はミクミンP の記事がとても分かりやすいです。

ブロックの底部は真っ黒なのですが、実はここには可視光カットフィルムを貼っていてその内側に AR マーカが仕込んであります。この AR マーカから機体の位置・角度を取得するとともに AR マーカの ID と TWE-Lite の ID を紐付けして、どのハードウェアボタンが押されたらどの機体から弾を発射するか、というのを判断しています。

テレビ石

テレビ石はとても不思議な石で、絵の上に乗せると下の絵が石の表面に見えるというものです。これは結晶構造が平行で綺麗に並んでいて光が細い単位で全反射して上に伝わることによる効果です。

f:id:hecomi:20150805173530j:plain

また、逆に言えばテレビ石上面のタッチは下面にそのまま伝わることになり、テレビ石上面のタッチが下部のカメラから見ると(少し減衰しますが)スクリーン表面のタッチと同様に見えます。

f:id:hecomi:20150805174916j:plain

またリアプロとテレビ石の組み合わせは相性が良くて、以下の様な構造にすることにより斜めから見てもボケないはっきりとした映像を上面に投影することが可能です(写真左が上部に拡散シートあり、右がなし)。

f:id:hecomi:20150805183959p:plain

f:id:hecomi:20150805174136j:plain f:id:hecomi:20150805174140j:plain

昔に奇石博物館に行って買ってもらって遊んだのを思い出して試してみたら面白かったので採用しました。今回は東急ハンズで購入した人口テレビ石を利用しましたが、光ファイバを充填しても作成することが出来ます。

が、新規性は無くて後述しますがより進んだ先行研究が有ります(応募した後に気づいた)。。

ソフトウェア全体構成

ここからソフトウェアの方の解説に移ります。

簡略化した全体像は以下になります。

f:id:hecomi:20150804200257p:plain

認識部は主に OpenCV で処理を行い、マーカ認識は ArUco を利用しています。流れとしては、Kinect v2 から取得した赤外線ストリームをホモグラフィ変換して下処理した後、テレビ石の認識(ランドルト環認識)とマーカ認識を行い、マーカ認識では隣接するブロックの検出、ポリゴン化、三角ポリゴン化を行います。認識した結果は JSON にして OSC で送ります。

ゲーム部は Unity で作成していて、その OSC メッセージを受け取り、認識した物体をゲーム中にマージします。三角ポリゴン化された情報を使ってメッシュやコライダを作成したり、位置や回転の補間(30 fps -> 60 fps)を行ったりしつつ、ハードウェアから送られてきたシリアル信号とマージしながらゲームを動かします。

Unity で描画した画は SyphonMad Mapper に送り、画面に認識した位置とぴったり合うように幾何変換してプロジェクタから出力します。

デモを円滑に行うため、多くのパラメタは GUI を作成して環境に合わせてリアルタイムに変更・保存・復元できるようにしてます。今回、Mad Mapper 経由で出力することにしたので、Unity の Editor がそのまま表示できる都合で、認識側だけでなく Unity 側の多くのパラメタも Editor からリアルタイムに変更できるようになったのはかなり便利でした。Mad Mapper 高かった & 単一の矩形の変換しか使ってないですが...

何も整理してない & 直前でバタバタしたコードが混ざってますがコードは以下に公開しています。Mac / Win どちらでも作業できるようにする意味とモジュール化が楽なので UI は Qtで作成しています。

認識概要

デモ

冒頭の動画と同時に撮影した認識時の動画です。

ホモグラフィ変換

なるべく Kinect の画が大きくなるように調整します。

f:id:hecomi:20150805165714p:plain

前処理

基本的にはアンシャープマスクをかけてキャリブ画像との差分を取って輝度をならすためのグラデーションをかけているだけです。

f:id:hecomi:20150805165733p:plain

テレビ石認識

テレビ石はカバーに一部黒い帯をつけてランドルト環(視力検査の形、OpenCV のロゴの形、C)にして、これをまずテンプレートマッチングして検出します。テンプレートマッチングでは傾きは得られないので、得られた ROI に対して中心部から外へ向けて 360 度レイを打って、端まで到達したレイの平均角度をこのテレビ石の角度として採用しています。

f:id:hecomi:20150805165756p:plain

今回はやりませんでしたが、黒い帯を複数つけてパターン化すれば ID も付与できると思います。

そして丸の内側の領域に対してテンプレートマッチングとはやや低めのスレッショルドを与えてタッチ認識を行います。

マーカ認識

マーカ認識には ArUco を使用しています。

ArUco はデフォルトでは cv::adaptiveThreshold を利用する設定になっている(ここ)ので元画像を食わせても認識精度が良くなく、動かしたりするとトラッキングが外れたり場所によって認識が弱かったりして困っていました。そこで cv::threshold を利用する形にして自前で ArUco が内部的に Threshold を一つにしてしまっているところを外側で複数振って食わせて自前で結果をマージしたところ認識が劇的に改善しました。

これでほぼトラッキングが外れなくなりました。

f:id:hecomi:20150805165829p:plain

ポリゴン化

基本的には cv::approxPolyDP を使ってポリゴン化しているのですが、今回は対象がレゴという最小の辺の長さがある程度決まっていて且つ 90 度単位でしか折れ曲がらないことがわかっているので、こういったルールを利用して要らない点を棄却しています。

エッジ認識・エッジパターン認識

棄却処理後の点群に対して、尖った点の位置や方向を認識します。これが Unity 上で武器の場所になります。また尖った点同士の位置や方向の関係を見てパターンの認識も行っています。これによって武器をレーザ化したりシールド化したりします。

三角ポリゴン化

Unity では三角ポリゴンでないと扱えないので、ポリゴンを三角形分割する必要があります。今回はこれを行うために polypartition というライブラリを利用しました。

色々な三角ポリゴン化のアルゴリズムが含まれています。利用法も簡単で結果下記のように短いコードで三角ポリゴン化出来ました。

ゲーム

概要

認識側に時間を費やしてしまったのでゲームは簡単なエフェクトだけ盛ってかなり手抜きな感じにしました。基本的にリッチなグラフィックはプロジェクタの画で潰れてしまうので、コントラストの高いプリミティブベースの画作りでごまかしたつもりです。

f:id:hecomi:20150805230458p:plain

基本的には縦スクロールするシューティングゲームでグローバル座標に敵やアイテムのロケータを置いておき、アクティベーション用のコライダが通過したらローカル座標のステージにロケータに対応したプレファブをインスタンス化して動かす、みたいな感じです。ステージを視覚的に配置できるのはゲームエンジンのお陰ですね。これでステージは前日まで出来てなかったのですが何とか間に合いました。

f:id:hecomi:20150805190051p:plain

送られてきたデータは得られたポリゴンデータから自前でメッシュを作成して MeshFilterMeshCollider に食わせます。 これだけで簡単に自機の形状と当たり判定がぴったり実際の物体に合わさって表示される形になります。

f:id:hecomi:20150805184317p:plain

認識が 30 fps なのに対してゲームは 60 fps で動くので間の点を補間しなければなりません。そこで認識側ではポリゴン点やエッジ点をマーカから見たローカル座標に変換しておいて、Unity 側でマーカの位置・回転を先読みして補間すると同時にポリゴン点なども動かすようにしました。これで認識側から来るメッセージが 1、2 フレ飛んでも割りと滑らかになったと思います。

いつ認識が外れたり別の武器になるとも知れないエッジ点の認識結果と、押した・話したイベントが呼ばれると保証されてないハードウェアの入力との間でいい感じにステートを扱うのが大変でした...。会場の無線の関係もあり、結局ハードウェア自体は今回は ON/OFF しか取っていない仕様だったので本番では弾が出っぱなし or 出ないを避けることが出来ず無念。。次回の課題です。

使用したライブラリ・素材

ゲームを作成するに辺り、keijiro さんのライブラリに多々お世話になりました。

BGM は MusMus さんからお借りしました。

赤外線カメラの選定

いくつかカメラを試しました。

Xtion

  • IR 画は 640x480 @ 30 fps
  • USB をつなげるだけで赤外線投光も含めて動作して便利
  • センサが小さく露光時間が長いせいかブレが大きく、速く動かすとロストする

RealSense F200

  • IR 画 は 640x480 @ 300 fps で激ヤバ性能(このモードの時の解像度は実質半分くらい)
  • USB つなげるだけで動く
  • うちの PC と相性が悪いのか絶望的に安定しない、使ってると接続が途切れてしばらくしないと使えない

f:id:hecomi:20150804224011p:plain

Leap Motion

  • スペックは調べてないです...、かなり速い
  • リアプロの関係上、真下に取り付けられないため、端につけると対辺の解像度がかなり低く認識できない

Kinect v2

  • IR 画は 512x424 @ 30 fps
  • 別電源が必要
  • 赤外線投光はかなり強く波長は 827-850 nm? 付近
  • ブレはかなり少ない

DC-NCR300U

  • レゴの時に使っていて壊してしまって試し忘れてました...。
  • 1920x1080 @ 15 fps / 1024 x 768 @ 30 fps
  • 歪みが大きいのでキャリブ必要あり

本当は F200 を使いたかったのですが、うちの PC(ALIENWARE 17)とは相性が悪くデモ用途には厳しいのと解像度が足らず断念しました。他にも別途マイクロビジョンさんから VGA 60 fps な赤外線カメラを発注したのですが本番までには間に合わず...。今回は Kinect v2 を利用することにしました。誰か Point Grey のカメラ恵んで下さい。

先行事例・研究

テレビ石・光ファイバ

最初はテレビ石の体験をメインにゲームを作る予定をしていたのですが、色々と調査をした結果、Hasso Plattner Institute の Lumino(2010)や、明治大学 福地研究室の Ficon(2011)が、光ファイバを使用して立体物への応用などより進んだ研究をされています。

後はディズニーリサーチも 2012 に発表しています。向きを変えたりセンサにしてるの面白いですね。

リアプロ

リアプロでマーカ認識するタンジブルなものでは Reactable が有名です。

Reactable に用いられているマーカ認識のソフトウェアコンポーネントは reacTIVision として GPL で公開されています。

通信としてはタンジブルインターフェース用の TUIO という OSC をラップしたプロトコルを使用していて、色々な実装があって面白いです。

液晶型

商品としては Microsoft の PixelSense(旧 Surface)で、Samsung の SUR-40 や Lenovo の HORIZON 2 が商品として出ています。

PixelSene はその名の通り画素中に赤外線センサが入っていて、IR を含むバックライトからの反射を検出することによりディスプレイ上の物体(手指やマーカ等)を検出することが出来ます。

これを用いて、ところてんさんがいくつかゲームを作成されています。

今回の作品の差別化ポイントは、

  • リアルタイムにコントローラを拡張可能
  • ハードウェア連動
  • 上記を2点を踏まえてゲームにした

の3点かな、と思います。コンセプトと同じです。ただ、ハードウェア連動だけどこかもっと進んだものを見たことあった気がするのでご存じの方は教えて下さい。

今回の反省点・次回への展望

認識速度・手法

動画を見るとお分かりいただけるように、かなりレイテンシが大きいです。これは主にプロジェクタ・カメラともに 30 fps で動いていることによって引き起こされています。

人間が操作する物体に直接映像を追従させるとするとこのレイテンシがとても気になります。これを避けるためには、

  1. 見た目で対応する
    • 例えばプロジェクタで照らすのでなくハードウェアそれ自体が光ってコライダや武器の発射をそれにあわせる
    • 先読みをもっとするがぼんやりとブラーを掛けた表現で追従してる感を出す
  2. カメラ・プロジェクタ共に高速なものを利用する
  3. ハードウェアを使って別方式を考える

といったことが考えられます。2 が今回は手に入らなかったので 1. でやろうと思ったのですが、littleBits のようにブロック間に電気を通すことが(我々の)技術・工数的に出来なかったので断念しました。

次は 2. と 3. をやろうと思っていて、私の方は高速なカメラやプロジェクタを使って色々テストしていきたいです。その際、マーカ認識はちょっと重たい処理になるので、次は赤外線チップ LED でパターンを作成してパッシブでなくアクティブな認識にしようと考えています。3. は別方式を id:jonki と話してて思いついたので彼にやってもらおうと思います。

ハードウェアの取りこぼし

会場の無線が悪かったこともありますが、ON / OFF 時のみにイベントを送信する設計がおそらく失敗でした。。そこで次回は、上のアクティブ型の認識と併せて、ボタンを押下した時に特定の LED が光るようにして画像もしくはフォトディテクタベースでボタン押下の認識を行おうかと考えています。その他の即時性の必要ないステートだけ別途無線で送る、みたいな形を試してみます。

ゲーム性

コントローラの拡張などをうまくゲームデザインに盛り込めなかったので次回はもっと工夫したいです。あとハードウェアも前回(Mont Blanc Pj.)は出力のみ、今回は入力のみだったので、次は双方向でなにかできるようにしたいです。

おわりに

会場では「前回もレゴやってましたよね?」と覚えていてくださっていた方も結構いらっしゃいまして嬉しかったです。お越しくださった方ありがとうございました。また素晴らしい場を提供してくださった運営の方々、本当にありがとうございました。来年も出せるよう頑張ろうと思います。

期間が短かったのでもっと色々やりたいことはあったのですが、作業時間と予算・我々の技術考えると結構限界が来て色々出来なくて悔しかったところも多々あります。それらは改善して次回に繋げられればと思います。

個別の具体的なコードの紹介はついては別途記事を起こしていこうと考えています。何かご質問・ご要望などあればご遠慮なくTwitter 等で @hecomi までお尋ねください。