Unity에서 Azure Spatial Anchors를 사용하여 앵커를 만들고 찾는 방법

Azure Spatial Anchors를 사용하면 다양한 디바이스 간에 전 세계 앵커를 공유할 수 있습니다. 여러 가지 다양한 개발 환경을 지원합니다. 이 문서에서는 다음을 수행하기 위해 Unity에서 Azure Spatial Anchors SDK를 사용하는 방법을 자세히 알아보겠습니다.

  • Azure Spatial Anchors 세션을 올바르게 설정하고 관리합니다.
  • 로컬 앵커에 속성을 만들고 설정합니다.
  • 클라우드에 업로드합니다.
  • 클라우드 공간 앵커를 찾아 삭제합니다.

필수 구성 요소

이 가이드를 완료하려면 다음이 필요합니다.

  • Azure Spatial Anchors 개요를 자세히 읽었습니다.
  • 5분 빠른 시작 중 하나를 완료했습니다.
  • C# 및 Unity에 대한 기본 지식이 있습니다.
  • Android를 사용하려는 경우 ARCore, iOS를 사용하려는 경우 ARKit에 대한 기본 지식이 있습니다.

플랫폼 간

세션 초기화

SDK의 기본 진입점은 세션을 나타내는 클래스입니다. 일반적으로 뷰 및 네이티브 AR 세션을 관리 하는 클래스에서 필드를 선언 합니다.

CloudSpatialAnchorSession 클래스에 대해 자세히 알아봅니다.

    CloudSpatialAnchorSession cloudSession;
    // In your view handler
    this.cloudSession = new CloudSpatialAnchorSession();

인증 설정

서비스에 액세스하려면 계정 키, 액세스 토큰 또는 Azure Active Directory 인증 토큰을 제공해야 합니다. 인증 개념 페이지에서 이에 대한 자세한 내용을 읽을 수도 있습니다.

계정 키

계정 키는 애플리케이션에서 Azure Spatial Anchors 서비스를 사용하여 인증할 수 있도록 하는 자격 증명입니다. 계정 키의 용도는 빨리 시작할 수 있도록 지원합니다. 특히 애플리케이션이 Azure Spatial Anchors와 통합하는 단계에서 더 필요합니다. 따라서 개발 중에 클라이언트 애플리케이션에 계정 키를 포함하여 계정 키를 사용할 수 있습니다. 개발을 넘어 진행할 때는 액세스 토큰에서 지원하는 프로덕션 수준의 인증 메커니즘이나 Azure Active Directory 사용자 인증으로 이동하는 것이 좋습니다. 개발을 위한 계정 키를 가져오려면 Azure Spatial Anchors 계정을 방문하여 "키" 탭으로 이동합니다.

SessionConfiguration 클래스에 대해 자세히 알아봅니다.

    this.cloudSession.Configuration.AccountKey = @"MyAccountKey";

액세스 토큰

액세스 토큰은 Azure 공간 앵커를 사용 하 여 인증 하는 더욱 강력한 방법입니다. 특히 프로덕션 배포를 위해 응용 프로그램을 준비 하는 경우입니다. 이 방법의 요약은 클라이언트 응용 프로그램에서 안전 하 게 인증할 수 있는 백 엔드 서비스를 설정 하는 것입니다. 백 엔드 서비스는 런타임에 AAD와 Azure 공간 앵커 보안 토큰 서비스를 사용 하 여 액세스 토큰을 요청 합니다. 이 토큰은 클라이언트 응용 프로그램에 전달 되 고 SDK에서 Azure 공간 앵커를 사용 하 여 인증 하는 데 사용 됩니다.

    this.cloudSession.Configuration.AccessToken = @"MyAccessToken";

액세스 토큰이 설정 되지 않은 경우 이벤트를 처리 TokenRequired 하거나 tokenRequired 대리자 프로토콜에서 메서드를 구현 해야 합니다.

이벤트 인수에 대해 속성을 설정 하 여 이벤트를 동기적으로 처리할 수 있습니다.

TokenRequiredDelegate 위임에 대해 자세히 알아봅니다.

    this.cloudSession.TokenRequired += (object sender, TokenRequiredEventArgs args) =>
    {
        args.AccessToken = @"MyAccessToken";
    };

