デベロッパーズガイドに詳細載ってないけど出来そうなことをやったら出来ました、という報告です。
もくじ
- MOVERIO BT-300とは
- Android StudioはMOVERIOの開発に使えないの?
- Unityで3D(サイドバイサイド)を試す
- Xamarin (VS) で作ったアプリを配置してみる
- その他注意点とか
1. MOVERIO BT-300とは
いわゆるスマートグラスです。情報は公式ページにのってますが、スマートグラスやHMDに類する中では小型軽量なのが特長です。
https://twitter.com/baku_dreameater/status/804294589867692032
はい。MOVERIO BT-300を予約で買いました。
そこで、開発者目線で軽く触った内容を共有しておきます。
具体的な視点としては、Android Studio
以外の2大MOVERIO開発環境であるUnity
とXamarin
でふつうにMOVERIOにさわれるね、という話を紹介していきます。
Unity
でやったこと- サイドバイサイド(3D対応)を適当に試した結果を紹介します。
Unity
からMOVERIO BT-300の固有APIを叩く話は本記事では扱いません。
Xamarin
でやったこと- その他
Unity
いじってた3D対応の注意点をひとつ発見したので、それを紹介します。
2. Android StudioはMOVERIOの開発に使えないの?
使えます。全く問題なく使えます。
というか、公式の技術者向け情報から拾えるデベロッパーズガイドにはAndroid Studio
を使う場合の手順が載っています。つまりデファクトスタンダードです。
こんな記事を書いておいてアレですが、導入の手筋としては大人しくAndroid Studio
を使ってガイド通りに進め、サンプルプロジェクトの動作を見ておくことをオススメします。
3. Unityでサイドバイサイド(3D対応)を試す
ここからが本題です。本節に対応したサンプルパッケージはこちらから。「文章は読まん!」という人はパッケージ中の「Moverio3dSample/Scenes/Main.scene
」を開き、何かを感じ取ってください。
サンプルはEthanとグルグル動くブロックを表示させてますが、本記事ではユニティちゃんを表示した例で説明していきます。イメージとしては以下のような画面を作ればOKです。
ここからは具体的な説明に進みます。
MOVERIO BT-300では左目、右目用の画像を繋げたものを用意し、3Dモードに入ることで3Dに対応します。具体的には次のような処理がされてます。
- アプリはMOVERIOに1280x720で画像を渡す
- MOVERIOは受け取った1280x720の画像を横方向に2倍引き延ばして2540x720の画像にする
- 大きくした画像を左半分と右半分にわけて表示する
この処理で画像がどう変化するか体感したければ、MOVERIOホーム画面で3Dモードに入ってみるのをオススメします1。
ともかく、この仕様を踏まえるとUnity
側から渡すべき画像の中身は以下のようになります。
- 1280x720画像で、左半分は左目にうつす画像、右半分は右目にうつす画像にする
- 画像は切断後に引き延ばし処理されることを考えて、あらかじめ画像を横方向0.5倍にスケールしておく
上の画像ではユニティちゃんが細くなってますが、これは引き延ばしを想定して横方向に縮めているためです。2倍引き延ばすと普通のユニティちゃんに戻り、MOVERIO装着時に見えるイメージはコチラの方になります。
逆に、引き延ばしを忘れて等倍映像のユニティちゃんをヨコに並べると太ったユニティちゃんが出てきてしまうので気を付けましょう。
ここまでは主に仕様の話でした。実装のことも軽く触れておくと、サンプルのケースでは以下のような方針でやっています。
- 目に相当するカメラをふたつ用意し、目カメラのレンダー先(
Target Texture
)をデフォルトではなくRender Texture
に設定 Render Texture
をMaterial
に載せてPlane
に投影し、視聴用スクリーン的なものを用意- Mainのカメラには視聴用スクリーンがうつるようにする
画像のスケール処理はRender Texture
の解像度を変えたりPlane
のScale
を調整することで良い感じにしています。多分ほかにも手はあるので、効率良さそうなのを思いついたら試してみてください。
いっぽう、この手ではデメリットとしてGUIのレイヤー制御がうまくいかないことも分かります。上のやり方ではGUIをメインのカメラにだけ表示しているのですが、この場合次のような問題が生じます。
- 片目にしか映らない
- GUIが横にグニョーンと拡大されてしまう
GUIが延びてしまっている参考として、さきほどの画面の右目部分だけ抜き出したのがコチラです。
これらの問題を解決する手としてはメニュー相当のオブジェクトも3D空間中に作り込んでしまうとか、あるいはMOVERIOの固有APIを叩いてメニュー表示時だけ2D化、主画面は3D、というような切り替えをサポートする必要があるでしょう。
ただしMOVERIOは3Dモードのカーソル挙動がちょっとアレなので(これについては本記事の末尾に記載)、見た目の問題だけ解決してもダメだったりします。
(2016/12/5追記) : ひとつ書き忘れていたので追記ですが、UnityでMoverio用にアプリを作る際には「Player Settings」でPortraitを無効化してください。これを忘れていると、首を大きくかしげたときにUnityがPortraitモードへ遷移しようとしてしまい(さらにMoverioがそれを邪魔して?)、UIがグチャグチャになります。
5. Xamarin (VS) で作ったアプリを配置してみる
前の節ではUnity
を使い、MOVERIOの3D対応が使えるらしいことを確認できました。
Xamarin
でもUIレイアウトに配慮すれば当然同じようなことが出来ますが、こちらでは別の重要案件としてMOVERIO BT-300の固有ライブラリ(BT300Ctrl.jar
)が使えるか試してみましょう。
ここからはVS2017RC
を使った例を示します。たぶんVS2015
やXamarin Studio
を使っていても大筋は変わらないと思います。
まずはプロジェクトの新規作成をし、jar
のラッパーをビルドするところまで一気にやります。クロスプラットフォームとか贅沢は言わずにおとなしくAndroid
向けアプリとして作っていきましょう。
- メインのアプリプロジェクトとして、単一画面プロジェクトを新規作成
- 1で作ったソリューションに対して追加プロジェクトを作成し、種類はバインドライブラリプロジェクトにする
- メインプロジェクトの参照ライブラリとして、2で作ったバインドライブラリプロジェクトを追加
- 2作ったバインドライブラリプロジェクトには
Jars
フォルダがあるので、ここに公式からダウンロードしてきたBT300Ctrl.jar
を追加。 - 4で追加した
BT300Ctrl.jar
について、プロパティでビルドアクションがInputJar
になっているのを確認 - とりあえずビルド。
ここまでやると、バインドライブラリプロジェクトが勝手にBT300Ctrl.jar
のラッパーを作ってくれるので、以降はメインのプロジェクトのみをいじり、MOVERIOのAPIはラッパー越しに叩けばOKとなります。
あとはそれっぽくUIを作ってメインコードにそれっぽくハンドラを書けば動きます。
using Android.OS; using Android.App; using Android.Widget; using System.Threading.Tasks; using Com.Epson.Moverio.Btcontrol; namespace MoverioBt300BasicSample { [Activity(Label = "MoverioBt300BasicSample", MainLauncher = true, Icon = "@drawable/icon")] public class MainActivity : Activity { DisplayControl _displayControl; protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); //Initialize handlers those using MOVERIO API _displayControl = new DisplayControl(ApplicationContext); var button2DMode = FindViewById<Button>(Resource.Id.button2DMode); var button3DMode = FindViewById<Button>(Resource.Id.button3DMode); var buttonMute3sec = FindViewById<Button>(Resource.Id.buttonMute3Sec); var checkBoxShowToast = FindViewById<CheckBox>(Resource.Id.checkBoxShowToast); var seekBarIntensity = FindViewById<SeekBar>(Resource.Id.seekBarIntensity); button2DMode.Click += (_, __) => _displayControl.SetMode(DisplayControl.DisplayMode2d, checkBoxShowToast.Checked); button3DMode.Click += (_, __) => _displayControl.SetMode(DisplayControl.DisplayMode3d, checkBoxShowToast.Checked); buttonMute3sec.Click += (_, __) => Task.Run(async () => { _displayControl.SetMute(true); await Task.Delay(3000); _displayControl.SetMute(false); }); seekBarIntensity.ProgressChanged += (_, e) => _displayControl.SetBacklight(e.Progress); } } }
using Com.Epson.Moverio.Btcontrol;
とあるのがラッパーによって使えるようになったAPIの名前空間です。
上記コード中のDisplayControl
クラスが実際に使っているクラスで、必要ならもう一つのラップクラスであるSensor
も利用できます。
今回は「とりあえず公式サンプルと同じことをやろう」ということでセンサーは使っていません。
手元でささっと試したい人向けにソースをGitHubに上げてますが、再頒布になってしまうのを防ぐため、BT300Ctrl.jar
は含めていません。ライブラリは公式から取得してください。
5. その他注意点とか
Unity
の節でもほんの少しだけ触れましたが、現状のMOVERIO BT-300は3Dモード時のカーソル移動に若干問題というかクセがあります。
その内容ですが、3Dモード時はカーソルが左目ウィンドウか右目ウィンドウのいずれか一方にしか現れません。落書きで描くと以下のようなイメージです。
直感的な解釈ですが、MOVERIOは3Dモードになると左+右ディスプレイをデュアルモニタ的に認識するので、カーソルが全体の中でひとつしか存在しないよ、ということになるみたいです。
この解釈でいくと、逆に2D表示はディスプレイの複製だと思っておけば分かりやすいです。
それで、この3Dモード時のカーソル動作は動きとしては納得できるんですが、UXとして使いやすいかと言われるとちょっとアレですね…。
対策としてはコントローラのメインボタンを押したら2Dに戻す、とかそういった操作をサポートしてカーソル操作への足がかりを作った方が親切なのかもしれません。
今回は以上です。次回に記事化するとしたら、今度はセンサーを使う例も紹介したいと思います。
- これをやるとホーム画面がヒジョーーーに視認しづらくなります。そもそもホーム画面で3Dモードに入れてしまうのはバグに見えるんですが、果たしてバグだとしたら直るのでしょうか…? ↩