LoginSignup
4
0

More than 1 year has passed since last update.

Azure Spatial anchorsを使ったマルチプラットフォーム位置共有方法でつまずいた点

Last updated at Posted at 2022-04-29

はじめに

この記事は、自分がHoloLens2とAndroidとでマルチプラットフォーム化する際に困った部分を記載している記事になります。

※バージョンが更新された場合修正されているかもしれないので気を付けてください。

前提条件

公式がだしているAzure Spatial Anchorsのチュートリアルドキュメント

イワケンさんが出されている記事を参考にし

これらを一通り実践してから自分のつまづいたところを確認していただけると
理解しやすくなると思います。


また記事後半は、Azure Spacial anchorsphotonを使った
多人数で体験させるためのコンテンツをつくる際のつまづいた点もご紹介いたします。

開発する上で参考になるドキュメントですのでこれも一通り試していただけますと幸いです。

※HoLoLens2二台とAndroidを使ったものとなります。
iOSはMACが自分の環境にないので検証できていないです。

開発環境

機材やソフト バージョン
HoLoLens2 20348.1450
Unity 2020.3.24f1
Windows10
Visual Studio 2019
Mixed Reality Feature Tool v1.0.2111.0 Preview
Xperia XZ1 Android 9

Mixed Reality Feature Tool

Mixed Reality Toolkit バージョン
Mixed Reality Toolkit Foundation 2.7.3
Mixed Reality Toolkit Examples 2.7.3
Mixed Reality Toolkit Standard Assets 2.7.3
Mixed Reality Toolkit Test Utilities 2.7.3
Mixed Reality Toolkit Tools 2.7.3
Mixed Reality Toolkit Extensions 2.7.3
Azure Mixed Reality Services バージョン
Azure Spatial Anchors SDK Core 2.12.0
Azure Spatial Anchors SDK Windows 2.12.0
Azure Spatial Anchors SDK iOS 2.12.0
Azure Spatial Anchors SDK Android 2.12.0
Platform Support バージョン
Mixed Reality OpenXR Plugin 1.4.0

Unity Plugin & Asset

Unity Plugin バージョン
ARCore XR Plugin 4.1.9
ARKit XR Plugin 4.1.9
Windows XR Plugin 4.6.2
ARFoundation 4.1.7

導入してつまずいた点

  1. AndroidとiOSでは正常にAnchorへの移動が機能するのになぜか
    HoloLens2では機能しなかった。

  2. 先の問題を修正してマルチユーザー機能のチュートリアル通りに行ったが
    自分の開発環境ではなぜかホストのアンカー位置へ移動してくれなかった。

1. HoloLens2でなぜAnchorへの移動が機能しなかったか

マイクロソフト公式が出されている

このリポジトリのReleaseで配布しているAzure Spatial Anchors v2.7.2

これに入っているAnchorModuleScript.csCloudManager_AnchorLocated
に原因がありました。

AnchorModuleScript.cs
private void CloudManager_AnchorLocated(object sender, AnchorLocatedEventArgs args)
    {
        QueueOnUpdate(new Action(() => Debug.Log($"Anchor recognized as a possible Azure anchor")));

        if (args.Status == LocateAnchorStatus.Located || args.Status == LocateAnchorStatus.AlreadyTracked)
        {
            currentCloudAnchor = args.Anchor;

            QueueOnUpdate(() =>
            {
                Debug.Log($"Azure anchor located successfully");

                // Notify AnchorFeedbackScript
                OnASAAnchorLocated?.Invoke();

#if WINDOWS_UWP || UNITY_WSA
                // HoloLens: The position will be set based on the unityARUserAnchor thatwas located.
                // Create a local anchor at the location of the object in question
                gameObject.CreateNativeAnchor();

                // Notify AnchorFeedbackScript
                OnCreateLocalAnchor?.Invoke();

                // On HoloLens, if we do not have a cloudAnchor already, we will have already positioned the
                // object based on the passed in worldPos/worldRot and attached a new world anchor,
                // so we are ready to commit the anchor to the cloud if requested.
                // If we do have a cloudAnchor, we will use it's pointer to setup the world anchor,
                // which will position the object automatically.
                if (currentCloudAnchor != null)
                {
                    Debug.Log("Local anchor position successfully set to Azure anchor position");   

                    //gameObject.GetComponent<UnityEngine.XR.WSA.WorldAnchor>().SetNativeSpatialAnchorPtr(currentCloudAnchor.LocalAnchor);                 
                }

#elif UNITY_ANDROID || UNITY_IOS
                Pose anchorPose = Pose.identity;
                anchorPose = currentCloudAnchor.GetPose();

                Debug.Log($"Setting object to anchor pose with position '{anchorPose.position}' and rotation '{anchorPose.rotation}'");
                transform.position = anchorPose.position;
                transform.rotation = anchorPose.rotation;

                // Create a native anchor at the location of the object in question
                gameObject.CreateNativeAnchor();

                // Notify AnchorFeedbackScript
                OnCreateLocalAnchor?.Invoke();

#endif
            });
        }
        else
        {
            QueueOnUpdate(new Action(() => Debug.Log($"Attempt to locate Anchor with ID '{args.Identifier}' failed, locate anchor status was not 'Located' but '{args.Status}'")));
        }
    }

通常のAnchorModuleScriptはこうなっているが

実際はHoloLensの対象コードでアンカーへ移動する処理がごっそりなくなってる!?


プラットフォーム依存コンパイルの
UNITY_ANDROID || UNITY_IOS のプラットフォーム達に入っている内容が
WINDOWS_UWP || UNITY_WSA に一部コードが入っていないのが原因

下記のコードが抜けている部分です。

