実現したいこと
- HoloLens2向けのアプリケーション開発をしています。
- QRコード読み込むと、仮想ボタンがQRコードの上に表示され、そのボタンを押すと、オブジェクトが生成されるアプリを開発したいです。
前提
Unityを使用して、HoloLens2向けのアプリケーションを開発しています。
Visual Studio 2022
Unity 2020.3 LTS
発生している問題・エラーメッセージ
- 現状、以下のように、QRを読み込むと、仮想ボタンが表示されますが、ボタンを押しても何も反応がありません(押した感はあります)
該当のソースコード
- Unityプロジェクト
- QRCodesManagerが主のオブジェクトです。
- QR CodesManager.csはQRコードの追加、更新、削除を管理しています。
- QR CodesVisualizer.csは、QRコードが認識された際のビジュアライズをしています。
- ビジュアライズしたいものをQRCodePrefabとしてインスペクターから設定できます。(私は、仮想ボタン「VoiceInputButton」を設定しています)
QR
1using System.Collections; 2 3using System.Collections.Generic; 4 5using UnityEngine; 6 7using Microsoft.MixedReality.QR; 8namespace QRTracking 9{ 10 public class QRCodesVisualizer : MonoBehaviour 11 { 12 public GameObject qrCodePrefab;//QRコードが認識されたときにインスタンス化されるプレハブ 13 public GameObject ButtonPrefab3; 14 15 16 17 private System.Collections.Generic.SortedDictionary<System.Guid, GameObject> qrCodesObjectsList; // 認識したQRコード(System.Guid(全世界で一意の識別子)が割り当てられる)とそれに対応するゲームオブジェクトのペアを保存している 18 private bool clearExisting = false; 19 20 struct ActionData //QRコードが追加、更新、削除されたときに発生するアクション 21 { 22 public enum Type 23 { 24 Added, 25 Updated, 26 Removed 27 }; 28 public Type type; 29 public Microsoft.MixedReality.QR.QRCode qrCode; 30 31 public ActionData(Type type, Microsoft.MixedReality.QR.QRCode qRCode) : this() //構造体のコンストラクタ。構造体を作成する際に呼び出される 32 { 33 this.type = type; 34 qrCode = qRCode; 35 } 36 } 37 38 private System.Collections.Generic.Queue<ActionData> pendingActions = new Queue<ActionData>(); //ActionData型のキューを作成している。QRコードにアクション(added,updated,removed)が発生すると、そのアクションとQRコードデータはこのpedingActionsキューに追加される 39 40 void Awake() 41 { 42 43 } 44 45 // Use this for initialization 46 void Start() 47 { 48 // GameObject qrCodeObject3 = Instantiate(ButtonPrefab3, new Vector3(0f, 0f, 1.4f), Quaternion.identity); //qrCodePrefabを生成する 49 50 System.Diagnostics.Debug.WriteLine("visualize start"); 51 System.Console.WriteLine("visualize start console"); 52 53 54 Debug.Log("QRCodesVisualizer start"); 55 qrCodesObjectsList = new SortedDictionary<System.Guid, GameObject>(); //qrCodeObjctsListの初期化 56 57 // イベントハンドラの登録。QRCodesManagerクラスのインスタンスの特定のイベントが発生したときに呼び出すメソッドを指定している。これらのイベントは、QRコードの追加、更新、削除、およびQRコードの追跡状態の変更を監視します。 58 QRCodesManager.Instance.QRCodesTrackingStateChanged += Instance_QRCodesTrackingStateChanged; 59 QRCodesManager.Instance.QRCodeAdded += Instance_QRCodeAdded; // 新たなQRコードが追加された場合に、Instance_QRCodeAddedメソッドを呼び出す 60 QRCodesManager.Instance.QRCodeUpdated += Instance_QRCodeUpdated; 61 QRCodesManager.Instance.QRCodeRemoved += Instance_QRCodeRemoved; 62 if (qrCodePrefab == null) 63 { 64 throw new System.Exception("Prefab not assigned"); 65 } 66 } 67 // QRコードの追跡状態が変化した場合に呼び出される 68 private void Instance_QRCodesTrackingStateChanged(object sender, bool status) 69 { 70 if (!status) 71 { 72 clearExisting = true; 73 } 74 } 75 76 // 新たなWQRコードが追加された場合に、Instance_QRCodeAddedメソッドを呼び出す 77 private void Instance_QRCodeAdded(object sender, QRCodeEventArgs<Microsoft.MixedReality.QR.QRCode> e) 78 { 79 Debug.Log("QRCodesVisualizer Instance_QRCodeAdded"); 80 81 lock (pendingActions) 82 { 83 pendingActions.Enqueue(new ActionData(ActionData.Type.Added, e.Data)); 84 } 85 } 86 87 // QRコードが更新された場合に呼び出される 88 private void Instance_QRCodeUpdated(object sender, QRCodeEventArgs<Microsoft.MixedReality.QR.QRCode> e) 89 { 90 Debug.Log("QRCodesVisualizer Instance_QRCodeUpdated"); 91 92 lock (pendingActions) 93 { 94 pendingActions.Enqueue(new ActionData(ActionData.Type.Updated, e.Data)); 95 } 96 } 97 98 // QRコードが削除された場合に呼び出される 99 private void Instance_QRCodeRemoved(object sender, QRCodeEventArgs<Microsoft.MixedReality.QR.QRCode> e) 100 { 101 Debug.Log("QRCodesVisualizer Instance_QRCodeRemoved"); 102 103 lock (pendingActions) 104 { 105 pendingActions.Enqueue(new ActionData(ActionData.Type.Removed, e.Data)); 106 } 107 } 108 109 // void Updateで呼ばれる 110 private void HandleEvents() 111 { 112 lock (pendingActions) // 複数のスレッドからリソースに同時にアクセスすることを防ぐ 113 { 114 while (pendingActions.Count > 0) // pendingActions(アクションのキュー)が終わるまでひたすら処理回す 115 { 116 var action = pendingActions.Dequeue(); 117 if (action.type == ActionData.Type.Added) //アクションがQRコードの追加なら 118 { 119 GameObject qrCodeObject = Instantiate(qrCodePrefab, new Vector3(0, 0, 0), Quaternion.identity); //qrCodePrefabを生成する 120 qrCodeObject.GetComponent<SpatialGraphCoordinateSystem>().Id = action.qrCode.SpatialGraphNodeId; // 現実世界の空間座標系をUnity座標系に変換する(QRコードに追従するように動くようになる)QRコードに関連する空間のノードIDをゲームオブジェクトに関連付けている。これによって、GameObjectが物理世界内の特定の位置・向きを持つようになる 121 qrCodeObject.GetComponent<QRCode>().qrCode = action.qrCode; // QRコードの情報をこのゲームオブジェクトに関連付けている 122 qrCodesObjectsList.Add(action.qrCode.Id, qrCodeObject); // qrCodesObjectsList(key: QRコードID, value: ゲームオブジェクト)に登録 123 } 124 else if (action.type == ActionData.Type.Updated)//アクションがQRコードの更新なら 125 { 126 if (!qrCodesObjectsList.ContainsKey(action.qrCode.Id))// Addで既に登録してあるのに、削除された以外で、keyがないことなんてあるのか 127 { 128 GameObject qrCodeObject = Instantiate(qrCodePrefab, new Vector3(0, 0, 0), Quaternion.identity); 129 qrCodeObject.GetComponent<SpatialGraphCoordinateSystem>().Id = action.qrCode.Id;//###########################なぜAddとUpdatedでGetComponent<QRCode>().qrCodeに代入するIDが異なるのかは謎########################################### 130 qrCodeObject.GetComponent<QRCode>().qrCode = action.qrCode; 131 qrCodesObjectsList.Add(action.qrCode.Id, qrCodeObject); 132 } 133 } 134 else if (action.type == ActionData.Type.Removed)//アクションがQRコードの削除なら 135 { 136 if (qrCodesObjectsList.ContainsKey(action.qrCode.Id)) 137 { 138 Destroy(qrCodesObjectsList[action.qrCode.Id]); 139 qrCodesObjectsList.Remove(action.qrCode.Id); 140 } 141 } 142 } 143 } 144 if (clearExisting) 145 { 146 clearExisting = false; 147 foreach (var obj in qrCodesObjectsList) 148 { 149 Destroy(obj.Value); 150 } 151 qrCodesObjectsList.Clear(); 152 153 } 154 } 155 156 // Update is called once per frame 157 void Update() 158 { 159 HandleEvents(); 160 } 161 } 162 163} 164
- VoiceInputButton
- QRコードが読み込まれたときに、QRコードの上に表示する仮想ボタンです。
VoiceInputButtonPressed.cs
1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5 6public class VoiceInputButtonPressed : MonoBehaviour 7{ 8 public GameObject ButtonPrefab; 9 public GameObject ButtonPrefab2; 10 11 12 13 void Start() 14 { 15 GameObject qrCodeObject2 = Instantiate(ButtonPrefab2, new Vector3(0f, 0f, 1.5f), Quaternion.identity); //qrCodePrefabを生成する 16 17 // ボタン押されたことのメッセージを表示したい 18 System.Diagnostics.Debug.WriteLine("#####System.Diagnostics.Debug.WriteLine#####"); 19 System.Console.WriteLine("#####START System.Console.WriteLine#####"); 20 Debug.Log("Start"); 21 22 23 } 24 25 void Update() 26 { 27 28 } 29 30 public void ButtonPressed() 31 { 32 // 新しいインスタンスを生成したい 33 GameObject qrCodeObject12 = Instantiate(ButtonPrefab, new Vector3(0f, 0f, 1.3f), Quaternion.identity); //qrCodePrefabを生成する 34 35 36 // ボタン押されたことのメッセージを表示したい 37 Debug.Log("#####ButtonPressed Debug.Log#####"); 38 System.Diagnostics.Debug.WriteLine("#####ButtonPressed System.Diagnostics.Debug.WriteLine#####"); 39 40 41 } 42} 43
試したこと
- (方針)QRコードのスクリプトの中では、別のオブジェクトを生成できない可能性がある。QRコードを読み込んだ時じゃなくて、Start()の時点でCubeが生成できるかどうか試す。
- QRCodesVisualizer.csのStart()で緑のCubeが表示できた。
- ✖(方針)Poster Sceneでそもそもボタンが動くのかどうか試してみる
- AdminMenuとHeadWidgetを配置する。AdminMenuのボタンを押して、HeadWidgetの表示非表示を制御することはできた。
- 次どうする?:となると、QRコードを読み込んだときに表示するボタンを押して、HeadWidgetの表示非表示が制御できるかどうかを試す。
- ✖(方針)いちいちHololens2にビルドするのめんどくさいから、Unity Editor内でQRコードを表示して、読み込めないか試してみる。
- Plane作って、QRコードのテクスチャ貼ったMaterialを貼ってみたけどQRCodeの認識ができないからだめそう。
- 👹(方針)QRコードを読み込んだときに表示するボタンを押して、HeadWidgetの表示非表示が制御できるかどうか。QRコードを読み込んで表示されたボタンとのインタラクションができないのでは。
- 試してみたこと:
(2)QRコード読み込んだ時に、VoiceInputButton.csのStart()で、青Cube
(3)ボタン押したときに、VoiceInputButton.csのButtonPressed()で、赤Cube
2. 結果:
UnityEditor上では、(1)だけできた(QRコードの認識ができないからしょうがない)
HoloLens2上では、全部だめ。
Editor上ではできて、HoloLens2上ではできないのが謎。
3. 考察:
QRコード読むのに特化していて、他とのインタラクションは制御できていない?いわけんさんのやつのタイトルが「Unity×HoloLens2×MRTK×QRCodeをとりあえず動かしたいとき」になっているのが気になる、とりあえず動かしたい時で、正式に使おうとしたらこのやり方じゃダメなのかも?
4. 結論:
別のやり方を試してみる。 - (方針)別のやり方を探す
- 他の人のQRコードリーダーを試してみる
- VuforiaのARマーカーを使用する
- 外付けのwebカメラを使う
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。