Создайте приложение дополненной реальности (AR) с помощью API устройства WebXR.

1. Прежде чем начать

В этой кодовой лаборатории рассматривается пример создания веб-приложения AR. Он использует JavaScript для визуализации 3D-моделей, которые выглядят так, как будто они существуют в реальном мире.

Вы используете API устройства WebXR , который сочетает в себе функции AR и виртуальной реальности (VR). Вы сосредотачиваетесь на расширениях AR для API устройства WebXR, чтобы создать простое приложение AR, которое работает в интерактивном Интернете.

Что такое АР?

AR — это термин, обычно используемый для описания смешения компьютерной графики с реальным миром. В случае AR на базе телефона это означает убедительное размещение компьютерной графики поверх прямой трансляции с камеры. Чтобы этот эффект оставался реалистичным при движении телефона по миру, устройству с поддержкой AR необходимо понимать мир, в котором оно движется, и определять свою позу (положение и ориентацию) в трехмерном пространстве. Это может включать в себя обнаружение поверхностей и оценку освещения окружающей среды.

AR стала широко использоваться в приложениях после выпуска Google ARCore и Apple ARKit , будь то фильтры для селфи или игры на основе AR.

Что ты построишь

В этой лаборатории кода вы создадите веб-приложение, которое помещает модель в реальный мир с использованием дополненной реальности. Ваше приложение будет:

  1. Используйте датчики целевого устройства, чтобы определять и отслеживать его положение и ориентацию в мире.
  2. Рендеринг 3D-модели, наложенной поверх изображения с камеры в реальном времени.
  3. Выполняйте тесты на попадание, чтобы размещать объекты поверх обнаруженных поверхностей в реальном мире.

Что вы узнаете

  • Как использовать API устройства WebXR
  • Как настроить базовую сцену AR
  • Как найти поверхность с помощью AR-тестов на попадание
  • Как загрузить и визуализировать 3D-модель, синхронизированную с камерой реального мира
  • Как визуализировать тени на основе 3D-модели

Эта лаборатория кода ориентирована на API AR. Нерелевантные концепции и блоки кода замалчиваются и предоставляются вам в соответствующем коде репозитория.

Что вам понадобится

Нажмите «Попробовать» на своем устройстве AR, чтобы попробовать первый шаг этой лаборатории кода. Если вы получаете страницу с сообщением «Ваш браузер не поддерживает функции AR», убедитесь, что на вашем устройстве Android установлены Сервисы Google Play для AR.

2. Настройте среду разработки

Загрузите код

  1. Щелкните следующую ссылку, чтобы загрузить весь код этой лаборатории кода на свою рабочую станцию:

  1. Распакуйте загруженный zip-файл. При этом распаковывается корневая папка ( ar-with-webxr-master ), которая содержит каталоги нескольких шагов этой лаборатории кода, а также все необходимые вам ресурсы.

Папки step-03 и step-04 содержат желаемое конечное состояние третьего и четвертого шагов этой лаборатории кода, а также final результат. Они здесь для справки.

Вы выполняете всю работу по кодированию в work каталоге.

Установить веб-сервер

  1. Вы можете использовать свой собственный веб-сервер. Если у вас его еще нет, в этом разделе подробно описано, как настроить веб-сервер для Chrome.
    Если это приложение еще не установлено на вашей рабочей станции, вы можете установить его из Интернет-магазина Chrome.

  1. После установки приложения «Веб-сервер для Chrome» перейдите на chrome://apps и щелкните значок «Веб-сервер»:

Значок веб-сервера

Далее вы увидите это диалоговое окно, которое позволяет вам настроить локальный веб-сервер:

Настройка веб-сервера Chrome

  1. Нажмите «Выбрать папку» и выберите папку ar-with-webxr-master . Это позволяет вам обслуживать незавершенную работу через URL-адрес, выделенный в диалоговом окне веб-сервера (в разделе URL-адреса веб-сервера ).
  2. В разделе «Параметры» (требуется перезагрузка) установите флажок «Автоматически показывать index.html» .
  3. Переключите веб-сервер в положение «Остановить» , а затем снова в положение «Запущено» . Перезапустите веб-сервер Chrome.
  4. Убедитесь, что отображается хотя бы один URL-адрес веб-сервера: http://127.0.0.1:8887 — URL-адрес локального хоста по умолчанию.

