VR/AR в браузере. Как быстро влиться и сделать свое первое приложение, используя WebVR API

от автора

Виртуальная и дополненные реальности активно развиваются и начинают предъявлять права на захват мира. Причем применение этих технологий разнообразно и не ограничивается только играми. А с появлением инструментов для работы с VR/AR технологиями в браузере интерес возрос еще больше. Уже сейчас можно экспериментировать и создавать MVP(Minimum Viable Product) веб-проекты с помощью JavaScript API, которое так и называется — WebVR. Давайте разбираться, что это и как с этим работать. И можно ли обойтись без этого самого WebVR API?

Эта статья носит ознакомительный характер, и она является первой в серии статей про WebVR API и Web AR реализации, которые я планирую. Если тема зайдет, то продолжу развивать ее, показывая уже более конкретные примеры с использованием различных техник и фреймворков. Я хочу поделиться своим личным опытом и обсудить в статье базовые принципы работы с WebVR, как сделать Web AR, что делать если у вас iOS, и рассмотрим устройства, под которые можно все это разрабатывать уже сегодня.

В Туту.ру я работаю в должности системный архитектор подразделения Frontend. Занимаюсь различными RnD (Research and Development ) задачами. Тема VR/AR — не пересекается напрямую с моей работой, но мы уже думаем в компании над применением данной технологии в контексте туристического бизнеса. Меня всегда манят технологии будущего и мне очень нравится Frontend стек. Скорее мне нравится сама идея того, что все можно делать в браузере. Пусть пока это и накладывает ряд ограничений и доставляет некоторые трудности. Но они все решаемы, а через какое-то время и вовсе нивелируются.

Откуда ноги растут

Саму спеку начали писать еще в 2014 году, но первая версия была представлена в начале 2016 года компанией Mozilla. Тогда была представлена первая полноценная черновая спецификация WebVR API. Эта спецификация описывает программный интерфейс для работы с различными VR устройствами типа Oculus Rift и им подобным (собственно данная спека и писалась изначально под окулус). Данная спецификация разработана при участии Брэндона Джонса (Brandon Jones) из компании Google и Джастина Роджерса (Justin Rogers) из Microsoft.

Поддержка новой спецификации WebVR уже реализована в Firefox и мобильном Chrome (точнее про степень реализации и нюансы будет сказано далее). А это значит, что уже сегодня можно свободно экспериментировать и пробовать технологию завтрашнего будущего. Если ваш браузер стар, странен или не обновляется — для всего этого есть полифилы.

Зачем нужен WebVR API?

WebVR API — это программный интерфейс для работы с устройствами. Он ничего не знает про 3D графику. Работа с графикой, отрисовка сцены, установка источников света и все прочее лежит на суровых плечах программистов. WebVR API всего лишь позволяет абстрагировать доступ к устройствам. Данное API предоставляет инструменты для рендеринга картинки, для получения информации об устройстве, его возможностях и технических характеристиках, но саму картинку и 3D мир нужно рисовать, используя уже ставшие привычными веб-технологии, такие как: HTML, CSS, WebGL, Canvas, etc…

WebVR API предоставляет нам несколько основных объектов для работы:

  • Navigator — позволяет получить список девайсов, определить активный;
  • VRDisplay — сообщает одет ли хедсет на голову, информация о кадрах, глазах;
  • VRPose — информация о позиции и ориентации девайса, скорости передвижения и направления;
  • VREyeParameters — информация о том, как рендерить видео в каждый отдельный глаз;
  • VRFrameData — информация о кадре сцены для проекции на отдельный глаз.

Полный список об объектах можно получить в следующих источниках:

Hello VR world

Простой код бойлерплейта для работы с VR устройством на JavaScript выглядит так:

navigator.getVRDisplays().then(displays => {   if (displays.length < 1) {      return console.warn('No displays found!');   }   displays.forEach(vrDisplay => { buildVRDisplay(vrDisplay) }) }); function buildVRDisplay(vrDisplay) {   // получаем доступ к информации о дисплее   const frameData = new VRFRameData;   // содержит информацию о проеуции левого и правого глаза   vrDisplay.getFrameData(frameData);   // получить параметры конкретного глаза   const rightEye = vrDisplay.getEyeParameters('left');   const onAnimationFrame = () => {      // здесь ваша логика анимации      vrDisplay.requestAnimationFrame(onAnimationFrame);   };   vrDisplay.requestAnimationFrame(onAnimationFrame); } 

Данный код должен дать представление, как выглядит работа с использованием WebVR API. Более подробные примеры рассмотрим далее, а сейчас давайте поговорим про поддержку браузерами и про устройства.

С какими устройствами работать?

Когда говорят про VR, то вспоминают Oculus Rift и им подобные. Если мы говорим про WebVR, логично предположить, что мы рассчитываем на разработку под браузеры.

Самые доступные и популярные на сегодня устройства — это так называемые Cardboard девайсы (или еще их называют VRBox’ы). Мобильный VR список устройств можно перечислить по пальцам:

  • Google Cardboard;
  • Google Daydream (новое исполнение Cardboard устройств);
  • различные китайские VRBox’ы под все модели смартфонов;
  • Samsung GR VR (на мой взгляд, удачное сочетание возможностей VR шлема и Cardboard устройства, да еще и с доступом в Oculus Store).

Noname VRBox

Просто бокс с линзами. Бывают в очень разных исполнениях, вплоть до копий Samsung GR VR, но с подключением через Bluetooth любой модели телефона. Делаются в разных форм факторах и разных исполнениях. Можно докупить Bluetooth джойстик, который будет работать с любым смартфоном на любой ОС. Качество очень даже хорошее, к линзам нет претензий. Вся соль кроется в смартфоне, размере дисплея и разрешении экрана.

Xiaomi VRBox

Особенности: наличие механической кнопки-манипулятора, работающей по принципу стилуса, который тапает в “слепую зону” экрана в области переносицы (инженеры жгут :)). Застежка на молнии.

Samsung GR VR

Особенности: подключается к боксу через USB, наличие сенсорной панели и кнопок на шлеме. В момент подключения активируется функционал Oculus, и телефон прикидывается Oculus-совместимым устройством.

Google Cardboard

Особенности: наличие кнопки, выполненной в виде небольшого круглого магнита. В приложении считывается изменение магнитного поля встроенным магнитометром, и данное изменение засчитывается как действие по кнопке в Cardboard-совместимых устройствах.

Google Daydream

Особенности: основное отличие от Cardboard — более основательный и удобный хеадсет и наличие геймпада. Это уже полноценный VRBox, не из картона 🙂

Вот про них мы и будем говорить. Если у вас есть смартфон с браузером Chrome и какая-то вариация VRBox’a, то вы уже сможете проверить в действии WebVR. Лучший вариант — Chrome Canary или Samsung Internet. Конечно, надо сказать про исключение — это iOS. Но там VR можно использовать через полифилы, поэтому демки также будут доступны и с iOS устройств (зависит от реализации). Опять же, надо понимать, что WebVR API — это не про 3D графику, и сделать WebVR мир можно и под iOS без использования этого самого VR API (ну или с полифилами).

Взглянуть на VR мир можно и через окно десктопного браузера, с которым обычно происходит разработка. Сначала мир строится без шлемов, а затем уже добавляются возможности разбиения картинки под оптическую пару. Для этого используем либо Firefox Nightly, либо Chrome вот с таким вот плагином: WebVR API Emulation. Либо Chrome Canary с включенной поддержкой, либо специальную сборку Chromium… Ну вы поняли 🙂

Что с поддержкой в браузерах?