AnchorModuleScript.cs
                    Pose anchorPose = Pose.identity;
                    anchorPose = currentCloudAnchor.GetPose();

                    Debug.Log($"Setting object to anchor pose with position '{anchorPose.position}' and rotation '{anchorPose.rotation}'");
                    transform.position = anchorPose.position;
                    transform.rotation = anchorPose.rotation;

                    //removeAnchor = "Inactive";
                    //Create a native anchor at the location of the object in question
                    gameObject.CreateNativeAnchor();

                    //Notify AnchorFeedbackScript
                    OnCreateLocalAnchor?.Invoke();

下記のAnchorModuleScriptが今のをふまえて修正したコード
AnchorModuleScript.cs
private void CloudManager_AnchorLocated(object sender, AnchorLocatedEventArgs args)
    {
        QueueOnUpdate(new Action(() => Debug.Log($"Anchor recognized as a possible Azure anchor")));

        if (args.Status == LocateAnchorStatus.Located || args.Status == LocateAnchorStatus.AlreadyTracked)
        {
            currentCloudAnchor = args.Anchor;

            QueueOnUpdate(() =>
            {
                Debug.Log($"Azure anchor located successfully");

                // Notify AnchorFeedbackScript
                OnASAAnchorLocated?.Invoke();

#if WINDOWS_UWP || UNITY_WSA
                // HoloLens: The position will be set based on the unityARUserAnchor thatwas located.
                // Create a local anchor at the location of the object in question
                gameObject.CreateNativeAnchor();

                // Notify AnchorFeedbackScript
                OnCreateLocalAnchor?.Invoke();

                // On HoloLens, if we do not have a cloudAnchor already, we will have already positioned the
                // object based on the passed in worldPos/worldRot and attached a new world anchor,
                // so we are ready to commit the anchor to the cloud if requested.
                // If we do have a cloudAnchor, we will use it's pointer to setup the world anchor,
                // which will position the object automatically.
                if (currentCloudAnchor != null)
                {
                    Debug.Log("Local anchor position successfully set to Azure anchor position");

                    //gameObject.GetComponent<UnityEngine.XR.WSA.WorldAnchor>().SetNativeSpatialAnchorPtr(currentCloudAnchor.LocalAnchor);

/////////////  ここからOnCreateLocalAnchor?.Invoke();までの文がごっそりなくなっている!!!!  /////////////

                    Pose anchorPose = Pose.identity;
                    anchorPose = currentCloudAnchor.GetPose();

                    Debug.Log($"Setting object to anchor pose with position '{anchorPose.position}' and rotation '{anchorPose.rotation}'");
                    transform.position = anchorPose.position;
                    transform.rotation = anchorPose.rotation;

                    //removeAnchor = "Inactive";
                    //Create a native anchor at the location of the object in question
                    gameObject.CreateNativeAnchor();

                    //Notify AnchorFeedbackScript
                    OnCreateLocalAnchor?.Invoke();

/////////////////////////////////////////////////////////////////////////////////////////////////////

                }

#elif UNITY_ANDROID || UNITY_IOS
                Pose anchorPose = Pose.identity;
                anchorPose = currentCloudAnchor.GetPose();

                Debug.Log($"Setting object to anchor pose with position '{anchorPose.position}' and rotation '{anchorPose.rotation}'");
                transform.position = anchorPose.position;
                transform.rotation = anchorPose.rotation;

                // Create a native anchor at the location of the object in question
                gameObject.CreateNativeAnchor();

                // Notify AnchorFeedbackScript
                OnCreateLocalAnchor?.Invoke();

#endif
            });
        }
        else
        {
            QueueOnUpdate(new Action(() => Debug.Log($"Attempt to locate Anchor with ID '{args.Identifier}' failed, locate anchor status was not 'Located' but '{args.Status}'")));
        }
    }

これで一度HoloLensにデプロイすると
アンカーの場所に移動してることが確認できます。

この問題についてissueで触れられていました。

2.マルチユーザー機能でなぜホストのアンカー位置に移動してくれないか

自分の開発した環境ではなぜかアンカーの位置共有が行われませんでした。
先ほどの公式のサンプルMulti-User Capabilities v2.7.2
に専用Unityパッケージがあるのでこれをimportしてください。

詳しい実装方法は、マルチユーザー機能のチュートリアルの概要のドキュメントを確認してください。

自分は、その中でもHoloLens2同士とAndroidとでアンカーの共有ができなかった問題の修正方法について説明します。

1.の問題を解決した後に、上記のマルチユーザー機能のチュートリアルを一通り終わらせてください。
ドキュメントではTableAnchorと言うオブジェクトをHierarchyに追加したと思いますがその際に

  • AR Session
  • AR Session Origin
  • AR Anchor Maneger

この三つのコンポーネントをactiveにしてあると思います。
画像1-2.png

このコンポーネントたちを非activeにしてください。

そしてMixed Reality Toolkitに下記を追加してください。

  • AR Anchor Maneger
  • AR Session Origin
  • DisableDiagnosticsSystem → AndroidやiOSを使う場合だけ必要。

画像2.png

これでそれぞれのデバイスにデプロイすれば、
自分が作ったアンカーに他デバイスが、位置共有できていることを確認できます。

終わりに

これで誰でもHoloLens2同士や他デバイスと位置ずれを気にせずにコンテンツ作れます!!!!

参考になったサイト

今回、公式のドキュメントでうまくいかなかった方は下記の方々も同様に
Azure Spatial anchorsの使い方を記事にされているので
つまってしまった場合は彼らの記事を参考にすると良いと思います!!!

夜風のMixed Reality ホロ元さん

MRが楽しい ホロモンさん

Synamon’s Engineer blog Synamonさん

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0