Настроить переадресацию портов

Настройте свое AR-устройство так, чтобы оно имело доступ к тому же порту на вашей рабочей станции, когда вы посещаете на нем localhost:8887.

  1. На рабочей станции разработки перейдите на страницу chrome://inspect и нажмите «Переадресация портов...» : хром://проверить
  2. Используйте диалоговое окно «Настройки переадресации портов» , чтобы перенаправить порт 8887 на локальный хост: 8887.
  3. Установите флажок Включить переадресацию портов :

Настроить переадресацию портов

Проверьте настройки

Проверьте свое соединение:

  1. Подключите устройство AR к рабочей станции с помощью USB-кабеля.
  2. На вашем AR-устройстве в Chrome введите http://localhost:8887 в адресной строке. Ваше AR-устройство должно перенаправить этот запрос на веб-сервер вашей рабочей станции разработки. Вы должны увидеть каталог файлов.
  3. На своем устройстве AR нажмите step-03 чтобы загрузить файл step-03/index.html в браузер.

Вы должны увидеть страницу с кнопкой «Начать дополненную реальность».

Однако если вы видите страницу с ошибкой «Неподдерживаемый браузер» , возможно, ваше устройство несовместимо.

ARCore поддерживается

ARCore не поддерживается

Теперь соединение с вашим веб-сервером должно работать с вашим устройством AR.

  1. Нажмите «Начать дополненную реальность» . Вам может быть предложено установить ARCore.

Установите приглашение ARCore

При первом запуске приложения AR вы увидите запрос на доступ к камере.

Chrome запрашивает разрешения камерыДиалог разрешений

Как только все будет готово, вы должны увидеть сцену из кубов, наложенную поверх изображения с камеры. Понимание сцены улучшается по мере того, как камера анализирует большую часть мира, поэтому перемещение может помочь стабилизировать ситуацию.

3. Настройте WebXR

На этом этапе вы узнаете, как настроить сеанс WebXR и базовую сцену AR. HTML-страница снабжена стилем CSS и JavaScript для включения базовых функций AR. Это ускоряет процесс настройки, позволяя команде разработчиков сосредоточиться на функциях AR.

HTML-страница

Вы встраиваете AR-опыт в традиционную веб-страницу, используя существующие веб-технологии. В этом случае вы используете полноэкранное полотно рендеринга, поэтому HTML-файл не должен быть слишком сложным.

Для запуска функций AR требуется жест пользователя, поэтому существуют некоторые компоненты Material Design для отображения кнопки «Запустить AR» и сообщения браузера о неподдержке.

Файл index.html , который уже находится в вашем work каталоге, должен выглядеть примерно так: Это часть фактического содержимого; не копируйте этот код в свой файл!

<!-- Don't copy this code into your file! -->
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Building an augmented reality application with the WebXR Device API</title>
    <link rel="stylesheet" href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css">
    <script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>

    <!-- three.js -->
    <script src="https://unpkg.com/three@0.123.0/build/three.js"></script>
    <script src="https://unpkg.com/three@0.123.0/examples/js/loaders/GLTFLoader.js"></script>

    <script src="../shared/utils.js"></script>
    <script src="app.js"></script>
  </head>
  <body>
  <!-- Information about AR removed for brevity. -->

  <!-- Starting an immersive WebXR session requires user interaction. Start the WebXR experience with a simple button. -->
  <a onclick="activateXR()" class="mdc-button mdc-button--raised mdc-button--accent">
    Start augmented reality
  </a>

</body>
</html>

Откройте ключевой код JavaScript

Отправная точка вашего приложения находится в app.js Этот файл представляет собой шаблон для настройки AR-опыта.

Ваш рабочий каталог также уже содержит код приложения ( app.js ).

Проверьте поддержку WebXR и AR

Прежде чем пользователь сможет работать с AR, проверьте наличие navigator.xr и необходимых функций XR. Объект navigator.xr является точкой входа для API устройства WebXR, поэтому он должен существовать, если устройство совместимо. Также убедитесь, что поддерживается режим сеанса "immersive-ar" .