처리기에서 비동기 작업을 실행 해야 하는 경우 deferral 다음 예제와 같이 개체를 요청 하 고 완료 하 여 토큰 설정을 연기할 수 있습니다.

    this.cloudSession.TokenRequired += async (object sender, TokenRequiredEventArgs args) =>
    {
        var deferral = args.GetDeferral();
        string myToken = await MyGetTokenAsync();
        if (myToken != null) args.AccessToken = myToken;
        deferral.Complete();
    };

Azure Active Directory 인증

또한 azure 공간 앵커를 사용 하면 응용 프로그램에서 사용자 Azure AD (Active Directory) 토큰을 사용 하 여 인증할 수 있습니다. 예를 들어 azure AD 토큰을 사용 하 여 Azure 공간 앵커와 통합할 수 있습니다. Enterprise azure ad에서 사용자를 유지 관리 하는 경우 azure 공간 앵커 SDK에서 사용자 azure ad 토큰을 제공할 수 있습니다. 이렇게 하면 동일한 Azure AD 테 넌 트의 일부인 계정에 대해 Azure 공간 앵커 서비스에 직접 인증할 수 있습니다.

    this.cloudSession.Configuration.AuthenticationToken = @"MyAuthenticationToken";

액세스 토큰과 마찬가지로, Azure AD 토큰이 설정 되지 않은 경우 TokenRequired 이벤트를 처리 하거나 위임 프로토콜에서 tokenRequired 메서드를 구현 해야 합니다.

이벤트 인수에 대해 속성을 설정 하 여 이벤트를 동기적으로 처리할 수 있습니다.

    this.cloudSession.TokenRequired += (object sender, TokenRequiredEventArgs args) =>
    {
        args.AuthenticationToken = @"MyAuthenticationToken";
    };

처리기에서 비동기 작업을 실행 해야 하는 경우 deferral 다음 예제와 같이 개체를 요청 하 고 완료 하 여 토큰 설정을 연기할 수 있습니다.

    this.cloudSession.TokenRequired += async (object sender, TokenRequiredEventArgs args) =>
    {
        var deferral = args.GetDeferral();
        string myToken = await MyGetTokenAsync();
        if (myToken != null) args.AuthenticationToken = myToken;
        deferral.Complete();
    };

세션 설정

세션에서 환경 데이터를 처리할 수 있도록 하려면 Start()를 호출합니다.

세션에서 발생 한 이벤트를 처리 하려면 이벤트 처리기를 연결 합니다.

Start 메서드에 대해 자세히 알아봅니다.

#if UNITY_ANDROID || UNITY_IOS
    this.cloudSession.Session = aRSession.subsystem.nativePtr.GetPlatformPointer();
#elif UNITY_WSA || WINDOWS_UWP
    // No need to set a native session pointer for HoloLens.
#else
    throw new NotSupportedException("The platform is not supported.");
#endif

    this.cloudSession.Start();

세션에 프레임 제공

공간 앵커 세션은 사용자 주위의 공간을 매핑하여 작동합니다. 이렇게 하면 앵커가 배치된 위치를 확인하는 데 도움이 됩니다. 모바일 플랫폼 (iOS & Android)은 플랫폼의 AR 라이브러리에서 프레임을 가져오기 위해 카메라 피드에 대 한 네이티브 호출이 필요 합니다. 반면, HoloLens는 지속적으로 환경을 검색하므로 모바일 플랫폼에서와 같은 특정 호출이 필요하지 않습니다.

Processframe 메서드에 대해 자세히 알아보세요.

#if UNITY_ANDROID || UNITY_IOS
    XRCameraFrame xRCameraFrame;
    if (aRCameraManager.subsystem.TryGetLatestFrame(cameraParams, out xRCameraFrame))
    {
        long latestFrameTimeStamp = xRCameraFrame.timestampNs;

        bool newFrameToProcess = latestFrameTimeStamp > lastFrameProcessedTimeStamp;

        if (newFrameToProcess)
        {
            session.ProcessFrame(xRCameraFrame.nativePtr.GetPlatformPointer());
            lastFrameProcessedTimeStamp = latestFrameTimeStamp;
        }
    }
