Как стать автором
Обновить

Когда реальность становится частью браузера: глубоко про WebXR и AR

Уровень сложностиСредний

Если кто-то вам скажет, что дополненная реальность — это сложно, он прав. Но если он скажет, что это невозможно в браузере — он отстал от жизни. WebXR API делает реальное расширяемым буквально в два клика, а иногда и в один — если повезёт с железом, браузером и звёздами на небе.

Это не просто «вставили коробку в A-Frame». Это статья для тех, кто хочет разобраться, как WebXR работает по-настоящему. Без магии, без примочек, с низкоуровневым контролем и болью от несовместимости устройств. Но с наградой в виде реально работающего AR прямо в Chrome на Android.

Что такое WebXR

WebXR Device API — это стандарт от W3C, предназначенный для взаимодействия с XR-устройствами (VR и AR) из браузера. Он пришёл на смену WebVR и теперь охватывает больше — включая дополненную реальность.

AR-режим в WebXR инициируется сессией типа immersive-ar, при которой браузер запускает камеру и позволяет проецировать объекты в реальный мир с учётом движений и положения устройства.

Первые грабли: поддержка и окружение

На момент написания статьи, поддержка AR через WebXR ограничена:

  • Chrome на Android с флагом #webxr-incubations включённым

  • Ограниченный список устройств, поддерживающих ARCore

  • Нет поддержки на iOS вообще (Safari и WebXR пока не дружат)

Проверить поддержку можно здесь: https://immersive-web.github.io/webxr-samples/

Минимальный AR с нуля (без A-Frame)

Давайте сразу к мясу. Пример ниже — чистый JavaScript + WebGL, никакой магии:

<!-- HTML -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>WebXR AR Minimal</title>
</head>
<body>
  <canvas id="xr-canvas"></canvas>
  <script type="module" src="main.js"></script>
</body>
</html>
// JavaScript (main.js)
const canvas = document.getElementById('xr-canvas');
const gl = canvas.getContext('webgl', { xrCompatible: true });

let xrSession = null;
let xrRefSpace = null;
let xrFrame = null;

navigator.xr.requestSession('immersive-ar', {
  requiredFeatures: ['local-floor']
}).then(session => {
  xrSession = session;
  session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });

  session.requestReferenceSpace('local-floor').then(refSpace => {
    xrRefSpace = refSpace;
    session.requestAnimationFrame(onXRFrame);
  });
});

function onXRFrame(time, frame) {
  let session = frame.session;
  session.requestAnimationFrame(onXRFrame);
  const pose = frame.getViewerPose(xrRefSpace);

  gl.bindFramebuffer(gl.FRAMEBUFFER, session.renderState.baseLayer.framebuffer);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  if (pose) {
    for (const view of pose.views) {
      const viewport = session.renderState.baseLayer.getViewport(view);
      gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);

      // тут можно отрисовать 3D-объекты, мы пока оставим пусто
    }
  }
}

Да, выглядит просто. Но если запустить — камера включится, и всё, что ты нарисуешь через WebGL, будет «парить» в реальном мире.

Работа с 3D-объектами: подключаем Three.js

Реалистично делать AR на WebGL вручную — удовольствие ниже среднего. Поэтому подключим Three.js, который умеет работать с WebXR через WebXRManager.

// JavaScript + Three.js
import * as THREE from 'three';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 20);

const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

renderer.xr.enabled = true;
document.body.appendChild(ARButton.createButton(renderer, { requiredFeatures: ['hit-test'] }));

const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1);
scene.add(light);

const geometry = new THREE.BoxGeometry(0.1, 0.1, 0.1);
const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const cube = new THREE.Mesh(geometry, material);
cube.position.set(0, 0, -0.5);
scene.add(cube);

function animate() {
  renderer.setAnimationLoop(() => {
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
  });
}

animate();

Не забудьте подключить ARButton из three/examples/jsm/webxr/ARButton.js — он отвечает за инициацию XR-сессии и автоматом проверяет поддержку.

Взаимодействие: тап, гест, тык

Чтобы взаимодействовать с объектами, можно использовать select событие сессии:

renderer.xr.getSession().addEventListener('select', () => {
  cube.material.color.set(Math.random() * 0xffffff);
});

Да, всё просто — пользователь «тапает» в пространство, и происходит событие.

UX-ад: как всё сломать красиво

  • Не рисуйте текст в AR — он не читается.

  • Избегайте малых объектов — они теряются в реальности.

  • Не полагайтесь на точность hit-test — поверхность может не определиться вообще.

  • Тестируйте на реальных людях — многие не понимают, что они должны делать.

Заключение

WebXR — это тот редкий случай, когда браузер становится больше, чем просто окно в интернет. Он становится порталом в AR. Но эта магия требует нервов, экспериментов и постоянной отладки. Оно того стоит — особенно, когда видишь, как твой 3D-объект вписывается в комнату пользователя.

Если вы готовы к приключениям и не боитесь нестабильности — WebXR ждёт.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.