Если все в порядке, нажатие кнопки «Войти в дополненную реальность» попытается создать сеанс XR. В противном случае вызывается onNoXRDevice() ( shared/utils.js ), который отображает сообщение об отсутствии поддержки AR.

Этот код уже присутствует в app.js , поэтому никаких изменений вносить не нужно.

(async function() {
  if (navigator.xr && await navigator.xr.isSessionSupported("immersive-ar")) {
    document.getElementById("enter-ar").addEventListener("click", activateXR)
  } else {
    onNoXRDevice();
  }
})();

Запросить XRSession

Когда вы нажимаете «Войти в дополненную реальность» , код вызывает activateXR() . Это запускает опыт AR.

  1. Найдите функцию activateXR() в app.js Некоторый код опущен:
activateXR = async () => {
  // Initialize a WebXR session using "immersive-ar".
  this.xrSession = /* TODO */;

  // Omitted for brevity
}

Точка входа в WebXR — через XRSystem.requestSession() . Используйте режим immersive-ar чтобы визуализированный контент можно было просматривать в реальной среде.

  1. Инициализируйте this.xrSession , используя режим "immersive-ar" :
activateXR = async () => {
  // Initialize a WebXR session using "immersive-ar".
  this.xrSession = await navigator.xr.requestSession("immersive-ar");

  // ...
}

Инициализировать XRReferenceSpace

XRReferenceSpace описывает систему координат, используемую для объектов в виртуальном мире. 'local' режим лучше всего подходит для AR-опыта, поскольку опорное пространство находится рядом со зрителем и стабильно отслеживается.

Инициализируйте this.localReferenceSpace в onSessionStarted() с помощью следующего кода:

this.localReferenceSpace = await this.xrSession.requestReferenceSpace("local");

Определить цикл анимации

  1. Используйте requestAnimationFrame XRSession , чтобы запустить цикл рендеринга, аналогично window.requestAnimationFrame .

В каждом кадре onXRFrame вызывается с меткой времени и XRFrame .

  1. Завершите реализацию onXRFrame . Когда кадр нарисован, поставьте в очередь следующий запрос, добавив:
// Queue up the next draw request.
this.xrSession.requestAnimationFrame(this.onXRFrame);
  1. Добавьте код для настройки графической среды. Добавьте в конец onXRFrame :
// Bind the graphics framebuffer to the baseLayer's framebuffer.
const framebuffer = this.xrSession.renderState.baseLayer.framebuffer;
this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer);
this.renderer.setFramebuffer(framebuffer);
  1. Чтобы определить позу зрителя, используйте XRFrame.getViewerPose() . Этот XRViewerPose описывает положение и ориентацию устройства в пространстве. Он также содержит массив XRView , который описывает каждую точку обзора, из которой должна быть визуализирована сцена, чтобы она правильно отображалась на текущем устройстве. В то время как стереоскопическая виртуальная реальность имеет два изображения (по одному для каждого глаза), устройства AR имеют только одно изображение.
    Информация pose.views чаще всего используется для настройки матрицы обзора и матрицы проекции виртуальной камеры. Это влияет на то, как сцена отображается в 3D. Когда камера настроена, сцену можно визуализировать.
  2. Добавьте в конец onXRFrame :
// Retrieve the pose of the device.
// XRFrame.getViewerPose can return null while the session attempts to establish tracking.
const pose = frame.getViewerPose(this.localReferenceSpace);
if (pose) {
  // In mobile AR, we only have one view.
  const view = pose.views[0];

  const viewport = this.xrSession.renderState.baseLayer.getViewport(view);
  this.renderer.setSize(viewport.width, viewport.height);

  // Use the view's transform matrix and projection matrix to configure the THREE.camera.
  this.camera.matrix.fromArray(view.transform.matrix);
  this.camera.projectionMatrix.fromArray(view.projectionMatrix);
  this.camera.updateMatrixWorld(true);

  // Render the scene with THREE.WebGLRenderer.
  this.renderer.render(this.scene, this.camera);
}

Проверьте это

Запустите приложение; на своем устройстве разработки посетите work/index.html . Вы должны увидеть изображение с камеры с плавающими в пространстве кубами, перспектива которых меняется при перемещении устройства. Чем больше вы перемещаетесь, тем лучше отслеживание, поэтому выясните, что подходит вам и вашему устройству.

