Человек наводит очки на щиток в цеху, и рядом с оборудованием появляется подсказка с последней датой обслуживания и порядком действий при аварии. Ни приложения из магазина, ни установки, ни привязки к конкретной модели устройства. Достаточно открыть адрес. Так выглядит обещание веб-стандарта для иммерсивных сценариев, и до реальной работы здесь меньше шагов, чем кажется, но и подводных камней хватает.
Стандарт заменил ранний интерфейс и покрывает оба вида реальности
Первая попытка дать браузеру доступ к устройствам погружения появилась весной 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;
}
Здесь важно помнить о переключении между источниками. Человек может положить контроллеры и поднять руки, и сцена должна корректно сменить способ управления, а не зависнуть в ожидании.
Отдельный штрих это отклик вибрацией. Короткое подтверждение касания виртуальной кнопки ощущается рукой и снижает число промахов, а управление без отклика кажется ватным даже при точном распознавании жестов.
Ограничения устройств диктуют скромность сцен
Очки носят на голове, и это определяет жёсткие рамки.
Первое ограничение это вес и нагрев. Тяжёлая сцена заставляет устройство работать на пределе, батарея садится за час, а корпус греется. Оптимизация здесь не роскошь, а условие работоспособности.
Второе ограничение это поле зрения. У части устройств оно уже, чем у человеческого глаза. Объекты, расположенные у краёв обзора, плохо видны, поэтому важную информацию стоит держать в центральной зоне.
Третье ограничение это удобство длительного ношения. Полчаса в шлеме утомляют, а час способен вызвать дискомфорт. Сценарии стоит рассчитывать на короткие сеансы с перерывами.
Четвёртое ограничение это гигиена и совместное использование. Одно устройство на бригаду требует протирки и продуманного порядка передачи.
Пятое ограничение касается безопасности. Человек в очках хуже видит окружение. Сценарии, где нужно двигаться по цеху, опасны, и их лучше избегать или ограничивать рамками обозначенной площадки.
Область применения определяется выгодой, а не новизной
Технология выглядит эффектно, и это главная ловушка. Эффектность не заменяет пользу.
Обучение персонала это самый очевидный сценарий. Опасные операции отрабатываются на модели, а не на живом оборудовании. Ошибка не приводит к аварии, а повторять упражнение можно сколько угодно раз.
Инструкции на месте работы это второй сценарий. Вместо бумажной папки перед сотрудником появляется подсказка, привязанная к конкретному узлу. Для сложного оборудования это сокращает время поиска.
Техническое обслуживание это третий сценарий. Специалист видит схему, наложенную на реальный агрегат, и получает подсказку о требуемом инструменте. Такой сценарий ценят выездные бригады.
Живой показ товара это четвёртый сценарий. Покупатель смотрит, как мебель встанет в его комнате. Ценность здесь высока только для товаров, где важен размер и внешний вид.
Есть и сценарии, где технология проигрывает. Показ сложных данных на трёхмерной модели часто хуже читается, чем обычный график на экране. Совместная работа в шлемах утомляет быстрее, чем видеозвонок. Для этих задач стоит честно признать, что привычные инструменты справляются лучше.
Практический порядок внедрения экономит бюджет
Начинать стоит с простого, и это не компромисс, а способ снизить риск.
Первый шаг это встроенный режим на обычном экране. Он не требует устройств и позволяет отработать логику сцены, управление и структуру данных. Ошибки на этом этапе дешёвы.
Второй шаг это поддержка одного устройства. Выбирается конкретная модель, на ней проверяется всё: производительность, нагрев, удобство, точность. Пытаться охватить все устройства сразу значит не проверить толком ни одно.
Третий шаг это измерение пользы. Сценарий сравнивается с обычным способом выполнения той же задачи. Если время сократилось или число ошибок уменьшилось, внедрение оправдано. Если разницы нет, эффектность не поможет.
Четвёртый шаг это расширение парка. Когда сценарий отлажен и польза доказана, добавляются другие устройства и режимы.
Веб-сценарии для очков получились редким случаем, когда технология честно ограничена и от этого выигрывает. Нужен защищённый контекст, нужно действие человека, нужно уложиться в миллисекунды кадра. Эти рамки отсекают лишнее и оставляют сценарии, где присутствие в дополненной реальности действительно что-то меняет. Всё остальное спокойно живёт на обычной странице, и это правильный итог.