Magic Leap 1 QRコードトラッキングについて
概要
Lumin SDK 0.25からバーコードトラッキング APIが搭載されました。この記事ではMagic Leap 1でバーコードトラッキング機能を実装する方法と利用する際に気をつけるべき点を説明します。
現時点において、バーコードトラッキングはQRコードのみサポートしているため、QRコードによるトラッキングについての説明となります。
QRコードトラッキング機能について
Magic Leap 1でQRコードのポジション、エンコードされたデータ(URLやテキスト情報)を取得することができます。QRコードはモデル1とモデル2のみサポートしています。(モデル1とモデル2については以下のリンク先ページにてご確認ください。)
同時追跡可能なQRコードの数
16個のQRコードを同時に追跡することができます。(16個以上のQRコードがある場合、一番小さいQRコードまたは一番遠いQRコードが除外されます。)
開発環境
以下はLumin SDK のバージョンに対し、サポートしているUniry Editorのバージョンが全て網羅したページになります。
https://developer.magicleap.com/en-us/learn/guides/unity-doc-archive
※ Unreal Engine、Lumin Runtimeでは当機能を利用することができません。
構築 / 実装
ここではUnity Editorを使用し、Magic Leap 1上で動作するQRコードトラッキングのサンプルアプリケーションを構築します。
Privileges(特権)
Camera Captureの設定が必要です。(この設定を行うと、Magic Leap 1のカメラ撮影機能とビデオ撮影機能は利用できません、)
API Level
Level 9 以上の設定が必要です。
1. シーンの作成
Magic Leap の Exampleシーン(Hello Cubeなど)を複製。ヒエラルキー上にあるMain CameraとDirectional Light 以外のGame Objectを全て削除します。
2. Privilege Requesterの作成
Privilege Requester というGameObjectを作成します。
Privilege RequesterのGame Objectに対し、Add Componentを行い、MLPrivilegeRequesterBehaviorBehaviorクラスを追加します。
MLPrivilegeRequesterBehavior クラスの Privilege に Camera Capture を追加します。
3. MLQRCodeVisual の作成
QRコードトラッキングのポジションに配置するCubeを作成。
名称をMLQRCodeVisualに変更。
Scaleは x = 0.06, y = 0.06, y = 0.06 に変更。
MLQRCodeVisualの配下にTextMeshを追加。生成したTextMeshの名称をinfoに変更。
infoのPosition、Scale、Text、Text Meshのカラーなどの設定値は、上記の設定を参考にしてください。
次に MLQRCodeVisual.cs というC#スクリプトを新規作成します。その後、以下のコードを反映します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.MagicLeap;
public class MLQRCodeVisual : MonoBehaviour
{
[SerializeField]
private TextMesh dataText;
#if UNITY_LUMIN
private Timer disableTimer;
#endif
void Awake()
{
#if UNITY_LUMIN
disableTimer = new Timer(3f);
#endif
}
void Update()
{
#if UNITY_LUMIN
if (gameObject.activeSelf && disableTimer.LimitPassed)
{
gameObject.SetActive(false);
}
#endif
}
public void Set(MLBarcodeScanner.BarcodeData data)
{
#if UNITY_LUMIN
disableTimer?.Reset();
#endif
transform.position = data.Pose.position;
transform.rotation = data.Pose.rotation;
dataText.text = data.ToString();
gameObject.SetActive(true);
}
}
MLQRCodeVisual.cs を MLQRCodeVisual Game Object にAdd Componentで追加。その後、MLQRCodeVisual.cs の Data Text を MLQRCodeVisual の 子コンポーネント、info を設定します。
MLQRCodeVisualをPrefab化。ヒエラルキーにあるMLQRCodeVisualは削除します。
4. MLQRCodeSampleの作成
MLQRCodeSample というGameObjectを作成します。
次にMLQRCodeSample.csというC#スクリプトを新規作成後、以下のコードを反映します。
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.MagicLeap;
using UnityEngine.XR.Management;
using static UnityEngine.XR.MagicLeap.MLBarcodeScanner;
using BarcodeSettings = UnityEngine.XR.MagicLeap.MLBarcodeScanner.Settings;
public class MLQRCodeSample : MonoBehaviour
{
[SerializeField, Tooltip("QRコードの大きさをメートル単位で表したもの")]
private float QRCodeSize = 0.1f;
[SerializeField, Tooltip("QRコードのデータを可視化するPrefab")]
private MLQRCodeVisual qrCodeVisualPrefab;
// トラッキング済みのQRコード
private Dictionary<string, MLQRCodeVisual> qrCodeVisualByBarcodeData = new Dictionary<string, MLQRCodeVisual>();
// QRコードトラッキングの設定
private BarcodeSettings _barcodeSettings;
// QRコードスキャンの重複起動を防ぐためのフラグ
private bool _isScanning;
// Control入力がサブスクライブされているかどうかを確認するためのフラグ
private bool _didInit;
void Start()
{
MLBarcodeScanner.BarcodeType type = MLBarcodeScanner.BarcodeType.All;
_barcodeSettings = MLBarcodeScanner.Settings.Create(false, type, QRCodeSize);
SetSettingsAsync(_barcodeSettings);
}
private void MLInputOnOnTriggerDown(byte controllerid, float triggervalue)
{
#if PLATFORM_LUMIN
// Controlのトリガーが押した状態で且つ、QRコードのスキャンを実施していない場合
if (triggervalue > .5f && !_isScanning)
{
// QRコードのスキャンを開始
StartScanningAsync();
// QRコードのスキャン中を判定するフラグを立てる
_isScanning = true;
// Controlを振動させる
MLInput.Controller targetController = MLInput.GetController(controllerid);
targetController.StartFeedbackPatternVibe(MLInput.Controller.FeedbackPatternVibe.ForceDown, MLInput.Controller.FeedbackIntensity.Medium);
}
#endif
}
private void MLInputOnOnTriggerUp(byte controllerid, float triggervalue)
{
#if PLATFORM_LUMIN
// Controlのトリガーが離した状態で且つ、QRコードのスキャンを実施している場合
if (triggervalue < .5f && _isScanning)
{
// QRコードのスキャンを停止
StopScanningAsync();
// QRコードのスキャン中を判定するフラグをOFFにする
_isScanning = false;
// Controlを振動させる
MLInput.Controller targetController = MLInput.GetController(controllerid);
targetController.StartFeedbackPatternVibe(MLInput.Controller.FeedbackPatternVibe.ForceDown, MLInput.Controller.FeedbackIntensity.Medium);
}
#endif
}
private void OnDestroy()
{
}
private void OnEnable()
{
#if PLATFORM_LUMIN
// XR Managerが動作中かを確認します。1つでも実行されていれば、Magic Leap 1であるとみなし、
// ControlのTriggerのイベントハンドラーを登録する。
if (XRGeneralSettings.Instance.Manager.isInitializationComplete)
{
_didInit = true;
MLBarcodeScanner.OnMLBarcodeScannerResultsFound += OnMLBarcodeScannerResultsFound;
MLInput.OnTriggerDown += MLInputOnOnTriggerDown;
MLInput.OnTriggerUp += MLInputOnOnTriggerUp;
}
#endif
}
private void OnDisable()
{
if (_didInit)
{
MLBarcodeScanner.OnMLBarcodeScannerResultsFound -= OnMLBarcodeScannerResultsFound;
MLInput.OnTriggerDown -= MLInputOnOnTriggerDown;
MLInput.OnTriggerUp -= MLInputOnOnTriggerUp;
}
}
#region Magic Leap Barcode Scanner API
private void SetSettingsAsync(BarcodeSettings value)
{
_ = MLBarcodeScanner.SetSettingsAsync(value);
}
private void StartScanningAsync(BarcodeSettings? settings = null)
{
_ = MLBarcodeScanner.StartScanningAsync(settings);
}
private void StopScanningAsync()
{
_ = MLBarcodeScanner.StopScanningAsync();
}
private void OnMLBarcodeScannerResultsFound(BarcodeData data)
{
Debug.Log(data.StringData);
if (data.Type != MLBarcodeScanner.BarcodeType.None)
{
ExtractBarcodeScannerData(data);
}
}
/// <summary>
/// QRコードのPrefabを作成または更新します。
/// </summary>
/// <param name="data"></param>
private void ExtractBarcodeScannerData(BarcodeData data)
{
Debug.Log(data.StringData);
if (qrCodeVisualByBarcodeData.TryGetValue(data.StringData, out MLQRCodeVisual visual))
{
visual.Set(data);
}
else
{
MLQRCodeVisual qrCode = Instantiate(qrCodeVisualPrefab);
qrCodeVisualByBarcodeData.Add(data.StringData, qrCode);
qrCode.Set(data);
}
}
#endregion
}
MLQRCodeSample.cs を MLQRCodeSample Game Object にAdd Componentで追加。
MLQRCodeSample.cs の qrCodeVisualPrefabにプレハブ化したMLQRCodeVisual を設定します。
QR Code Sizeのデフォルト値を0.1としています。この値はメートル単位となるため10cmのQRコードを対象とする設定になります。(QR Code Sizeで設定した大きさのQRコードを用意してください。サイズが異なるとポジションがズレます。)
5. アプリケーションのビルド
QRコードトラッキングのサンプルアプリケーションの構築は、これで完了しました。最後はMagic Leap 1にビルドする設定~ビルドまでを行います。
Player Settings の Magic Leap Manifest Settings にある Controller Pose、Camera Capture にチェックを入れます。以上でQRコードのトラッキングの実装と設定は全て完了しました。Magic Leap 1をPCに接続して、Build And Run を実行します。
6. 動作確認
Control の Triggerを押しつづけるとQRコードのトラッキング処理が開始され、対象のQRコードが見つかれば、MLQRCodeVisual GameObjectがQRコードの上に配置されます。(Triggerを離すとQRコードのトラッキング処理は停止します。)
注意点
1. トラッキングの遅延について
検出されたQRコードの位置と実際の位置の間に遅延が発生します。
遅延が発生する原因は2つ。
上記により、リアルタイムで且つスムーズなトラッキングを行うことができません。
対応案
1. QRコードトラッキングするオブジェクトが静止状態の場合
検出したタイミングでQRコードトラッキングのスキャンを無効にし、PCFを使ってオブジェクトの位置を保存します。(複数のセッションでコンテンツを持続させたい場合や、ヘッドトラッキングが失われても、QRコードを再スキャンすることなくオブジェクトの位置を復元させたい場合など、)
2. QRコードトラッキングに連動してオブジェクトの位置をリアルタイムにトラッキングを行う場合
ポーズを補間・予測してトラッキングの品質を向上させます。
ネットワークライブラリは、動的オブジェクトに対してこれを行います。 Photon SmoothSync または MirrorNetworkingのNetworkTransformBase.cs が参考になります。
2. QRコードの推奨サイズ
ユーザーがQRコードとどれくらい離れているかによって異なります。一般的な照明の明るさの場合、A4サイズの紙に印刷されたQRコードであれば、約1メートルの距離からトラッキングされます。(トラッキングされた後、よりある程度の距離が離れてもトラッキングは維持されます。)
QRコード自体が小さい場合と大きい場合、距離によって小さくなったり大きくなったりします。それに応じて、検出範囲と追跡範囲が短くなったり長くなったりします。
QRコードは少なくとも4cm(明るい部屋の場合)以上の大きさで、QRコードの周りに白い枠があること。カメラからはっきり見えるような大きさにする必要があります。
16個のQRコードを同時に追跡することができますが、16個のQRコードをひとつのカメラに収めようとした場合、必然的にQRコードのサイズが小さくなるため、認識率は悪くなります。(16個のQRコードを同時追跡するのは現実的でなく、数個程度に留めるべきです。)
まとめ
今後、Magic Leapは、QRコードトラッキングを効果的に使用するための情報をオンラインのガイドで提供する予定です。(注意点でまとめた内容をより深掘りしたガイドになると思います。)
参考
QRコードのExample PackageはMagic Leap Developer Relations の方が作成しております。パッケージは以下から入手することができます。(今回の記事のサンプルもこちらのExampleを参考に構築しました。)
Magic Leapは、QRコードトラッキングを効果的に使用するための情報をオンラインのガイドで提供する予定です。
最後に
弊社では、Magic Leap 1を活用したアプリケーションをMagic Leap Worldに2つリリースしています!
OnePlanet XR
「OnePlanet XR」はAR/MR技術に専門特化したコンサルティングサービスです。豊富な実績を元に、AR/MR技術を活用した新たな事業の立ち上げ支援や、社内業務のデジタル化/DX推進など、貴社の必要とするイノベーションを実現いたします。
MRグラスを活用した3Dモデル設置シミュレーション
ご相談から受け付けております。ご興味ございましたら弊社までお問い合わせください。
お問い合わせ先: https://1planet.co.jp/xrconsulting.html
OnePlanet Tech Magazine
技術ブログマガジンも連載中です!