Table of Contents

Получение результатов работы сессии

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

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

Получение обновлений InputFrame

Для получения обновлений InputFrame можно использовать событие InputFrameUpdate. Это событие срабатывает только при изменении InputFrame в выходных данных сессии для каждого кадра.

Примечание

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

С помощью InputFrame можно получить изображение с физической камеры, параметры камеры, метку времени, преобразование физической камеры относительно мировой системы координат и состояние отслеживания. Однако, поскольку преобразование камеры уже применено сессией к виртуальной камере и другим объектам, обычно нет необходимости получать преобразование камеры через InputFrame.

Получение изображения с физической камеры для текущего кадра

Для получения данных изображения с физической камеры типа Image можно использовать метод InputFrame.image().

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

Session.InputFrameUpdate += (inputFrame) => {
    using (var image = inputFrame.image())
    {
    }
};
Осторожно

При использовании данных типа Image и других данных типа class, полученных из него, необходимо гарантировать корректный вызов Dispose() (в приведенном выше коде это обеспечивается оператором using). В противном случае могут возникнуть утечки памяти или даже остановка обновления изображения.

Если требуется сохранить InputFrame или Image для использования в следующем кадре, необходимо увеличить значение ARAssembly.ExtraBufferCapacity в соответствии с объемом сохраняемых данных. Иначе может произойти сбой получения данных из-за недостаточного размера буфера.

Если требуется сохранить InputFrame, необходимо также вызвать метод Clone() для создания копии ссылки, а затем вызвать Dispose() для копии, когда она больше не нужна.

Поскольку частота кадров физической камеры обычно ниже частоты рендеринга, событие InputFrameUpdate срабатывает не для каждого кадра рендеринга. Однако, аналогично, изображение с физической камеры также обновляется не в каждом кадре рендеринга. Содержимое изображения для всех кадров рендеринга до следующего срабатывания события InputFrameUpdate будет соответствовать изображению текущего InputFrame.

Примечание

Изображение в InputFrame всегда соответствует фону текущего кадра виртуальной камеры. Однако при рендеринге фона изображение может масштабироваться и обрезаться, поэтому несоответствие размера или пропорций получаемого изображения отображаемому на экране является нормальным.

Кроме того, важно отметить, что данные изображения, возвращаемые InputFrame.image(), доступны для чтения CPU и не являются GPU-текстурой. Если требуется использовать данные изображения на GPU, необходимо загрузить их в GPU-текстуру или получить GPU-текстуру напрямую через интерфейс CameraImageRenderer.RequestTargetTexture(Action<Camera, RenderTexture>).

[Опционально] Перехват рендеринга изображения с физической камеры

Для управления отрисовкой изображения с физической камеры можно использовать ARAssembly.CameraImageRenderer.

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

if (Session.Assembly != null && Session.Assembly.CameraImageRenderer.OnSome)
{
    Session.Assembly.CameraImageRenderer.Value.enabled = false;
}

Важно: перед этим необходимо проверить существование ARAssembly.CameraImageRenderer.

Примечание

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

После остановки отрисовки изображения с физической камеры приложение может получить данные изображения через InputFrame и использовать их для пользовательской отрисовки.

Получение обновлений transform

Через событие PostSessionUpdate можно получить данные transform объектов в сцене после каждого обновления сессии.

Примечание

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

Получение transform виртуальной камеры

Transform камеры в сцене можно получить через ARAssembly.Camera.

Session.PostSessionUpdate += () =>
{
    var position = Session.Assembly.Camera.transform.position;
    var rotation = Session.Assembly.Camera.transform.rotation;
};

Получение transform target

Transform target в сцене можно получить через используемый конкретный объект target. Например, для отслеживания изображений этим target является объект, на котором находится компонент ImageTargetController.

Session.PostSessionUpdate += () =>
{
    var position = target.transform.position;
    var rotation = target.transform.rotation;
};

[Опционально] Получение pose

Pose — это структура данных, описывающая положение и ориентацию объекта, обычно состоящая из position и rotation. В AR-приложениях pose обычно описывает положение и ориентацию физической камеры или отслеживаемой цели относительно некоторой системы отсчета.

Unity не предоставляет необработанные данные pose, поскольку pose обычно используется для управления движением объектов в сцене, и эту работу автоматически выполняет сессия. Для вычислений содержимого и рендеринга достаточно transform.

Важно

Прежде чем читать следующие методы, подумайте еще раз: удовлетворяют ли вашим потребностям данные transform камеры, отслеживаемых целей и других объектов в сцене? Как правило, дополнительные данные pose не требуются.

Если по какой-то причине все же необходимы данные pose, их можно вычислить на основе transform в событии PostSessionUpdate. Обычно относительный transform между target и camera, полученный в PostSessionUpdate, и есть pose.

Следующий код демонстрирует, как получить transform камеры и цели, и вычислить относительный pose между ними:

Session.PostSessionUpdate += () =>
{
    Pose cameraToWorld = new(Session.Assembly.Camera.transform.position, Session.Assembly.Camera.transform.rotation);
    Pose targetToWorld = new(target.transform.position, target.transform.rotation);
    Pose worldToTarget = new()
    {
        position = Quaternion.Inverse(targetToWorld.rotation) * (-targetToWorld.position),
        rotation = Quaternion.Inverse(targetToWorld.rotation)
    };
    Pose cameraToTarget = cameraToWorld.GetTransformedBy(worldToTarget);
};
Осторожно

Если вы одновременно используете AR Foundation, гарнитуру или другие работающие сторонние библиотеки, они также могут изменять transform камеры в сцене. Убедитесь, что логика обновления этих библиотек завершена, прежде чем выполнять расчеты pose, иначе результаты могут быть некорректными. В таких сценариях относительный pose между target и origin в PostSessionUpdate остается точным.

[Опционально] Перехват обновлений transform

Во время работы AR-функций transform объектов в Unity, таких как камера и отслеживаемые цели, обычно обновляется сессией автоматически. Эти процессы обновления гарантируют правильность и согласованность AR-рендеринга, поэтому нет способа перехватить эти обновления.

Однако, если требуется пользовательская логика обновления transform объектов, это можно реализовать, прослушивая событие PostSessionUpdate. Для этого требуется более сложный подход:

  1. Хотя обычно содержимое рендеринга следует размещать как дочерние узлы или дополнительные компоненты под объектами, управляемыми сессией, для пользовательского обновления transform эти объекты необходимо вынести из иерархии управляемых сессией объектов. То есть, эти объекты не должны быть дочерними по отношению к объектам, управляемым сессией.
  2. В событии PostSessionUpdate записывайте transform объектов, которые требуется обновлять пользовательским способом.
  3. Наконец, в событии PostSessionUpdate обновляйте transform этих объектов, используя пользовательскую логику на основе данных, предоставленных сессией.
Примечание

Использование события PostSessionUpdate обязательно, поскольку только после этого момента сессия больше не будет управлять объектами в сцене.

Важно: этот метод неприменим для изменения камеры; для обработки пользовательского обновления камеры требуется более сложная логика.

Кроме того, этот метод можно использовать только для пользовательского обновления transform объектов, но не для изменения transform объектов, управляемых сессией. Если transform управляемых сессией объектов изменяется извне, сессия все равно перезапишет эти изменения при следующем обновлении, что может повлиять на корректность некоторых вычислений.

Осторожно

При использовании этого метода вы должны гарантировать корректность transform объектов, иначе это может привести к ошибкам AR-рендеринга.

Если вы одновременно используете AR Foundation, гарнитуру или другие сторонние библиотеки, они также могут изменять transform объектов в сцене. Убедитесь, что логика обновления этих библиотек не конфликтует с пользовательской логикой, иначе могут возникнуть непредвиденные результаты.

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