Человек наводит очки на щиток в цеху, и рядом с оборудованием появляется подсказка с последней датой обслуживания и порядком действий при аварии. Ни приложения из магазина, ни установки, ни привязки к конкретной модели устройства. Достаточно открыть адрес. Так выглядит обещание веб-стандарта для иммерсивных сценариев, и до реальной работы здесь меньше шагов, чем кажется, но и подводных камней хватает.
Стандарт заменил ранний интерфейс и покрывает оба вида реальности
Первая попытка дать браузеру доступ к устройствам погружения появилась весной 2014 года. Её предложил разработчик одной из компаний, и работа шла силами нескольких команд. Через два года увидела свет первая версия предложения.
Ограничение раннего интерфейса было заложено в названии: он умел работать только с виртуальной реальностью. Дополненная реальность, где изображение накладывается на реальный мир, оставалась за рамками.
В 2018 году появился новый стандарт, который заменил прежний и охватил оба направления сразу. Рабочая группа по иммерсивным технологиям стала официальной двадцать четвёртого сентября 2018 года. Спецификация основного интерфейса получила статус кандидата в рекомендации, а отдельные модули продолжают разрабатываться.
Буква в названии не является частью аббревиатуры. Она играет роль переменной и подставляется под разные виды реальности: виртуальную, дополненную, смешанную и те, что появятся позже. Стандарт изначально проектировался так, чтобы не привязываться к одному варианту.
Стандарт определяет три режима работы. Встроенный режим показывает трёхмерное содержимое прямо в обычной странице, без шлема. Режим погружения в виртуальность выводит картинку на шлем. Режим дополненной реальности накладывает изображение поверх обзора реального мира.
Запуск сцены требует защищённого соединения и действия пользователя
Первое ограничение знакомо по другим чувствительным возможностям браузера: сцена работает только в защищённом контексте. Второе ограничение специфично для иммерсивных сценариев и связано с защитой от внезапного перехода.
Браузер требует, чтобы запрос на полноценную сессию исходил от действия человека. Проще говоря, нажать нужно самому. Автоматический переход в полноэкранный трёхмерный режим при загрузке страницы запрещён, и это правильно: иначе случайно открытая ссылка уводила бы пользователя в шлем без предупреждения.
Работа начинается с проверки поддержки и запроса сессии:
async function startImmersive(mode) {
if (!navigator.xr) {
return null;
}
const supported = await navigator.xr.isSessionSupported(mode);
if (!supported) {
return null;
}
const session = await navigator.xr.requestSession(mode, {
requiredFeatures: ["local-floor"],
optionalFeatures: ["hit-test", "anchors"],
});
return session;
}
document.querySelector("#enter").addEventListener("click", async () => {
const session =
(await startImmersive("immersive-ar")) ||
(await startImmersive("immersive-vr"));
if (!session) {
console.log("Погружение недоступно на этом устройстве");
return;
}
await session.end();
});
Обратите внимание на разделение требований на обязательные и необязательные. Если запросить всё сразу как необходимое, сцена не запустится на устройстве, где чего-то не хватает. Обязательным стоит оставлять минимум.
Второй важный момент в примере: попытка сначала дополненной реальности, потом виртуальной. Это частый практический приём, поскольку очки и телефоны поддерживают разные режимы.
Кадр рисуется в цикле и должен укладываться в жёсткий бюджет
В отличие от обычной страницы, где перерисовка происходит по необходимости, иммерсивная сцена рисуется непрерывно. Каждый кадр нужно успеть подготовить за доли секунды, иначе изображение дёргается, а у пользователя возникает неприятное ощущение.
Целевая частота определяется устройством. Для комфортного восприятия она обычно составляет от семидесяти двух до ста двадцати кадров в секунду. Несложно посчитать бюджет одного кадра: при девяноста герцах на всё отводится примерно одиннадцать миллисекунд. Внутри этого времени нужно успеть обновить логику, собрать данные о положении головы и рук, отрисовать сцену дважды, по разу для каждого глаза.
Отсюда следуют практические ограничения. Тяжёлые вычисления в цикле недопустимы. Загрузка данных идёт заранее или в отдельном потоке. Количество полигонов и текстур подбирается с запасом.
let session = null;
let referenceSpace = null;
let renderer = null;
async function startRenderLoop(newSession, gl, xrRenderer) {
session = newSession;
renderer = xrRenderer;
referenceSpace = await session.requestReferenceSpace("local-floor");
renderer.setSize(gl.canvas.width, gl.canvas.height, false);
renderer.xr.enabled = true;
await renderer.xr.setSession(session);
session.addEventListener("end", () => {
session = null;
referenceSpace = null;
});
}
В основе лежит опорная система координат, которая описывает, где находится пользователь и куда он смотрит. Есть базовый вариант, привязанный к положению в момент запуска, и вариант с привязкой к полу, когда нужно знать высоту. Для сцен, где объект стоит на поверхности, второй вариант обязателен.
Дополненная реальность требует понимания окружающего пространства
Виртуальность строится в пустоте, и вопросов о взаимодействии с миром не возникает. Дополненная реальность сложнее: объект должен вести себя правдоподобно по отношению к реальным поверхностям.
Первое, что нужно, это определение попадания луча в поверхность. Пользователь наводит устройство на стол, и приложение понимает, что камера смотрит на стол и на каком расстоянии он находится. Без этого невозможно поставить виртуальный предмет на реальную плоскость.
Второе это якоря. Когда место найдено, создаётся привязка, и объект держится за неё даже при движении пользователя. Без якоря модель уплывает при малейшем смещении.
Третье это освещение. Найденные поверхности и оценки освещённости позволяют подобрать яркость и тени так, чтобы объект не выглядел наклейкой. Освещение оценивается приблизительно, но даже грубая оценка заметно улучшает правдоподобие.
async function placeObject(session, frame, referenceSpace, scene) {
const hits = frame.getHitTestResults(hitTestSource);
if (hits.length === 0) {
return null;
}
const pose = hits[0].getPose(referenceSpace);
if (!pose) {
return null;
}
const anchor = await hits[0].createAnchor();
const model = scene.cloneModel();
model.position.set(
pose.transform.position.x,
pose.transform.position.y,
pose.transform.position.z,
);
anchors.set(anchor, model);
return model;
}
Работа с якорями требует освобождения ресурсов. Если пользователь разместил десяток объектов и ушёл на другой экран, якоря стоит удалить, иначе они продолжат занимать память и вычислительное время.
Ввод строится на положении контроллеров и положении рук
Управление в иммерсивных сценах отличается от мыши и клавиатуры. Основных источников ввода три.
Первый это контроллеры. У каждого есть положение в пространстве, кнопки и, в части моделей, аналоговые стики. Состояние читается каждый кадр и передаётся приложению.
Второй это отслеживание рук. Камера распознаёт положение пальцев и жесты, и приложение может реагировать на касание виртуальных кнопок без физического устройства.
Третий это взгляд. Направление взгляда используется как указатель, а длительная задержка на объекте воспринимается как выбор. Для людей с ограниченной подвижностью это единственный доступный способ.
function readInputs(frame, inputSource, referenceSpace) {
const state = { select: false, position: null };
for (const source of frame.session.inputSources) {
if (source.handedness !== inputSource) {
continue;
}
const pose = frame.getPose(source.targetRaySpace, referenceSpace);
if (pose) {
state.position = pose.transform.position;
}
const gamepad = source.gamepad;
if (gamepad && gamepad.buttons[0]) {
state.select = gamepad.buttons[0].pressed;
}
}
return state;
}
Здесь важно помнить о переключении между источниками. Человек может положить контроллеры и поднять руки, и сцена должна корректно сменить способ управления, а не зависнуть в ожидании.
Ограничения устройств диктуют скромность сцен
Очки носят на голове, и это определяет жёсткие рамки.
Первое ограничение это вес и нагрев. Тяжёлая сцена заставляет устройство работать на пределе, батарея садится за час, а корпус греется. Оптимизация здесь не роскошь, а условие работоспособности.
Второе ограничение это поле зрения. У части устройств оно уже, чем у человеческого глаза. Объекты, расположенные у краёв обзора, плохо видны, поэтому важную информацию стоит держать в центральной зоне.
Третье ограничение это удобство длительного ношения. Полчаса в шлеме утомляют, а час способен вызвать дискомфорт. Сценарии стоит рассчитывать на короткие сеансы с перерывами.
Четвёртое ограничение это гигиена и совместное использование. Одно устройство на бригаду требует протирки и продуманного порядка передачи.
Пятое ограничение касается безопасности. Человек в очках хуже видит окружение. Сценарии, где нужно двигаться по цеху, опасны, и их лучше избегать или ограничивать рамками обозначенной площадки.
Область применения определяется выгодой, а не новизной
Технология выглядит эффектно, и это главная ловушка. Эффектность не заменяет пользу.
Обучение персонала это самый очевидный сценарий. Опасные операции отрабатываются на модели, а не на живом оборудовании. Ошибка не приводит к аварии, а повторять упражнение можно сколько угодно раз.
Инструкции на месте работы это второй сценарий. Вместо бумажной папки перед сотрудником появляется подсказка, привязанная к конкретному узлу. Для сложного оборудования это сокращает время поиска.
Техническое обслуживание это третий сценарий. Специалист видит схему, наложенную на реальный агрегат, и получает подсказку о требуемом инструменте. Такой сценарий ценят выездные бригады.
Демонстрация товара это четвёртый сценарий. Покупатель смотрит, как мебель встанет в его комнате. Ценность здесь высока только для товаров, где важен размер и внешний вид.
Есть и сценарии, где технология проигрывает. Показ сложных данных на трёхмерной модели часто хуже читается, чем обычный график на экране. Совместная работа в шлемах утомляет быстрее, чем видеозвонок. Для этих задач стоит честно признать, что привычные инструменты справляются лучше.
Практический порядок внедрения экономит бюджет
Начинать стоит с простого, и это не компромисс, а способ снизить риск.
Первый шаг это встроенный режим на обычном экране. Он не требует устройств и позволяет отработать логику сцены, управление и структуру данных. Ошибки на этом этапе дешёвы.
Второй шаг это поддержка одного устройства. Выбирается конкретная модель, на ней проверяется всё: производительность, нагрев, удобство, точность. Пытаться охватить все устройства сразу значит не проверить толком ни одно.
Третий шаг это измерение пользы. Сценарий сравнивается с обычным способом выполнения той же задачи. Если время сократилось или число ошибок уменьшилось, внедрение оправдано. Если разницы нет, эффектность не поможет.
Четвёртый шаг это расширение парка. Когда сценарий отлажен и польза доказана, добавляются другие устройства и режимы.
Веб-сценарии для очков получились редким случаем, когда технология честно ограничена и от этого выигрывает. Нужен защищённый контекст, нужно действие человека, нужно уложиться в миллисекунды кадра. Эти рамки отсекают лишнее и оставляют сценарии, где присутствие в дополненной реальности действительно что-то меняет. Всё остальное спокойно живёт на обычной странице, и это правильный итог.