Tokyo HoloLens Meetup vol.2
鈴木 孝明
Sharing Deep Dive
- 30 分で掴み取る HoloLens で最もクールな機能の勘所 -
Name
鈴木 孝明 a.k.a @xin9le
Work
XR Engineer
Award
Microsoft MVP for Visual Studio
and Development Technologies
Web Site
http://xin9le.net
About Me
No-Wall Communication Platform
AR / VR の壁、言語の壁がない
世界中の誰とでも会話ができる空間
SxSW 2017 で 1st デモを披露
開発は 5 名 (エンジニア 2 名) で 1 ヵ月
自分たちが想像した以上に反響があった
Project Sonata
http://connect.sonata.world
Alex Kipman にも知ってもらえた
HoloLens が指す「共有」とは
What’s Sharing
複数人で同一のホログラムを
操作/閲覧する体験
前回 80 台以上で繋いで話題に
同一空間内で
同じ室内で HoloLens を被ってホログラムを見るケース
HoloLens における「Sharing」は基本的にコレ
異なる空間で
地理的に異なる場所にいる (e.g. 別室) ケース
AR / VR をまたぐ体験の場合もこっち
Sharing Patterns
本日扱うのは
こっち
Holograms 240 : Sharing Holograms
Windows Holographic – Academy という公式チュートリアルの一部
とりあえず動かして試したい場合はコレがお手軽
https://developer.microsoft.com/en-us/windows/mixed-reality/holograms_240
今回ピックアップする内容
チュートリアルではあまり表に出てこない基本的な考え方
実装上のポイントやハマりポイント
How To Learn Sharing
Sharing で最も大事な「錨」を下ろそう
World Anchor
位置/姿勢を固定する Component
GameObject に引っ付けると transform をオーバーライド
空間における「ココ!」の決定に利用 (= 地図にピンを刺す的な)
https://docs.unity3d.com/ScriptReference/VR.WSA.WorldAnchor.html
Sharing のキモは「座標系」の共有
複数のユーザーで共通の空間アンカーを設定
それを原点としたローカル座標系として GameObject を扱う
WorldAnchor (= 空間アンカー) #とは
𝑍 𝐴
𝑥 𝐴
𝑂 𝐴
𝑥 𝐵
𝑍 𝐵
𝑂 𝐵
A / B で同じ座標系を共有
𝑍𝑆
𝑂𝑆
𝑥 𝑆
※ 実際は 3 次元だけど便宜上 2 次元で表現
共有座標系で GameObject を扱う
空間アンカーが設定された GameObject の子要素とする
localPosition / localRotation で相対座標として位置/姿勢を制御
双方向通信による変更通知
ネットワークを介して位置/姿勢をリアルタイムに通知/反映
HoloToolkit-Unity の SharingService.exe がサーバーとして機能
オブジェクト共有の仕組み
var anchor = gameObject.AddComponent<WorldAnchor>(); // 空間アンカーを設置
if (!anchor.isLocated) // 即座に空間アンカーが設定されないときは変更を監視
{
WorldAnchor.OnTrackingChangedDelegate handler = null;
handler = (_, located) =>
{
if (!located) return;
anchor.OnTrackingChanged -= handler;
};
anchor.OnTrackingChanged += handler;
}
How To Add
var anchor = gameObject.GetComponent<WorldAnchor>();
if (anchor != null)
DestroyImmediate(anchor); // 普段使わないコレを使うらしい
How To Remove
空間アンカーの前回値保持
Previous Value Holding
WorldAnchorStore
ローカルストレージに空間アンカーをシリアライズ
[Key : 名前 / Value : WorldAnchor] の辞書型ストレージ
メリット / デメリット
アプリを再起動しても高速に空間アンカーを復帰させられる
保存/読み込みが別空間で行われると全く使い物にならない
前回値保持の仕組み
// 非同期に取得する必要があるので若干めんどくさい
WorldAnchorStore.GetAsync(store =>
{
this.AnchorStore = store; // プロパティなどに保持
var anchor = store.Load(name, gameObject); // 前回値読み込み
});
// 名前と空間アンカーをペアにして保存
var anchor = gameObject.AddComponent<WorldAnchor>();
var name = "何か一意な名称";
this.AnchorStore.Save(name, anchor);
How To Implement
空間アンカーを他のユーザーと共有する
Share World Anchor
WorldAnchorTransferBatch
空間アンカーに関する情報を丸ッと byte 配列にシリアライズ
ネットワーク経由で全ユーザーに送信してデシリアライズ
位置合わせのアルゴリズム
WorldAnchorTransferBatch が内部で何をしているのかは不明
空間メッシュ / 特徴点 / 空間アンカーを使って計算している予感
空間アンカー共有の仕組み
var batch = new WorldAnchorTransferBatch();
batch.AddWorldAnchor(anchor.name, anchor);
var buffer = new List<byte>(); // ここにシリアライズ結果を入れてもらう
WorldAnchorTransferBatch.ExportAsync(batch, x => buffer.AddRange(x), x =>
{
const int minAnchorDataSize = 100000; // 適当に最低保証値を設定
if (x != SerializationCompletionReason.Succeeded) return;
if (buffer.Count <= minAnchorDataSize) return;
// 空間アンカーの共有のために buffer をサーバーに送信したり
});
How To Serialize
// data (byte[]) : 何らかの方法で手に入れた空間アンカー情報
WorldAnchorTransferBatch.ImportAsync(data, (reason, batch) =>
{
if (reason != SerializationCompletionReason.Succeeded) return;
if (!batch.GetAllIds().Any()) return; // 空間アンカー情報が含まれるか
var name = batch.GetAllIds().First(); // 最初のひとつを使うとする
batch.LockObject(name, gameObject); // 設置したい GameObject に適用
});
How To Deserialize
小さ過ぎるデータサイズ
シリアライズ結果が小さいとデシリアライズに失敗しやすい
HoloToolkit-Unity のサンプルでは 100 KB を最低保証値としている
滅多に成功しない保存/読み込み
まずまずシリアライズに全然成功しない #成功率 10 % 未満なのでは
データサイズが一定以上あってもデシリアライズに失敗しまくる
成功するまでリトライするような地道な実装が必要
ハマりポイント #1
大き過ぎるデータサイズ
100 KB どころか簡単に 10 MB とか超えてくる
弊社内で実験したときは 50 MB を超えたことも
バカにならないデータ転送量
50 MB を全ユーザーにブロードキャストするとか危険の極み
海外でデモするときレンタル Wi-Fi (500 MB/day) とかだと即死
相当な実装上の工夫と安定した Wi-Fi 環境が必須
ハマりポイント #2
保存/読み込みが超絶遅い
シリアライズ / デシリアライズにそれぞれ 30 秒かかるとかザラ
1 分以上待って失敗とかもザラで圧倒的イラ壁
圧倒的デバッガビリティの低さ
Sharing の検証は実機を使って部屋中を動き回る必要がある
にも関わらずデバッグ時は PC にケーブルを繋いでないとダメ
そしてエミュレーターは何の役にも立たない…
ハマりポイント #3
ちょっとした余談
Additional Talk
Pros
Sharing はもちろん、音声通信など豊富な機能が用意されている
クライアント実装だけに集中して開発できる
Cons
カスタマイズ性が一切なく、ボトルネックになった際に対処不能
(簡単に) スケールアウトできないので少人数利用に限られる
自前 API がある場合、それと異なる通信の口を持つことになる
SharingService.exe の是非
SharingService.exe 不採用
サーバー側の開発は得意分野なので自由度を得る方が重要
MagicOnion を採用
弊社 CTO (@neuecc) 謹製の gRPC Wrapper ライブラリ
HTTP/2 ベースの通信なので非常に高速 #なハズ
Project Sonata は gRPC を Unity で動作させた世界初の公開事例
MessagePack for C# によりバイナリのサイズ/生成速度とも最適化
Grani の出した答え
これだけは覚えて帰りましょう
Today’s Summary
本日のまとめ
共有座標系
相対座標操作
同一空間内
かどうか考慮 注意点多し
Grani さん
頑張ってます
空間アンカー 前回値保持 空間アンカー
の共有
Project Sonata
Sharing に夢を見ても
甘く見るな
Grani leads VR/AR/MR future using C#!!
Thank you

Sharing Deep Dive