Search
Write a publication
Pull to refresh

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

Level of difficultyMedium

Если кто-то вам скажет, что дополненная реальность — это сложно, он прав. Но если он скажет, что это невозможно в браузере — он отстал от жизни. 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 ждёт.

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.