1. Прежде чем начать
В этой кодовой лаборатории рассматривается пример создания веб-приложения AR. Он использует JavaScript для визуализации 3D-моделей, которые выглядят так, как будто они существуют в реальном мире.
Вы используете API устройства WebXR , который сочетает в себе функции AR и виртуальной реальности (VR). Вы сосредотачиваетесь на расширениях AR для API устройства WebXR, чтобы создать простое приложение AR, которое работает в интерактивном Интернете.
Что такое АР?
AR — это термин, обычно используемый для описания смешения компьютерной графики с реальным миром. В случае AR на базе телефона это означает убедительное размещение компьютерной графики поверх прямой трансляции с камеры. Чтобы этот эффект оставался реалистичным при движении телефона по миру, устройству с поддержкой AR необходимо понимать мир, в котором оно движется, и определять свою позу (положение и ориентацию) в трехмерном пространстве. Это может включать в себя обнаружение поверхностей и оценку освещения окружающей среды.
AR стала широко использоваться в приложениях после выпуска Google ARCore и Apple ARKit , будь то фильтры для селфи или игры на основе AR.
Что ты построишь
В этой лаборатории кода вы создадите веб-приложение, которое помещает модель в реальный мир с использованием дополненной реальности. Ваше приложение будет:
- Используйте датчики целевого устройства, чтобы определять и отслеживать его положение и ориентацию в мире.
- Рендеринг 3D-модели, наложенной поверх изображения с камеры в реальном времени.
- Выполняйте тесты на попадание, чтобы размещать объекты поверх обнаруженных поверхностей в реальном мире.
Что вы узнаете
- Как использовать API устройства WebXR
- Как настроить базовую сцену AR
- Как найти поверхность с помощью AR-тестов на попадание
- Как загрузить и визуализировать 3D-модель, синхронизированную с камерой реального мира
- Как визуализировать тени на основе 3D-модели
Эта лаборатория кода ориентирована на API AR. Нерелевантные концепции и блоки кода замалчиваются и предоставляются вам в соответствующем коде репозитория.
Что вам понадобится
- Рабочая станция для кодирования и размещения статического веб-контента.
- Android-устройство с поддержкой ARCore под управлением Android 8.0 Oreo
- Гугл Хром
- Установлены сервисы Google Play для AR (Chrome автоматически предложит установить их на совместимые устройства)
- Веб-сервер по вашему выбору
- USB-кабель для подключения устройства AR к рабочей станции
- Пример кода
- Текстовый редактор
- Базовые знания HTML, CSS, JavaScript и инструментов разработчика Google Chrome.
Нажмите «Попробовать» на своем устройстве AR, чтобы попробовать первый шаг этой лаборатории кода. Если вы получаете страницу с сообщением «Ваш браузер не поддерживает функции AR», убедитесь, что на вашем устройстве Android установлены Сервисы Google Play для AR.
2. Настройте среду разработки
Загрузите код
- Щелкните следующую ссылку, чтобы загрузить весь код этой лаборатории кода на свою рабочую станцию:
- Распакуйте загруженный zip-файл. При этом распаковывается корневая папка (
ar-with-webxr-master
), которая содержит каталоги нескольких шагов этой лаборатории кода, а также все необходимые вам ресурсы.
Папки step-03
и step-04
содержат желаемое конечное состояние третьего и четвертого шагов этой лаборатории кода, а также final
результат. Они здесь для справки.
Вы выполняете всю работу по кодированию в work
каталоге.
Установить веб-сервер
- Вы можете использовать свой собственный веб-сервер. Если у вас его еще нет, в этом разделе подробно описано, как настроить веб-сервер для Chrome.
Если это приложение еще не установлено на вашей рабочей станции, вы можете установить его из Интернет-магазина Chrome.
- После установки приложения «Веб-сервер для Chrome» перейдите на
chrome://apps
и щелкните значок «Веб-сервер»:
Далее вы увидите это диалоговое окно, которое позволяет вам настроить локальный веб-сервер:
- Нажмите «Выбрать папку» и выберите папку
ar-with-webxr-master
. Это позволяет вам обслуживать незавершенную работу через URL-адрес, выделенный в диалоговом окне веб-сервера (в разделе URL-адреса веб-сервера ). - В разделе «Параметры» (требуется перезагрузка) установите флажок «Автоматически показывать index.html» .
- Переключите веб-сервер в положение «Остановить» , а затем снова в положение «Запущено» .
- Убедитесь, что отображается хотя бы один URL-адрес веб-сервера: http://127.0.0.1:8887 — URL-адрес локального хоста по умолчанию.
Настроить переадресацию портов
Настройте свое AR-устройство так, чтобы оно имело доступ к тому же порту на вашей рабочей станции, когда вы посещаете на нем localhost:8887.
- На рабочей станции разработки перейдите на страницу chrome://inspect и нажмите «Переадресация портов...» :
- Используйте диалоговое окно «Настройки переадресации портов» , чтобы перенаправить порт 8887 на локальный хост: 8887.
- Установите флажок Включить переадресацию портов :
Проверьте настройки
Проверьте свое соединение:
- Подключите устройство AR к рабочей станции с помощью USB-кабеля.
- На вашем AR-устройстве в Chrome введите http://localhost:8887 в адресной строке. Ваше AR-устройство должно перенаправить этот запрос на веб-сервер вашей рабочей станции разработки. Вы должны увидеть каталог файлов.
- На своем устройстве AR нажмите
step-03
чтобы загрузить файлstep-03/index.html
в браузер.
Вы должны увидеть страницу с кнопкой «Начать дополненную реальность». | Однако если вы видите страницу с ошибкой «Неподдерживаемый браузер» , возможно, ваше устройство несовместимо. |
Теперь соединение с вашим веб-сервером должно работать с вашим устройством AR.
- Нажмите «Начать дополненную реальность» . Вам может быть предложено установить ARCore.
При первом запуске приложения AR вы увидите запрос на доступ к камере.
→
Как только все будет готово, вы должны увидеть сцену из кубов, наложенную поверх изображения с камеры. Понимание сцены улучшается по мере того, как камера анализирует большую часть мира, поэтому перемещение может помочь стабилизировать ситуацию.
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.
- Найдите функцию
activateXR()
вapp.js
Некоторый код опущен:
activateXR = async () => {
// Initialize a WebXR session using "immersive-ar".
this.xrSession = /* TODO */;
// Omitted for brevity
}
Точка входа в WebXR — через XRSystem.requestSession()
. Используйте режим immersive-ar
чтобы визуализированный контент можно было просматривать в реальной среде.
- Инициализируйте
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");
Определить цикл анимации
- Используйте
requestAnimationFrame
XRSession
, чтобы запустить цикл рендеринга, аналогичноwindow.requestAnimationFrame
.
В каждом кадре onXRFrame
вызывается с меткой времени и XRFrame .
- Завершите реализацию
onXRFrame
. Когда кадр нарисован, поставьте в очередь следующий запрос, добавив:
// Queue up the next draw request.
this.xrSession.requestAnimationFrame(this.onXRFrame);
- Добавьте код для настройки графической среды. Добавьте в конец
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);
- Чтобы определить позу зрителя, используйте
XRFrame.getViewerPose()
. ЭтотXRViewerPose
описывает положение и ориентацию устройства в пространстве. Он также содержит массивXRView
, который описывает каждую точку обзора, из которой должна быть визуализирована сцена, чтобы она правильно отображалась на текущем устройстве. В то время как стереоскопическая виртуальная реальность имеет два изображения (по одному для каждого глаза), устройства AR имеют только одно изображение.
Информацияpose.views
чаще всего используется для настройки матрицы обзора и матрицы проекции виртуальной камеры. Это влияет на то, как сцена отображается в 3D. Когда камера настроена, сцену можно визуализировать. - Добавьте в конец
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
требуются дополнительные функции.
- В
app.js
найдитеnavigator.xr.requestSession
. - Добавьте функции
"hit-test"
и"dom-overlay"
поrequiredFeature
. Feature следующим образом:
this.xrSession = await navigator.xr.requestSession("immersive-ar", {
requiredFeatures: ["hit-test", "dom-overlay"]
});
- Настройте наложение 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>
Добавить сетку
Используйте сетку, чтобы указать место, на которое указывает вид устройства.
- В
app.js
замените вызовDemoUtils.createCubeScene()
вsetupThreeJs()
пустым вызовомThree.Scene()
.
setupThreeJs() {
// ...
// this.scene = DemoUtils.createCubeScene();
this.scene = DemoUtils.createLitScene();
}
- Заполните новую сцену объектом, представляющим точку столкновения. Предоставленный класс
Reticle
обрабатывает загрузку модели прицела вshared/utils.js
. - Добавьте
Reticle
в сцену вsetupThreeJs()
:
setupThreeJs() {
// ...
// this.scene = DemoUtils.createCubeScene();
this.scene = DemoUtils.createLitScene();
this.reticle = new Reticle();
this.scene.add(this.reticle);
}
Чтобы выполнить проверку попадания, вы используете новый XRReferenceSpace
. Это опорное пространство указывает новую систему координат с точки зрения зрителя для создания луча, совмещенного с направлением просмотра. Эта система координат используется в XRSession.requestHitTestSource()
, который может вычислять тесты попадания.
- Добавьте следующее в
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 });
// ...
}
- Используя этот
hitTestSource
, выполняйте проверку попадания в каждом кадре:- Если результаты проверки на попадание отсутствуют, значит, у ARCore не было достаточно времени для понимания среды. В этом случае предложите пользователю переместить устройство, используя стабилизацию
<div>
. - Если есть результаты, переместите прицельную марку в это место.
- Если результаты проверки на попадание отсутствуют, значит, у ARCore не было достаточно времени для понимания среды. В этом случае предложите пользователю переместить устройство, используя стабилизацию
- Измените
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 на мобильных устройствах основным действием является касание экрана.
- Добавьте прослушиватель событий
select
в нижней частиonSessionStarted
:
this.xrSession.addEventListener("select", this.onSelect);
В этом примере касание экрана приводит к тому, что подсолнух помещается в прицельную сетку.
- Создайте реализацию
onSelect
в классеApp
:
onSelect = () => {
if (window.sunflower) {
const clone = window.sunflower.clone();
clone.position.copy(this.reticle.position);
this.scene.add(clone);
}
}
Протестируйте приложение
Вы создали прицельную марку, в которую можно прицеливаться с помощью устройства, используя тесты на попадание. Нажимая на экран, вы сможете поместить подсолнух в место, указанное сеткой.
- При запуске приложения вы должны увидеть прицельную сетку, очерчивающую поверхность пола. Если нет, попробуйте медленно осмотреться с помощью телефона.
- Как только вы увидите сетку, коснитесь ее. Сверху следует разместить подсолнух. Возможно, вам придется немного передвигаться, чтобы базовая платформа AR могла лучше обнаруживать поверхности в реальном мире. Низкое освещение и поверхности без особенностей снижают качество понимания сцены и увеличивают вероятность того, что попадание не будет обнаружено. Если у вас возникнут какие-либо проблемы, ознакомьтесь с кодом
step-04/app.js
чтобы увидеть рабочий пример этого шага.
5. Добавляем тени
Создание реалистичной сцены включает в себя такие элементы, как правильное освещение и тени на цифровых объектах, которые добавляют реалистичности и погружения в сцену.
Освещение и тени обрабатываются three.js
. Вы можете указать, какие источники света должны отбрасывать тени, какие материалы должны получать и отображать эти тени и какие сетки могут отбрасывать тени. Сцена этого приложения содержит источник света, отбрасывающий тень, и плоскую поверхность для рендеринга только теней.
- Включите тени в
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
на ту же высоту, что и реальная поверхность, чтобы тень цветка отображалась поверх реальной земли.
- В
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.