#endif

사용자에게 피드백 제공

세션 업데이트 이벤트를 처리하는 코드를 작성할 수 있습니다. 이 이벤트는 세션에서 사용자 환경에 대한 이해가 향상될 때마다 발생합니다. 이렇게 하면 다음과 같은 작업을 수행할 수 있습니다.

  • 디바이스가 이동하고 세션에서 해당 환경의 이해를 업데이트할 때 UserFeedback 클래스를 사용하여 사용자에게 피드백을 제공합니다. 이 작업을 수행하려면
  • 공간 앵커를 만들기에 충분한 추적 공간 데이터가 있는 지점을 확인합니다. ReadyForCreateProgress 또는 RecommendedForCreateProgress를 사용하여 이를 확인합니다. ReadyForCreateProgress가 1을 초과하면 클라우드 공간 앵커를 저장하기에 충분한 데이터가 있지만 이 작업을 수행하려면 RecommendedForCreateProgress가 1을 초과할 때까지 대기하는 것이 좋습니다.

SessionUpdatedDelegate 위임에 대해 자세히 알아봅니다.

    this.cloudSession.SessionUpdated += (object sender, SessionUpdatedEventArgs args) =>
    {
        var status = args.Status;
        if (status.UserFeedback == SessionUserFeedback.None) return;
        this.feedback = $"Feedback: {Enum.GetName(typeof(SessionUserFeedback), status.UserFeedback)} -" +
            $" Recommend Create={status.RecommendedForCreateProgress: 0.#%}";
    };

클라우드 공간 앵커 만들기

클라우드 공간 앵커를 만들려면 먼저 플랫폼의 AR 시스템에서 앵커를 만든 다음, 해당하는 클라우드를 만듭니다. CreateAnchorAsync() 메서드를 사용합니다.

CloudSpatialAnchor 클래스에 대해 자세히 알아봅니다.

    // Create a local anchor, perhaps by hit-testing and spawning an object within the scene
    Vector3 hitPosition = new Vector3();
#if UNITY_ANDROID || UNITY_IOS
    Vector2 screenCenter = new Vector2(0.5f, 0.5f);
    List<ARRaycastHit> aRRaycastHits = new List<ARRaycastHit>();
    if(arRaycastManager.Raycast(screenCenter, aRRaycastHits) && aRRaycastHits.Count > 0)
    {
        ARRaycastHit hit = aRRaycastHits[0];
        hitPosition = hit.pose.position;
    }
#elif WINDOWS_UWP || UNITY_WSA
    RaycastHit hit;
    if (this.TryGazeHitTest(out hit))
    {
        hitPosition = hit.point;
    }
#endif

    Quaternion rotation = Quaternion.AngleAxis(0, Vector3.up);
    this.localAnchor = GameObject.Instantiate(/* some prefab */, hitPosition, rotation);
    this.localAnchor.AddComponent<CloudNativeAnchor>();

    // If the user is placing some application content in their environment,
    // you might show content at this anchor for a while, then save when
    // the user confirms placement.
    CloudNativeAnchor cloudNativeAnchor = this.localAnchor.GetComponent<CloudNativeAnchor>();
    if (cloudNativeAnchor.CloudAnchor == null) { await cloudNativeAnchor.NativeToCloud(); }  
    CloudSpatialAnchor cloudAnchor = cloudNativeAnchor.CloudAnchor;
    await this.cloudSession.CreateAnchorAsync(cloudAnchor);
    this.feedback = $"Created a cloud anchor with ID={cloudAnchor.Identifier}");

앞에서 설명한 것처럼 새 클라우드 공간 앵커를 만들기 전에 캡처된 충분한 환경 데이터가 필요합니다. 즉, ReadyForCreateProgress가 1보다 커야 하지만 RecommendedForCreateProgress가 1보다 커질 때까지 기다리는 것이 좋습니다.

GetSessionStatusAsync 메서드에 대해 자세히 알아봅니다.

    SessionStatus value = await this.cloudSession.GetSessionStatusAsync();
    if (value.RecommendedForCreateProgress < 1.0f) return;
    // Issue the creation request ...

속성 설정

