Виртуальная и дополненные реальности активно развиваются и начинают предъявлять права на захват мира. Причем применение этих технологий разнообразно и не ограничивается только играми. А с появлением инструментов для работы с 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 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);

Эта библиотека совместима с фреймворком 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 мира.



Много хороших примеров можно посмотреть тут.

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

React VR


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, то в оффлайн офисе можно было бы разместить информационные стенды и различные плюхи-приколюхи, для развлечения клиентов. Если брошюру клиент может пропустить, потому что реакция на рекламную макулатуру не всегда позитивна, то ту же рекламу, показанную через призму новых технологий, клиент может с удовольствием воспринять и остаться доволен.

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

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


Поделиться с друзьями
-->

Комментарии (1)


  1. TimsTims
    22.03.2017 18:42
    +3

    ту же рекламу, показанную через призму новых технологий, клиент может с удовольствием воспринять и остаться доволен

    сразу вспомнил футураму)


    А еще серия «Оракул», где рекламу показывают людям во сне, т.к. людям всё-равно нечего делать, когда они спят)