Если у вас возникли проблемы с запуском приложения, проверьте разделы «Введение» и «Настройка среды разработки» .

4. Добавьте прицельную сетку

После настройки базовой сцены AR пришло время начать взаимодействовать с реальным миром с помощью проверки попадания. В этом разделе вы программируете проверку попадания и используете ее для поиска поверхности в реальном мире.

Понимание хит-теста

Тест на попадание — это, как правило, способ провести прямую линию из точки пространства в некотором направлении и определить, пересекается ли она с какими-либо интересующими объектами. В этом примере вы нацеливаете устройство на определенное место в реальном мире. Представьте себе луч, идущий от камеры вашего устройства прямо в физический мир перед ним.

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

Объяснение теста на попадание

Запросите XRSession с дополнительными функциями

Для проведения тестов на попадание при запросе XRSession требуются дополнительные функции.

  1. В app.js найдите navigator.xr.requestSession .
  2. Добавьте функции "hit-test" и "dom-overlay" по requiredFeature . Feature следующим образом:
this.xrSession = await navigator.xr.requestSession("immersive-ar", {
  requiredFeatures: ["hit-test", "dom-overlay"]
});
  1. Настройте наложение DOM. Наложите элемент document.body на вид камеры AR следующим образом:
this.xrSession = await navigator.xr.requestSession("immersive-ar", {
  requiredFeatures: ["hit-test", "dom-overlay"],
  domOverlay: { root: document.body }
});

Добавить подсказку о движении

ARCore работает лучше всего, когда имеется адекватное понимание окружающей среды. Это достигается с помощью процесса, называемого одновременной локализацией и картографированием (SLAM), в котором визуально различные характерные точки используются для расчета изменения местоположения и характеристик окружающей среды.

Используйте "dom-overlay" из предыдущего шага, чтобы отобразить подсказку о движении поверх потока камеры.

Добавьте <div> в index.html со stabilization идентификатора. Этот <div> отображает пользователям анимацию, показывающую состояние стабилизации, и предлагает им перемещаться со своим устройством, чтобы улучшить процесс SLAM. Оно отображается, когда пользователь находится в AR, и скрывается, когда прицел находит поверхность, контролируемую классами <body> .

  <div id="stabilization"></div>

</body>
</html>

Добавить сетку

Используйте сетку, чтобы указать место, на которое указывает вид устройства.

  1. В app.js замените вызов DemoUtils.createCubeScene() в setupThreeJs() пустым вызовом Three.Scene() .
setupThreeJs() {
  // ...

  // this.scene = DemoUtils.createCubeScene();
  this.scene = DemoUtils.createLitScene();
}
  1. Заполните новую сцену объектом, представляющим точку столкновения. Предоставленный класс Reticle обрабатывает загрузку модели прицела в shared/utils.js .
  2. Добавьте Reticle в сцену в setupThreeJs() :
setupThreeJs() {
  // ...

  // this.scene = DemoUtils.createCubeScene();
  this.scene = DemoUtils.createLitScene();
  this.reticle = new Reticle();
  this.scene.add(this.reticle);
}

Чтобы выполнить проверку попадания, вы используете новый XRReferenceSpace . Это опорное пространство указывает новую систему координат с точки зрения зрителя для создания луча, совмещенного с направлением просмотра. Эта система координат используется в XRSession.requestHitTestSource() , который может вычислять тесты попадания.

  1. Добавьте следующее в onSessionStarted() в app.js :
async onSessionStarted() {
  // ...

  // Setup an XRReferenceSpace using the "local" coordinate system.
  this.localReferenceSpace = await this.xrSession.requestReferenceSpace("local");

  // Add these lines:
  // Create another XRReferenceSpace that has the viewer as the origin.
  this.viewerSpace = await this.xrSession.requestReferenceSpace("viewer");
  // Perform hit testing using the viewer as origin.
  this.hitTestSource = await this.xrSession.requestHitTestSource({ space: this.viewerSpace });

  // ...
}
  1. Используя этот hitTestSource , выполняйте проверку попадания в каждом кадре:
    • Если результаты проверки на попадание отсутствуют, значит, у ARCore не было достаточно времени для понимания среды. В этом случае предложите пользователю переместить устройство, используя стабилизацию <div> .
    • Если есть результаты, переместите прицельную марку в это место.
  2. Измените onXRFrame , чтобы переместить прицельную марку:
onXRFrame = (time, frame) => {
  // ... some code omitted ...
  this.camera.updateMatrixWorld(true);

  // Add the following:
  const hitTestResults = frame.getHitTestResults(this.hitTestSource);

  if (!this.stabilized && hitTestResults.length > 0) {
    this.stabilized = true;
    document.body.classList.add("stabilized");
  }
  if (hitTestResults.length > 0) {
    const hitPose = hitTestResults[0].getPose(this.localReferenceSpace);

    // update the reticle position
    this.reticle.visible = true;
    this.reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z)
    this.reticle.updateMatrixWorld(true);
  }
  // More code omitted.
}

Добавить поведение при касании экрана

XRSession может генерировать события на основе взаимодействия с пользователем через событие select , которое представляет собой основное действие. В WebXR на мобильных устройствах основным действием является касание экрана.

  1. Добавьте прослушиватель событий select в нижней части onSessionStarted :
this.xrSession.addEventListener("select", this.onSelect);

В этом примере касание экрана приводит к тому, что подсолнух помещается в прицельную сетку.

  1. Создайте реализацию onSelect в классе App :
onSelect = () => {
  if (window.sunflower) {
    const clone = window.sunflower.clone();
    clone.position.copy(this.reticle.position);
    this.scene.add(clone);
  }
}

Протестируйте приложение

Вы создали прицельную марку, в которую можно прицеливаться с помощью устройства, используя тесты на попадание. Нажимая на экран, вы сможете поместить подсолнух в место, указанное сеткой.

  1. При запуске приложения вы должны увидеть прицельную сетку, очерчивающую поверхность пола. Если нет, попробуйте медленно осмотреться с помощью телефона.
  2. Как только вы увидите сетку, коснитесь ее. Сверху следует разместить подсолнух. Возможно, вам придется немного передвигаться, чтобы базовая платформа AR могла лучше обнаруживать поверхности в реальном мире. Низкое освещение и поверхности без особенностей снижают качество понимания сцены и увеличивают вероятность того, что попадание не будет обнаружено. Если у вас возникнут какие-либо проблемы, ознакомьтесь с кодом step-04/app.js чтобы увидеть рабочий пример этого шага.

5. Добавляем тени

Создание реалистичной сцены включает в себя такие элементы, как правильное освещение и тени на цифровых объектах, которые добавляют реалистичности и погружения в сцену.

Освещение и тени обрабатываются three.js . Вы можете указать, какие источники света должны отбрасывать тени, какие материалы должны получать и отображать эти тени и какие сетки могут отбрасывать тени. Сцена этого приложения содержит источник света, отбрасывающий тень, и плоскую поверхность для рендеринга только теней.

  1. Включите тени в three.js WebGLRenderer . После создания рендерера установите следующие значения в его shadowMap :
setupThreeJs() {
  ...
  this.renderer = new THREE.WebGLRenderer(...);
  ...
  this.renderer.shadowMap.enabled = true;
  this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  ...
}

Пример сцены, созданной в DemoUtils.createLitScene() содержит объект с shadowMesh — плоскую горизонтальную поверхность, которая отображает только тени. Эта поверхность изначально имеет позицию Y , равную 10 000 единиц. После размещения подсолнуха переместите shadowMesh на ту же высоту, что и реальная поверхность, чтобы тень цветка отображалась поверх реальной земли.

  1. В onSelect после добавления clone в сцену добавьте код для изменения положения теневой плоскости:
onSelect = () => {
  if (window.sunflower) {
    const clone = window.sunflower.clone();
    clone.position.copy(this.reticle.position);
    this.scene.add(clone);

    const shadowMesh = this.scene.children.find(c => c.name === "shadowMesh");
    shadowMesh.position.y = clone.position.y;
  }
}

Проверьте это

Размещая подсолнух, вы должны видеть, как он отбрасывает тень. Если у вас возникнут какие-либо проблемы, проверьте код final/app.js чтобы увидеть рабочий пример этого шага.

6. Дополнительные ресурсы

Поздравляем! Вы завершили эту лабораторную работу по дополненной реальности с помощью WebXR.

Узнать больше