Получение результата выполнения session
Во время выполнения session изменяются transform некоторых объектов сцены и изображение камеры. Иногда этих изменений недостаточно для приложения, и может понадобиться получать результат выполнения session на каждом frame и дополнительно обрабатывать эти данные. В этой статье объясняется, как получать и использовать такие данные.
Перед началом
- Изучите базовые понятия, состав и рабочий процесс session в Введении в ARSession
- Узнайте, как создать session
- Узнайте, как получать доступ к компонентам AR-функций
Получение обновлений InputFrame
Можно использовать событие InputFrameUpdate для получения обновлений InputFrame. Это событие срабатывает только тогда, когда InputFrame изменяется в выходных данных session на каждом frame.
Примечание
InputFrameUpdate действует только в session, где изображение отрисовывается EasyAR. Обычно оно не работает при использовании AR Foundation или гарнитур, и тогда нужно использовать методы, предоставляемые этими сторонними библиотеками, чтобы получать обновления данных.
С помощью InputFrame можно получить изображение физической камеры, параметры камеры, timestamp, transform физической камеры относительно мировой системы координат, состояние tracking и т. д. Однако, поскольку transform камеры уже применяется session к виртуальной камере и другим объектам, обычно получать transform камеры через InputFrame не требуется.
Получение изображения физической камеры текущего frame
Можно использовать метод InputFrame.image(), чтобы получить данные изображения физической камеры типа Image.
Например, следующий код получает изображение физической камеры при обновлении InputFrame:
Session.InputFrameUpdate += (inputFrame) => {
using (var image = inputFrame.image())
{
}
};
Осторожно
При использовании данных типа Image и других данных типа class, полученных из них, необходимо убедиться, что Dispose() вызывается правильно (инструкция using в коде выше это гарантирует); иначе возможны утечки памяти и даже остановка обновления изображения.
Если нужно сохранить InputFrame или Image для использования на следующем frame, необходимо увеличить значение ARAssembly.ExtraBufferCapacity в соответствии с объёмом сохраняемых данных; иначе получение данных может завершиться неудачей из-за нехватки буфера.
Если нужно сохранить InputFrame, также необходимо вызвать Clone(), чтобы создать копию-ссылку, а затем вызвать Dispose() для этой копии, когда она больше не нужна.
Поскольку частота кадров физической камеры обычно ниже частоты рендеринга, событие InputFrameUpdate получают не все frame рендеринга, но и изображение физической камеры также не обновляется на каждом frame рендеринга. Все frame рендеринга до следующего срабатывания InputFrameUpdate имеют тот же контент изображения, что и текущий InputFrame.
Примечание
Изображение в InputFrame всегда совпадает с фоновым изображением виртуальной камеры текущего frame, но при рендеринге фона возможны масштабирование и обрезка, поэтому нормально, если полученный размер или пропорции изображения не совпадают с тем, что отображается на экране.
Также следует учитывать, что данные изображения, возвращаемые InputFrame.image(), доступны для чтения CPU, но это не GPU texture. Если нужно использовать данные изображения на GPU, их необходимо загрузить в GPU texture, либо получить GPU texture напрямую через интерфейс CameraImageRenderer.RequestTargetTexture(Action<Camera, RenderTexture>).
[Опционально] Перехват рендеринга изображения физической камеры
Можно использовать ARAssembly.CameraImageRenderer для управления отрисовкой изображения физической камеры.
Следующий код может остановить отрисовку изображения физической камеры:
if (Session.Assembly != null && Session.Assembly.CameraImageRenderer.OnSome)
{
Session.Assembly.CameraImageRenderer.Value.enabled = false;
}
Обратите внимание, что сначала нужно проверить, существует ли ARAssembly.CameraImageRenderer.
Примечание
Остановить обновление изображения этим способом можно только в session, где изображение отрисовывает EasyAR. Обычно он не работает при использовании AR Foundation или гарнитур, и тогда нужно использовать методы, предоставляемые этими сторонними библиотеками, чтобы реализовать соответствующую функцию.
После остановки рендеринга изображения физической камеры приложение может получать данные изображения физической камеры через InputFrame и использовать их для собственного рендеринга.
Получение обновлений transform
Можно получать данные transform объектов сцены после каждого обновления session через событие PostSessionUpdate.
Примечание
Для некоторых функций, например Mega, даже если изображение не меняется и нет видимого запроса обновления сервиса, AR-вычисления всё равно выполняются на каждом frame рендеринга. Поэтому, если нужно получить все изменения transform, необходимо получать данные transform каждый frame, а не только на некоторых frame.
Получение 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. Например, для image tracking таким target является объект, на котором находится компонент ImageTargetController.
Session.PostSessionUpdate += () =>
{
var position = target.transform.position;
var rotation = target.transform.rotation;
};
[Опционально] Получение pose
pose — это структура данных, описывающая положение и ориентацию объекта, обычно состоящая из position и rotation. В AR-приложениях pose обычно используется для описания положения и ориентации физической камеры или target отслеживания относительно некоторой системы отсчёта.
Unity не предоставляет сырые данные pose, потому что pose обычно используется для управления движением объектов сцены, а это как раз автоматически делает session. Для расчёта и рендеринга контента достаточно transform.
Важно
Перед тем как читать следующий метод, ещё раз подумайте, достаточно ли уже данных transform камеры, target отслеживания и других объектов. Обычно дополнительные данные pose не нужны.
Если по какой-то причине данные pose действительно нужны, их можно вычислить из transform в событии PostSessionUpdate. Обычно относительный transform target и camera, полученный в PostSessionUpdate, и есть pose.
Ниже приведён код, показывающий, как получить transform camera и target и вычислить относительный 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 камеры, target отслеживания и других объектов в Unity обычно автоматически обновляется session. Эти обновления обеспечивают корректность и согласованность AR-рендеринга, поэтому перехватить их напрямую нельзя.
Но если нужна собственная логика обновления transform объектов, это можно сделать, подписавшись на событие PostSessionUpdate. Здесь требуется довольно неудобный способ:
- Хотя обычно рендеримый контент следует размещать как дочерние узлы или дополнительные компоненты под объектами, управляемыми session, если нужно переопределить обновление transform, эти объекты следует вывести из иерархии, управляемой session. То есть они не должны быть дочерними объектами, управляемыми session.
- В событии PostSessionUpdate запишите transform объектов, которые хотите обновлять вручную.
- Наконец, в событии PostSessionUpdate обновите transform этих объектов собственной логикой на основе данных, предоставленных session.
Примечание
Использовать событие PostSessionUpdate обязательно, потому что только после этого момента session больше не воздействует на объекты сцены.
Обратите внимание, что этот способ нельзя использовать для изменения camera; для пользовательского обновления камеры требуется более сложная логика.
Кроме того, этот способ подходит только для пользовательского обновления transform объектов, но не для изменения transform объектов, управляемых session. Если transform объекта, управляемого session, будет изменён извне, session всё равно перезапишет эти изменения при следующем обновлении frame, и это может повлиять на корректность некоторых вычислений.
Осторожно
При использовании этого способа необходимо гарантировать корректность transform объектов, иначе это может привести к ошибкам AR-рендеринга.
Если вы также используете AR Foundation, гарнитуру или другие сторонние библиотеки, они могут изменять transform объектов сцены. Нужно убедиться, что логика их обновления не конфликтует с вашей пользовательской логикой, иначе возможны непредсказуемые результаты.
Связанные темы
- Центральный режим ограничивает, какие объекты session может изменять через transform
- Введение в базовые компоненты AR