Table of Contents

Доступ к ar-компонентам в сеансе

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

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

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

Некоторые параметры компонентов (например DesiredFocusMode) необходимо настраивать до запуска компонента. Если вы не хотите вручную настраивать и запускать компонент после старта сессии, можно заранее настроить все возможные источники кадров перед сборкой сессии. Процесс сборки сохранит один или несколько этих компонентов и применит их конфигурацию.

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

Примечание

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

Например, этот код изменяет режим фокусировки всех источников кадров перед сборкой сессии:

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

Для источников кадров ARCoreARFoundationFrameSource и ARKitARFoundationFrameSource настройки находятся в компонентах Main Camera.

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

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

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

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

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

В скриптах можно проверять State сессии, чтобы определить, доступны ли AR компоненты в данный момент:

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

Также можно подписаться на событие StateChanged, чтобы отслеживать изменения состояния сессии и обращаться к AR компонентам в подходящий момент. Обычно, чтобы гарантированно перехватить состояние Ready, подписку на событие StateChanged нужно выполнить до старта сессии. Безопасно сделать это, например, в методе Awake():

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

Если получить AR компоненты через методы типа FindAnyObjectByType<T>() или GetComponent<T>(), они гарантированно будут включены в сессию и могут использоваться во время выполнения.
Сохранять ссылки на эти компоненты безопасно, но при их использовании необходимо гарантировать, что сессия активна и эти компоненты корректно включены в сессию. В противном случае возможно возникновение исключений или непредсказуемого поведения.
Эти компоненты не работают до старта и после остановки сессии. Рекомендуется даже при таком подходе отслеживать State сессии и событие StateChanged.

Доступ к компоненту источника кадров

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

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

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

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

Доступ к компонентам фильтра кадров можно получить через свойство ARAssembly.FrameFilters. В работающем сеансе, в списке ARAssembly.FrameFilters может присутствовать несколько компонентов любого типа.

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

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

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

Для доступа к компоненту camera можно использовать свойство ARAssembly.Camera. Это быстрый способ найти камеру, используемую в AR, если в сцене присутствуют несколько камер.

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

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

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

Компонент origin можно получить через свойство ARAssembly.Origin.

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

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 существует только в сессиях с включенной функцией отслеживания движений.

Доступ к компоненту 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 действителен только в сессиях, где отрисовка выполняется 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.

Следующие шаги

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

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