클라우드 공간 앵커를 저장할 때 몇 가지 속성을 추가하도록 선택할 수 있습니다. 저장되는 개체의 형식이나 상호 작용에 대해 활성화해야 하는지 여부와 같은 기본 속성입니다. 이렇게 하면 검색 시 유용할 수 있습니다. 예를 들어 빈 콘텐츠가 있는 그림 프레임과 같이 사용자에 대한 개체를 즉시 렌더링할 수 있습니다. 그런 다음, 백그라운드에서 다른 다운로드를 하면 추가 상태 세부 정보(예: 프레임에 표시할 그림)가 표시됩니다.

AppProperties 속성에 대해 자세히 알아봅니다.

    CloudSpatialAnchor cloudAnchor = new CloudSpatialAnchor() { LocalAnchor = localAnchor };
    cloudAnchor.AppProperties[@"model-type"] = @"frame";
    cloudAnchor.AppProperties[@"label"] = @"my latest picture";
    await this.cloudSession.CreateAnchorAsync(cloudAnchor);

속성 업데이트

앵커에 대 한 속성을 업데이트 하려면 메서드를 사용 UpdateAnchorProperties() 합니다. 두 개 이상의 장치가 동일한 앵커에 대 한 속성을 동시에 업데이트 하려고 하면 낙관적 동시성 모델을 사용 합니다. 즉, 첫 번째 쓰기가 성공 하 게 됩니다. 다른 모든 쓰기에는 "동시성" 오류가 발생 합니다. 다시 시도 하기 전에 속성의 새로 고침이 필요 합니다.

UpdateAnchorPropertiesAsync 메서드에 대해 자세히 알아봅니다.

    CloudSpatialAnchor anchor = /* locate your anchor */;
    anchor.AppProperties[@"last-user-access"] = @"just now";
    await this.cloudSession.UpdateAnchorPropertiesAsync(anchor);

서비스에서 앵커를 만든 후에는 앵커 위치를 업데이트할 수 없습니다. 새 앵커를 만들고 이전 앵커를 삭제 하 여 새 위치를 추적 해야 합니다.

속성을 업데이트 하기 위해 앵커를 찾지 않아도 되는 경우 메서드를 사용할 수 있습니다 GetAnchorPropertiesAsync() .이 메서드는 CloudSpatialAnchor 속성을 가진 개체를 반환 합니다.

GetAnchorPropertiesAsync 메서드에 대해 자세히 알아봅니다.

    var anchor = await cloudSession.GetAnchorPropertiesAsync(@"anchorId");
    if (anchor != null)
    {
        anchor.AppProperties[@"last-user-access"] = @"just now";
        await this.cloudSession.UpdateAnchorPropertiesAsync(anchor);
    }

Set expiration

나중에 지정된 날짜에 자동으로 만료되도록 앵커를 구성할 수도 있습니다. 앵커가 만료되면 더 이상 찾거나 업데이트되지 않습니다. 만료는 클라우드에 저장하기 전에 앵커가 만들어질 때만 설정할 수 있습니다. 이후에는 만료를 업데이트할 수 없습니다. 앵커를 만드는 동안 만료가 설정되지 않은 경우 앵커는 수동으로 삭제할 때만 만료됩니다.

만료 속성에 대해 자세히 알아보세요.

    cloudAnchor.Expiration = DateTimeOffset.Now.AddDays(7);

클라우드 공간 앵커 찾기

이전에 저장된 클라우드 공간 앵커를 찾는 것은 Azure 공간 앵커를 사용하는 주요 이유 중 하나입니다. 여러 가지 방법으로 클라우드 공간 앵커를 찾을 수 있습니다. 감시자에서 한 번에 한 가지 전략을 사용할 수 있습니다.

  • 식별자로 앵커를 찾습니다.
  • 이전에 찾은 앵커에 연결된 앵커를 찾습니다. 여기에서 앵커 관계에 대해 알아볼 수 있습니다.
  • 광역 위치 재결정을 사용하여 앵커를 찾습니다.

참고

앵커를 찾을 때마다 Azure Spatial Anchors는 수집된 환경 데이터를 사용하여 앵커에 대한 시각적 정보를 보강하려고 합니다. 앵커를 찾는 데 문제가 있는 경우 앵커를 만든 다음, 서로 다른 각도와 조명 조건에서 여러 번 배치하는 것이 유용할 수 있습니다.

식별자로 클라우드 공간 앵커를 찾는 경우 클라우드 공간 앵커 식별자를 애플리케이션의 백 엔드 서비스에 저장하고 적절하게 인증할 수 있는 모든 디바이스에서 액세스할 수 있도록 합니다. 이에 대한 예제는 자습서: 여러 디바이스 간에 Spatial Anchors 공유를 참조하세요.

AnchorLocateCriteria 개체를 인스턴스화하고, 찾고자 하는 식별자를 설정하고, AnchorLocateCriteria를 제공하여 세션에서 CreateWatcher 메서드를 호출합니다.

CreateWatcher 메서드에 대해 자세히 알아봅니다.

    AnchorLocateCriteria criteria = new AnchorLocateCriteria();
    criteria.Identifiers = new string[] { @"id1", @"id2", @"id3" };
    this.cloudSession.CreateWatcher(criteria);

감시자를 만든 후에는 요청된 모든 앵커에 대해 AnchorLocated 이벤트가 발생합니다. 이 이벤트는 앵커가 있는 경우 또는 앵커를 찾을 수 없는 경우에 발생합니다. 이러한 상황이 발생하는 경우 이유가 상태에 명시됩니다. 감시자의 모든 앵커를 처리하거나, 찾거나, 찾지 못하게 되면 LocateAnchorsCompleted 이벤트가 발생합니다. 감시자당 식별자는 35개로 제한됩니다.

AnchorLocatedDelegate 위임에 대해 자세히 알아봅니다.

    this.cloudSession.AnchorLocated += (object sender, AnchorLocatedEventArgs args) =>
    {
        switch (args.Status)
        {
            case LocateAnchorStatus.Located:
                CloudSpatialAnchor foundAnchor = args.Anchor;
                // Go add your anchor to the scene...
                break;
            case LocateAnchorStatus.AlreadyTracked:
                // This anchor has already been reported and is being tracked
                break;
            case LocateAnchorStatus.NotLocatedAnchorDoesNotExist:
                // The anchor was deleted or never existed in the first place
                // Drop it, or show UI to ask user to anchor the content anew
                break;
            case LocateAnchorStatus.NotLocated:
                // The anchor hasn't been found given the location data
                // The user might in the wrong location, or maybe more data will help
                // Show UI to tell user to keep looking around
                break;
        }
    }

앵커 삭제

클라우드 공간 앵커를 삭제하려면 DeleteAnchor() 메서드를 사용합니다. 더 이상 사용하지 않을 때 앵커를 삭제하는 것은 Azure 리소스를 정리하기 위해 개발 프로세스와 관행 초기에 포함하는 것이 좋습니다.

DeleteAnchorAsync 메서드에 대해 자세히 알아봅니다.

    await this.cloudSession.DeleteAnchorAsync(cloudAnchor);
    // Perform any processing you may want when delete finishes

세션 일시 중지, 재설정 또는 중지

세션을 일시적으로 중지하려면 Stop()을 호출하면 됩니다. 이렇게 하면 ProcessFrame()을 호출하는 경우에도 감시자 및 환경 처리가 중지됩니다. 그런 다음, Start()를 호출하여 처리를 다시 시작할 수 있습니다. 다시 시작하는 경우 세션에서 이미 캡처된 환경 데이터가 유지 관리됩니다.

Stop 메서드에 대해 자세히 알아봅니다.

    this.cloudSession.Stop();

세션에서 캡처된 환경 데이터를 다시 설정 하기 위해를 호출할 수 있습니다 Reset() .

Reset 메서드에 대해 자세히 알아보세요.

    this.cloudSession.Reset();

세션 후 제대로 정리 하려면를 호출 Dispose() 합니다.

Dispose 메서드에 대해 자세히 알아봅니다.

    this.cloudSession.Dispose();

다음 단계

이 가이드에서는 Azure 공간 앵커 SDK를 사용 하 여 앵커를 만들고 찾는 방법을 배웠습니다. 앵커 관계에 대 한 자세한 내용을 보려면 다음 가이드를 계속 진행 합니다.