Table of Contents

Доступ к компонентам AR-функций в session

В работающей session можно обращаться к различным функциональным компонентам через свойство Assembly. В этой статье описано, как обращаться к этим компонентам и на что нужно обращать внимание при доступе к ним.

Перед началом

Настройка AR-компонентов во время редактирования или перед запуском

Иногда некоторые параметры компонентов, например DesiredFocusMode, необходимо настроить до запуска компонента. Если вы не хотите вручную настраивать и запускать компоненты после запуска session, простой способ — настроить все потенциально используемые компоненты frame source перед сборкой session. Процесс сборки сохранит один или несколько из этих компонентов и применит их конфигурацию.

В это время можно использовать любые базовые методы Unity, такие как FindAnyObjectByType<T>() или GetComponent<T>(), чтобы найти компоненты и затем настроить их.

Примечание

Не определено, будут ли AR-компоненты, полученные таким способом, включены в session во время выполнения. Поэтому необходимо настроить все возможные варианты.

Например, следующий код показывает процесс изменения режима фокусировки для всех компонентов frame source перед сборкой session:

void Awake()
{
    var allFrameSources = Session.GetComponentsInChildren<FrameSource>();
    foreach (var source in allFrameSources)
    {
        if (source is CameraDeviceFrameSource)
        {
            ((CameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? CameraDeviceFocusMode.Continousauto : CameraDeviceFocusMode.Medium;
        }
        else if (source is MotionTrackerFrameSource)
        {
            ((MotionTrackerFrameSource)source).DesiredFocusMode = autoFocus ? MotionTrackerCameraDeviceFocusMode.Continousauto : MotionTrackerCameraDeviceFocusMode.Medium;
        }
        else if (source is ARCoreFrameSource)
        {
            ((ARCoreFrameSource)source).DesiredFocusMode = autoFocus ? ARCoreCameraDeviceFocusMode.Auto : ARCoreCameraDeviceFocusMode.Fixed;
        }
        else if (source is ARKitFrameSource)
        {
            ((ARKitFrameSource)source).DesiredFocusMode = autoFocus ? ARKitCameraDeviceFocusMode.Auto : ARKitCameraDeviceFocusMode.Fixed;
        }
        else if (source is AREngineFrameSource)
        {
            ((AREngineFrameSource)source).DesiredFocusMode = autoFocus ? AREngineCameraDeviceFocusMode.Auto : AREngineCameraDeviceFocusMode.Fixed;
        }
        else if (source is ThreeDofCameraDeviceFrameSource)
        {
            ((ThreeDofCameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? ThreeDofCameraDeviceFocusMode.Auto : ThreeDofCameraDeviceFocusMode.Fixed;
        }
        else if (source is InertialCameraDeviceFrameSource)
        {
            ((InertialCameraDeviceFrameSource)source).DesiredFocusMode = autoFocus ? InertialCameraDeviceFocusMode.Auto : InertialCameraDeviceFocusMode.Fixed;
        }
        else if (source is ARFoundationFrameSource)
        {
            cameraManager.autoFocusRequested = autoFocus;
        }
    }
}

Этот процесс также можно выполнить в редакторе; при этом также нужно настроить все компоненты:

alt text

Конфигурация двух frame source, ARCoreARFoundationFrameSource и ARKitARFoundationFrameSource, находится на компоненте Main Camera.

Предупреждение

AR-компоненты, полученные таким способом, можно использовать только для настройки перед запуском.
Поскольку процесс сборки отбирает AR-компоненты, AR-компоненты, полученные через дерево сцены, могут не быть включены в session и не смогут работать нормально.

Использование собранных AR-компонентов во время выполнения

AR-компоненты, работающие в session, определяются только после сборки. До завершения сборки никакие AR-компоненты использовать нельзя. Собранные AR-компоненты доступны через свойство Assembly.

Assembly можно использовать при условии, что состояние session >= Assembled. В частности, свойство Assembly получает значение только после завершения выполнения метода Assemble(); через него можно обращаться к компонентам session. После остановки или повреждения session свойство Assembly очищается, и доступ к компонентам становится невозможен.

В скрипте можно проверять State session, чтобы определить, можно ли в этот момент обращаться к AR-компонентам:

if (Session.State >= ARSession.SessionState.Ready)
{
    // Assembly доступна
}
else
{
    // Assembly недоступна
}

Также можно подписаться на событие StateChanged, чтобы получать изменения состояния session и обращаться к AR-компонентам в подходящий момент. В целом, чтобы успеть поймать состояние Ready, нужно подписаться на событие StateChanged до start session; обычно безопасно выполнить подписку в Awake():

void Awake()
{
    Session.StateChanged += (state) =>
    {
        if (Session.State == ARSession.SessionState.Ready)
        {
            // Assembly доступна; после этого Assembly остается доступной, пока session не остановится или не будет повреждена
        }
        else if (Session.State < ARSession.SessionState.Ready)
        {
            // Assembly недоступна; после этого Assembly остается недоступной, пока session не будет перезапущена
        }
        else
        {
            // Assembly доступна; обычно обработка не требуется
        }
    };
}
Осторожно

Если AR-компоненты, полученные через FindAnyObjectByType<T>() или GetComponent<T>() и другие методы, гарантированно будут включены в session, их также можно использовать во время выполнения.
Хранить ссылки на эти компоненты безопасно, но при использовании этих компонентов нужно убедиться, что session находится в рабочем состоянии и эти компоненты корректно включены в session; иначе могут возникнуть исключения или непредсказуемое поведение.
До запуска session и после ее остановки эти компоненты не работают. Даже при таком использовании рекомендуется следить за State session и событием StateChanged.

Доступ к компоненту frame source

К компоненту frame source можно обращаться через свойство ARAssembly.FrameSource. В нормально работающей session ARAssembly.FrameSource существует ровно один.

При использовании session обычно нужно обратиться к ARAssembly.FrameSource, чтобы определить фактический тип компонента frame source, используемый во время выполнения, и затем получить доступ к свойственным этому компоненту свойствам и методам.

Например, следующий код показывает, как использовать разные методы обнаружения плоскости в зависимости от frame source:

void PlaceObject(Vector2 touchPosition)
{
    if (Session.Assembly.FrameSource is MotionTrackerFrameSource)
    {
        Ray ray = Session.Assembly.Camera.ScreenPointToRay(touchPosition);
        if (Physics.Raycast(ray, out var hitInfo))
        {
            TouchRoot.transform.position = hitInfo.point;
        }
    }
    else if (Session.Assembly.FrameSource is ARFoundationFrameSource)
    {
        var raycastManager = Session.Assembly.Origin.Value.GetComponent<UnityEngine.XR.ARFoundation.ARRaycastManager>();
        var hits = new List<UnityEngine.XR.ARFoundation.ARRaycastHit>();
        if (raycastManager.Raycast(touchPosition, hits, UnityEngine.XR.ARSubsystems.TrackableType.PlaneWithinPolygon))
        {
            var hitPose = hits[0].pose;
            TouchRoot.transform.position = hitPose.position;
        }
    }
}

Доступ к компонентам frame filter

К компонентам frame filter можно обращаться через свойство ARAssembly.FrameFilters. В нормально работающей session в списке ARAssembly.FrameFilters компонентов любого типа может быть несколько.

Например, следующий код показывает, как получить один MegaTrackerFrameFilter из session и зарегистрировать соответствующее событие:

var megaTracker = session.Assembly.FrameFilters.Where(f => f is MegaTrackerFrameFilter).FirstOrDefault() as MegaTrackerFrameFilter;
if (megaTracker)
{
    megaTracker.LocalizationRespond += (response) =>
    {
    };
}

Доступ к компоненту camera

К компоненту camera можно обращаться через свойство ARAssembly.Camera. Если в сцене несколько camera, это быстрый способ найти камеру, используемую AR.

Например, следующий код показывает, как получить camera в session и выполнить raycast объектов в сцене:

var ray = Session.Assembly.Camera.ScreenPointToRay(screenPoint);
if (Physics.Raycast(ray, out var hitInfo))
{
    TouchRoot.transform.position = hitInfo.point;
};

Доступ к компоненту origin

К компоненту origin можно обращаться через свойство ARAssembly.Origin.

Например, следующий код показывает, как получить origin в session и отобразить в сцене усеченную пирамиду, представляющую текущее положение и ориентацию камеры:

if (session.Assembly.Origin.OnSome)
{
    GameObject frustum = Instantiate(CameraFrustumPrefab, session.Assembly.Camera.transform.position, session.Assembly.Camera.transform.rotation);
    frustum.transform.SetParent(session.Assembly.Origin.Value.transform);
}

Обратите внимание: здесь сначала нужно проверить, существует ли ARAssembly.Origin.

Примечание

ARAssembly.Origin существует только в session, где включена функция отслеживания движения.

Доступ к компоненту CameraImageRenderer

К компоненту CameraImageRenderer можно обращаться через свойство ARAssembly.CameraImageRenderer.

Например, следующий код получает RenderTexture изображения физической камеры:

RenderTexture renderTexture;

void Awake()
{
    Session.StateChanged += (state) =>
    {
        if (state == ARSession.SessionState.Ready && Session.Assembly.CameraImageRenderer.OnSome)
        {
            Session.Assembly.CameraImageRenderer.Value.RequestTargetTexture((_, texture) => renderTexture = texture);
        }
    };
}

Обратите внимание: здесь сначала нужно проверить, существует ли ARAssembly.CameraImageRenderer.

Примечание

ARAssembly.CameraImageRenderer действует только в session, где отрисовку изображения выполняет EasyAR. Как правило, при использовании AR Foundation или головных дисплеев он недействителен; в этом случае отрисовка изображения физической камеры выполняется AR Foundation или SDK головного дисплея.

Доступ к компоненту FrameRecorder

К компоненту FrameRecorder можно обращаться через свойство ARAssembly.FrameRecorder.

Например, следующий код запускает запись; место сохранения файла зависит от конфигурации, по умолчанию он сохраняется во внутреннем каталоге хранения приложения:

if (session.Assembly.FrameRecorder.OnSome)
{
    var frameRecorder = session.Assembly.FrameRecorder.Value;
    frameRecorder.enabled = true;
}

Обратите внимание: здесь сначала нужно проверить, существует ли ARAssembly.FrameRecorder.

Примечание

ARAssembly.FrameRecorder в некоторых случаях, например при использовании FramePlayer, недоступен.

Дальнейшие шаги

  • Узнайте, как получать результаты работы session; эти результаты содержат выходные данные AR-компонентов
  • Кроме того, вы можете изучить доступ к компонентам по следующим примерам:
    • Пример Workflow_ARSession показывает способы доступа к различным компонентам и их использования

Связанные темы