Итак, на сегодня WebVR API в той или иной мере поддерживается в следующих браузерах:

  1. Microsoft Edge в Hololens;
  2. Mozilla Servo в HTC Vive;
  3. Firefox Nightly;
  4. Chrome Canary (нужно включить флаг chrome://flags/#enable-webvr);
  5. Chrome Canary for Android;
  6. Chrome for Android (включая Daydream устройства, версия 56+);
  7. Chromium на HTC Vive, Oculus, Android;
  8. Chromium WebVR Build (https://webvr.info/get-chrome/);
  9. Samsung Internet (Samsung GR VR);
  10. Oculus Carmel (это WebVR браузер, доступен так же в Samsung GR VR);
  11. iOS Chrome (с полифилами на момент написания статьи);
  12. iOS Safari (с полифилами на момент написания…);
  13. Chrome (с полифилами на момент…);
  14. Firefox (с полифилами на…).

Полный список с таблицами совместимости можно посмотреть по ссылке webvr.rocks


Не забываем включить поддержку WebVR API.

Полифилы и вспомогательные библиотеки

Если ваше устройство не поддерживает WebVR API, то можно воспользоваться полифилом, который можно подключить на страницу, либо использовать специальное расширение для браузера. Ссылка на полифил: github.com/googlevr/webvr-polyfill

WebVR API Emulation for Chrome

Поставить можно по сслылке: chrome.google.com/webstore/detail/webvr-api-emulation/gbdnpaebafagioggnhkacnaaahpiefil

Про этот плагин стоит сказать пару слов отдельно. Он не просто добавляет эмуляцию WebVR API, но также позволяет делать различные манипуляции и интегрируется в DevTools.

WebVR-UI

Если ваше устройство не является VR девайсом (а браузер в смартфоне — это всего лишь браузер), то вы можете воссоздать VR интерфейс для переключения в режим хедсета, используя библиотеку webvr-ui. С помощью этой библиотеки вы сможете сделать красивый UI интерфейс с кнопками переключения в VR режим. Ссылка на проект: github.com/googlevr/webvr-ui

Добавив несколько строк кода:

var renderer = new THREE.WebGLRenderer(); var options = {}; var enterVR = new webvrui.EnterVRButton(renderer.domElement, options); document.body.appendChild(enterVR.domElement); 

мы можем получить такой вот интересный интерфейс для нашего WebVR проекта.

Эта библиотека совместима с фреймворком A-Frame, что очень классно. Вам достаточно добавить всего лишь атрибут в ваш код:

<a-scene webvr-ui>     ... </a-scene> 

И у вас будет доступен удобный VR интерфейс. Если будет доступен WebVR, то будет предложено перейти в VR режим, иначе будет предложено попробовать запустить ваше веб-приложение в режиме демонстрации без VR режима.

Данная библиотека гибко настраиваемая, так что вы можете делать свои кастомные кнопки.

Чем нам мир построить?

Чтобы влиться в мир VR, нужно научиться работать с 3D-графикой. Это кажется сложной задачей, если вы будете осваивать WebGL с нуля. Но проще всего взять готовые библиотеки, такие как Threejs, D3.js или специализированные фреймворки для работы с VR (такие, как A-Frame от команды Mozilla). Уже даже есть превью релиз React VR для поклонников React и всего, что выходит из недр FB. Но это тема отдельной статьи.

Верстаем VR мир

Используя фреймворк A-Frame, можно сверстать VR мир с минимальными усилиями. A-Frame — это HTML-фреймворк для создания веб-приложений и сайтов под виртуальную реальность. Если смотреть на результат в браузере, то это выглядит как веб-страница, которая представляет 3D- изображение с возможностью навигации и взаимодействия с объектами. Вся картинка отрисовывается при помощи WebGL, а основная задача фреймворка — это предоставить простой инструмент, который бы позволил создавать трехмерный мир привычным для фронтендеров, похожим на HTML-разметку, способом. Сам фреймворк базируется на Threejs и является более высокоуровневой надстройкой.

Фреймворк A-Frame создает 3D-сцену через набор геометрических примитивов. Вы можете также добавлять более сложные компоненты и даже дописывать свои, если базовых вам уже не хватает. Для объектов сцены доступны типичные геометрические свойства, такие как: местоположение, вращение, масштабирование, кроме того, можно описывать расположение камер и источников света.

У A-Frame есть хороший инспектор, позволяющий делать отладку 3D мира.

Много хороших примеров можно посмотреть по ссылке: aframe.io/examples

Они просты для понимания и, изучив их, можно очень быстро сделать свой первый «Hello VR world». A-Frame можно также использовать и для AR разработки. Если углубляться в A-Frame, то тут опять же можно наговорить на целую отдельную статью (которая появится, если будет интерес к данной тематике).

ReactVR

ReactVR — это фреймворк, базирующийся на Reactjs. Если будет интерес и пост наберет хороший рейтинг, сделаю отдельно статью про это… Пока просто оставлю ссылку: developer.oculus.com/blog/introducing-the-react-vr-pre-release

Если статья наберет хороший рейтинг, тем самым показав что читателям интересна эта тема, то я сделаю отдельно статью про это.

Можем ли обойтись без WebVR?

Как уже было сказано выше, сам WebVR API нужен только для работы с VR устройствами, а точнее, для получения характеристик о дисплеях и для рендеринга картинки. Но если мы говорим про Mobile VR, то физически мы работаем с 1м экраном. Но мы можем эмулировать стереопару, и WebVR API нам может помочь абстрагироваться и инкапсулировать работу с экраном таким образом, что мы будем как бы работать с двумя физическими дисплеями. При этом наш код будет кроссплатформенным, и мы сможем наше WebVR приложение запускать на Oculus в браузере Carmel, к примеру.

Пример 3D мира на Threejs с использованием WebVR API

Здесь покажу пример работы с бойлерплейтом, благодаря которому можно делать WebVR проекты, которые заведутся на всех браузерах. Даже в iOS.

Готовое демо: webvr.majorov.su/sample1

<!DOCTYPE html>  <html lang="en"> <head> 	<title>Web VR boilerplate demo</title> 	<meta charset="utf-8"> 	<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0, shrink-to-fit=no"> 	<meta name="mobile-web-app-capable" content="yes"> 	<meta name="apple-mobile-web-app-capable" content="yes"/> 	<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> 	<style> 		body { 			width: 100%; 			height: 100%; 			background-color: #000; 			color: #fff; 			margin: 0px; 			padding: 0; 			overflow: hidden; 		}  		/* Position the button on the bottom of the page. */ 		#ui { 			position: absolute; 			bottom: 10px; 			left: 50%; 			transform: translate(-50%, -50%); 			text-align: center; 			font-family: 'Karla', sans-serif; 			z-index: 1; 		}  		a { 			color: white; 		} 	</style> </head> <body> 	<div id="ui"> 		<div id="vr-button"></div> 		<a id="magic-window" href="#">Try it without a headset</a> 	</div> </body> <script>WebVRConfig = { BUFFER_SCALE: 0.5 }</script> <script src="node_modules/es6-promise/dist/es6-promise.min.js"></script> <script src="node_modules/three/build/three.min.js"></script> <script src="node_modules/three/examples/js/controls/VRControls.js"></script> <script src="node_modules/three/examples/js/effects/VREffect.js"></script> <script src="node_modules/webvr-polyfill/build/webvr-polyfill.min.js"></script> <script src="node_modules/webvr-ui/build/webvr-ui.min.js"></script> <script> 	var lastRenderTime = 0; 	// Текущий активный VRDisplay. 	var vrDisplay; 	var boxSize = 5; 	// Настройки для THREE.Objects. 	var scene; 	var cube; 	var controls; 	var effect; 	var camera; 	// VR UI Кнопка 	var vrButton;  	function onLoad() { 		// Настройка three.js WebGL рендера. 		var renderer = new THREE.WebGLRenderer({antialias: true}); 		renderer.setPixelRatio(window.devicePixelRatio);  		// Вставляем наш слой для рендера в DOM 		document.body.appendChild(renderer.domElement);  		// Создаем сцену 		scene = new THREE.Scene();  		// Создаем камеру 		var aspect = window.innerWidth / window.innerHeight; 		camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 10000);  		controls = new THREE.VRControls(camera); 		controls.standing = true; 		camera.position.y = controls.userHeight;  		// Добавляем VR stereo рендер 		effect = new THREE.VREffect(renderer); 		effect.setSize(window.innerWidth, window.innerHeight);  		var loader = new THREE.TextureLoader(); 		loader.load('img/box.png', onTextureLoaded);  		// Создаем 3D объекты 		var geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5); 		var textureLoader = new THREE.TextureLoader(); 		var texture0 = textureLoader.load('img/1.jpg'); 		var texture1 = textureLoader.load('img/1.jpg'); 		var texture2 = textureLoader.load('img/0.jpg'); 		var texture3 = textureLoader.load('img/0.jpg'); 		var texture4 = textureLoader.load('img/2.jpg'); 		var texture5 = textureLoader.load('img/0.jpg'); 		var materials = [ 			new THREE.MeshBasicMaterial({map: texture0}), 			new THREE.MeshBasicMaterial({map: texture1}), 			new THREE.MeshBasicMaterial({map: texture2}), 			new THREE.MeshBasicMaterial({map: texture3}), 			new THREE.MeshBasicMaterial({map: texture4}), 			new THREE.MeshBasicMaterial({map: texture5}) 		];  		var material = new THREE.MultiMaterial(materials); 		cube = new THREE.Mesh(geometry, material); 		cube.position.set(0, controls.userHeight, -1);  		scene.add(cube);  		window.addEventListener('resize', onResize, true); 		window.addEventListener('vrdisplaypresentchange', onResize, true);  		// Initialize the WebVR UI. 		var uiOptions = { 			color: 'black', 			background: 'white', 			corners: 'square' 		};  		vrButton = new webvrui.EnterVRButton(renderer.domElement, uiOptions); 		vrButton.on('exit', function () { 			camera.quaternion.set(0, 0, 0, 1); 			camera.position.set(0, controls.userHeight, 0); 		}); 		vrButton.on('hide', function () { 			document.getElementById('ui').style.display = 'none'; 		}); 		vrButton.on('show', function () { 			document.getElementById('ui').style.display = 'inherit'; 		}); 		document.getElementById('vr-button').appendChild(vrButton.domElement); 		document.getElementById('magic-window').addEventListener('click', function () { 			vrButton.requestEnterFullscreen(); 		}); 	}  	function onTextureLoaded(texture) { 		texture.wrapS = THREE.RepeatWrapping; 		texture.wrapT = THREE.RepeatWrapping; 		texture.repeat.set(boxSize, boxSize);  		var geometry = new THREE.BoxGeometry(boxSize, boxSize, boxSize); 		var material = new THREE.MeshBasicMaterial({ 			map: texture, 			color: 0x01BE00, 			side: THREE.BackSide 		});  		skybox = new THREE.Mesh(geometry, material); 		skybox.position.y = boxSize / 2; 		scene.add(skybox); 		setupStage(); 	}   	// Request animation frame loop function 	function animate(timestamp) { 		var delta = Math.min(timestamp - lastRenderTime, 500); 		lastRenderTime = timestamp; 		cube.rotation.y += delta * 0.0006; 		if (vrButton.isPresenting()) controls.update(); 		effect.render(scene, camera); 		vrDisplay.requestAnimationFrame(animate); 	}  	function onResize(e) { 		effect.setSize(window.innerWidth, window.innerHeight); 		camera.aspect = window.innerWidth / window.innerHeight; 		camera.updateProjectionMatrix(); 	}  	function setupStage() { 		navigator.getVRDisplays().then(function (displays) { 			if (displays.length > 0) { 				vrDisplay = displays[0]; 				if (vrDisplay.stageParameters) { 					setStageDimensions(vrDisplay.stageParameters); 				} 				vrDisplay.requestAnimationFrame(animate); 			} 		}); 	}  	function setStageDimensions(stage) { 		var material = skybox.material; 		scene.remove(skybox); 		var geometry = new THREE.BoxGeometry(stage.sizeX, boxSize, stage.sizeZ); 		skybox = new THREE.Mesh(geometry, material); 		skybox.position.y = boxSize / 2; 		scene.add(skybox); 		cube.position.set(0, controls.userHeight, 0); 	}  	window.addEventListener('load', onLoad); </script> </html> 

В следующих статьях можем более подробно разобраться в деталях разработки под WebVR. Ссылка на гитхаб с бойлерплейтом github.com/borismus/webvr-boilerplate

А что там с Web AR ?

Web AR(Augmented Reality) — также возможно создавать в браузере. Но «WebAR API» не существует, это просто обозначение дополненной реальности, реализованной на веб-технологиях.

Технически вся работа точно такая же, как и работа с WebVR, но дополнительно вы получаете видеопоток с веб-камеры, используя WebRTC. Дополнительно пишите логику покадровой обработки, для поиска нужных объектов. А далее, как и в случае с WebVR — уже рисуете 3D сцену на фоне видеопотока. И, надо сказать, что AR не обязательно подразумевает наличие хеадсета. Вспомним “Pockemon GO!” — это AR проект, но без VR шлема. Отсюда следует, что, чтобы создать AR проект, не обязательно иметь VR шлем. Но при этом VR и AR понятия могут пересекаются по некоторым параметрам и технологиям.

Что с поддержкой?

Здесь все упирается, в первую очередь, в поддержку WebRTC. Поэтому можно сказать, что Web AR можно реализовать на всех Android устройствах. В iOS — нет, но если очень хочется, то…

Как быть с iOS устройствами?

Если речь идет о WebVR — то в iOS устройствах все можно реализовать через полифилы (или вовсе обойтись без WebVR API, описывая все самостоятельно и реализуя отслеживание действий через акселерометр и прочие датчики, самому бить картинку и эмулировать два дисплея). Если говорить про AR, тут все плохо, так как нет поддержки WebRTC. Но есть такой проект как Argonjs. Это проект, который состоит из фреймворка, базирующегося на A-Frame, и, внимание, специального браузера.

Argon 4 by Georgia Tech

Ссылка на проект argonjs.io
Демо argonjs.io/samples

Суть работы браузера проста: есть два слоя. Один слой — это Webkit движок, второй слой (подложка) — это вывод видеопотока с камеры. В браузере есть свой API, чем-то похоже на работу самых первых версий PhoneGap (если кто-то пробовал на заре развития этого проекта, году эдак в 2008, тогда это был специальный браузер под iPhone с расширенным JS API).

При этом Argonjs можно использовать и для VR разработки под iOS. Точнее для обкатки MVP. Если все же нужно разрабатывать кроссплатформенное приложение под VR/AR на JS, то можно смотреть в сторону React Native вкупе с React VR либо попробовать упаковать все в PhoneGap.

Важно! В AppStore есть несколько версий браузера. На данный момент надо качать версию 4, не ниже, иначе фреймворк не заведется: itunes.apple.com/us/app/argon4/id1089308600?mt=8

А что там с геймпадами?

Это дополнительная тема для изучения. Разбираемся с Bluetooth API и Gamepad API. Они есть в браузерах и поддерживаются как на десктопе так и на мобильных устройствах (опять же есть нюансы и список фаворитов среди браузеров). Изучаем документацию и учимся с ними работать. Про геймпады и взаимодействие с VR миром — это тема отдельной статьи (или даже нескольких), в двух словах не рассказать.

Юзкейсы и применение

Если говорить про Туту.ру, то у нас уже есть идеи юзкейсов для применения VR/AR на практике. К примеру, это 3D галереи для проекта Туры. Галереи 360 с небольшой доработкой можно адаптировать под VR шлемы, и все, у кого дома есть VR Box, могли бы “осмотреть” будущий отель и пляж с эффектом присутствия. Такую же технику можно применить и к 3D галереям для проекта Поезда, где можно посмотреть вагон изнутри и выбрать место прямо из VR шлема в Сапсане. Таким же образом, в будущем, можно было бы сделать и для междугородних автобусов. А для проекта экскурсии, который у нас также имеется, можно было бы делать демо-превью будущей экскурсии.

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

В общем, есть полет для фантазии. Это я рассказал юзкейсы именно в контексте нашей компании, и они не все здесь перечислены. Если же говорить глобально, то юзкейсов можно придумать с вагон и маленькую тележку 🙂

Ссылки по теме

ссылка на оригинал статьи https://habrahabr.ru/post/324570/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *