加载中

Virtual reality is set to be worth up to $7 billion by 2020. The web is definitely not going to remain an exclusively 2D environment during this time. In fact, there are already a few simple ways to bring VR into the browser. It is also incredibly fun to work with!

To begin your development adventure into the Virtual Web, there are three potential ways to do this:

  • JavaScript, Three.js and Watching Device Orientation

  • JavaScript, Three.js and WebVR (My new preferred method!)

  • CSS and WebVR (still very early days)

I’ll go over each one and show a short summary of how each works.

有人认为虚拟现实将在 2020 年达到 70 亿美元的价值。在那之前,web 肯定不会一直停留于 2D 环境。实际上,已经有一些简单的方法可以将虚拟现实带进浏览器了。而且那弄起来也非常有趣!

要开始你的虚拟 Web 开发之旅,有这么三种可行的方式:

  • JavaScript,Three.js 和监视设备朝向

  • JavaScript,Three.js 和 WebVR(我最近比较喜欢的方式)

  • CSS 和 WebVR(时日尚早)

我会将每一种方式都过一遍,简要展示下它们各自是如何工作的。

JavaScript, Three.js and Watching Device Orientation

One of the ways that most browser based virtual reality projects work at the moment is via the deviceorientation browser event. This tells the browser how the device is oriented and allows the browser to pick up if it has been rotated or tilted. This functionality within a VR perspective allows you to detect when someone looks around and adjust the camera to follow their gaze.

To achieve a wonderful 3D scene within the browser, we use three.js, a JavaScript framework that makes it easy to create 3D shapes and scenes. It takes most of the complexity out of putting together a 3D experience and allows you to focus on what you are trying to put together within your scene.

JavaScript,Three.js 和监视设备朝向

当前,大多数基于浏览器的虚拟现实项目都是利用浏览器的 deviceorientation 事件。此事件告诉浏览器设备的朝向,而且允许浏览器在设备旋转或倾斜时有所动作。从虚拟现实的角度看,此功能允许你侦测到某人看向某个方向,然后你可以调整摄像头以跟随他的视线。

为了在浏览器里获得良好的 3D 场景,我们使用一个可以方便地创建 3D 形状和场景的 JavaScript 框架three.js。它封装了创建 3D 内容的大部分复杂性,让你可以专注于把你希望的东西放进你的场景。

I’ve written two demos here at SitePoint that use the Device Orientation method:

If you are new to three.js and how to put together a scene, I’d recommend taking a look at the above two articles for a more in depth introduction into this method. I will cover key concepts here, however it’ll be at a higher level.

The key components of each of these involve the following JavaScript files (you can get these files from the example demos above and also will find them in the three.js examples download):

  • three.min.js – Our three.js framework

  • DeviceOrientationControls.js – This is the three.js plugin that provides the Device Orientation we discussed above. It moves our camera to meet the movements of our device.

  • OrbitControls.js – This is a backup controller that lets the user move the camera using the mouse instead if we don’t have a device that has access to the Device Orientation event.

  • StereoEffect.js – A three.js effect that splits the screen into a stereoscopic image angled slightly differently for each eye just like in VR. This creates the actual VR split screen without us needing to do anything complicated.

我在 SitePoint 上写过两个使用设备朝向方法的示例:

如果你不熟悉 three.js 和组建场景,我推荐你看一下上面的两篇文章以更深入的理解此方法。我将只大致介绍下主要概念。

下面是要用到的关键 JavaScript 文件(你可以从上面的示例中获取,也可以 从three.js 例子下载):

  • three.min.js– three.js 框架

  • DeviceOrientationControls.js– 这是一个 three.js 插件,它帮助我们完成之前提到过的监视设备朝向,可以另摄像头根据设备的移动进行调整。

  • OrbitControls.js– 这是一个备用的控制器,它可以在没有设备朝向事件的时候用鼠标调整摄像头。

  • StereoEffect.js– 这是一个 three.js 的效果插件,可以针对每只眼睛对画面进行细微的角度调整,就像虚拟现实该有的立体效果。这使得我们不用做任何复杂的工作,就可以创造实打实的虚拟现实分屏效果。

Device Orientation

The code to enable Device Orientation controls looks like so:

function setOrientationControls(e) {
  if (!e.alpha) {
    return;
  }
  controls = new THREE.DeviceOrientationControls(camera, true);
  controls.connect();
  controls.update();
  element.addEventListener('click', fullscreen, false);
  window.removeEventListener('deviceorientation', setOrientationControls, true);
}
window.addEventListener('deviceorientation', setOrientationControls, true);
function fullscreen() {
  if (container.requestFullscreen) {
    container.requestFullscreen();
  } else if (container.msRequestFullscreen) {
    container.msRequestFullscreen();
  } else if (container.mozRequestFullScreen) {
    container.mozRequestFullScreen();
  } else if (container.webkitRequestFullscreen) {
    container.webkitRequestFullscreen();
  }
}

The DeviceOrientation event listener provides an alpha, beta and gamma value when it has a compatible device. If we don’t have any alpha value, it doesn’t change our controls to use Device Orientation so that we can use Orbit Controls instead.

If it does have this alpha value, then we create a Device Orientation control and provide it our camera variable to control. We also set it to set our scene to fullscreen if the user taps the screen (we don’t want to be staring at the browser’s address bar when in VR).

设备朝向

使用设备朝向控制的代码大致如下:

function setOrientationControls(e) {
  if (!e.alpha) {
    return;
  }
  controls = new THREE.DeviceOrientationControls(camera, true);
  controls.connect();
  controls.update();
  element.addEventListener('click', fullscreen, false);
  window.removeEventListener('deviceorientation', setOrientationControls, true);
}
window.addEventListener('deviceorientation', setOrientationControls, true);
function fullscreen() {
  if (container.requestFullscreen) {
    container.requestFullscreen();
  } else if (container.msRequestFullscreen) {
    container.msRequestFullscreen();
  } else if (container.mozRequestFullScreen) {
    container.mozRequestFullScreen();
  } else if (container.webkitRequestFullscreen) {
    container.webkitRequestFullscreen();
  }
}

在可用设备上,设备朝向事件监听器提供一组 alpha,beta 和 gamma 值。如果没有 alpha 值就不能通过设备朝向进行控制,转而替代的是轨道控制。

如果有 alpha 值,那么我们就可以使用设备朝向控制摄像头。如果用户轻击屏幕,我们还可将场景在全屏模式下呈现(我们可不想在虚拟现实下看到浏览器地址栏)。

Orbit Controls

If that alpha value isn’t present and we don’t have access the device’s Device Orientation event, this technique instead provides a control to move the camera via dragging it around with the mouse. This looks like so:

controls = new THREE.OrbitControls(camera, element);
controls.target.set(
  camera.position.x,
  camera.position.y,
  camera.position.z
);
controls.noPan = true;
controls.noZoom = true;

The main things that might be confusing from the code above is the noPan and noZoom. Basically, we don’t want to move physically around the scene via the mouse and we don’t want to be able to zoom in or out – we only want to look around.

轨道控制

如果 alpha 值不存在,我们也就不可以访问设备的定位事件,这替代了通过摄像头拖拽鼠标的技术。这看起来就像这样:

controls = new THREE.OrbitControls(camera, element);
controls.target.set(
  camera.position.x,
  camera.position.y,
  camera.position.z
);
controls.noPan = true;
controls.noZoom = true;

主要可能混乱的代码是上面的 noPan 和 noZoom。基本上,我们不需要通过鼠标移动身体的场景,我们也不希望能够放大或缩小 —— 我只是想环视。

Stereo Effect

In order to use the stereo effect, we define it like so:

effect = new THREE.StereoEffect(renderer);

Then on resize of the window, we update its size:

effect.setSize(width, height);

Within each requestAnimationFrame we set the scene to render through our effect:

effect.render(scene, camera);

That is the basics of how the Device Orientation style of achieving VR works. It can be effective for a nice and simple implementation with Google Cardboard, however it isn’t quite as effective on the Oculus Rift. The next approach is much better for the Rift.

JavaScript, Three.js and WebVR

Looking to access VR headset orientation like the Oculus Rift? WebVR is the way to do it at the moment. WebVR is an early and experimental Javascript API that provides access to the features of Virtual Reality devices like Oculus Rift and Google Cardboard. At the moment, it is available on Firefox Nightly and a few experimental builds of Mobile Chrome and Chromium. One thing to keep in mind is that it the spec is still in draft and is subject to change, so experiment with it but know that you may need to adjust things over time.

立体效果

为了使用立体效果,我们先这么定义:

effect = new THREE.StereoEffect(renderer);

然后再窗口重设尺寸时,相应更新它的尺寸:

effect.setSize(width, height);

在每次 requestAnimationFrame 的时候,使用效果渲染场景:

effect.render(scene, camera);

以上便是使用设备朝向方法达到虚拟现实的基本方法。这种方法对于简易的 Google Cardboard 实现效率还可以,但在 Oculus Rift 上就不是太高效了。下面要介绍的方法在 Rift 上表现得要好得多。

JavaScript,Three.js 和 WebVR

对像是 Oculus Rift 这样的头戴式虚拟设备的朝向感兴趣?WebVR 是当前可行的方法。WebVR 是一种先锋的实验性质的 JavaScript 的 API,它提供访问 Oculus Rift 和 Google Cardboard 等虚拟设备的能力。当前,它在 Firefox Nightly 和一些experimental builds of Mobile Chrome and Chromium 上可用。需要记住的一点是,WebVR 的细节依然在草稿阶段且随时可能会改变,所以可以拿它做一些实验,而且过些时候你可能需要做一些调整。

Overall, the WebVR API provides access to the VR device information via:

navigator.getVRDevices

I won’t go into lots of technical details here (I’ll cover this in more detail in its own future SitePoint article!), if you’re interested in finding out more check out the WebVR editor’s draft. The reason I won’t go into detail with it is that there is a much easier method to implement the API.

This aforementioned easier method to implement the WebVR API is to use the WebVR Boilerplate from Boris Smus. It provides a good level of baseline functionality that implements WebVR and gracefully degrades the experience for different devices. It is currently the nicest web VR implementation I’ve seen. If you are looking to build a VR experience for the web, this is currently the best place to start!

To start using this method, download the WebVR Boilerplate on Github.

总之,WebVR API 可以让你通过如下方式访问虚拟现实设备:

navigator.getVRDevices

我不会在这里讲太多细节(在之后 SitePoint 上的文章中我会讲更多细节的东西),如果你对细节感兴趣的话可以看看 the WebVR editor’s draft。我不讲细节的原因是有更简单的方法实现 API。

上面说的更简单的实现 WebVR API 的方法是使用 WebVR Boilerplate from Boris Smus。在不同的设备上,它可以保证基本的 WebVR 功能,同时考虑到用户体验上的优雅降级。它是我至今经过的最好的 web 虚拟现实实现。如果你在找寻基于 web 的虚拟现实实现方案,这便是当前最好的选择。

要开始使用此方法,先下载 WebVR Boilerplate on Github

You can focus on editing the index.html and using all of the files in that set up, or you can implement the specific plugins into your own project from scratch. If you’d like to compare the differences in each implementation, I’ve migrated my Visualizing a Twitter Stream in VR with Three.js and Node example from above into a WebVR powered Twitter Stream in VR.

To include this project into your own from scratch, the files you’ll want to have are:

  • three.min.js – Our three.js framework of course

  • VRControls.js – A three.js plugin for VR controls via WebVR (this can be found in bower_components/threejs/examples/js/controls/VRControls.js in the Boilerplate project)

  • VREffect.js – A three.js plugin for the VR effect itself that displays the scene for an Oculus Rift (this can be found in bower_components/threejs/examples/js/effects/VREffect.js in the Boilerplate project)

  • webvr-polyfill.js – This is a polyfill for browsers which don’t fully support WebVR just yet (this can be found on GitHub and also in bower_components/webvr-polyfill/build/webvr-polyfill.js in the Boilerplate code)

  • webvr-manager.js – This is part of the Boilerplate code which manages everything for you, including providing a way to enter and exit VR mode (this can be found in build/webvr-manager.js)

Implementing it requires only a few adjustments from the Device Orientation method. Here’s an overview for those looking to try this method:

你可以使用其中的文件,专心编辑 index.html,或者你也可以从草稿开始实现特定的插件。如果你想比较两者的区别,我已经把上面提过的 Visualizing a Twitter Stream in VR with Three.js and Node迁移到 WebVR powered Twitter Stream in VR 了。

要把此项目加到你自己的草稿上,你需要这些文件:

  • three.min.js – 当然是我们的 three.js 框架

  • VRControls.js – 一个 three.js 插件,用于通过 WebVR 进行虚拟现实的控制 (可以从样板项目找到 bower_components/threejs/examples/js/controls/VRControls.js)

  • VREffect.js – 一个 three.js 插件,用于在 Oculus Rift 上显示虚拟现实效果的画面(可以从样板项目找到 bower_components/threejs/examples/js/effects/VREffect.js)

  • webvr-polyfill.js – 这是一个用于对 WebVR 支持不完善的浏览器的填充工具(可以从GitHub 上找到,或者从样板项目找到 bower_components/webvr-polyfill/build/webvr-polyfill.js)

  • webvr-manager.js – 这是样板代码的一部分,它管理所有的东西,包括提供进入和离开虚拟现实模式的方法(可以从 build/webvr-manager.js 找到)

实现它仅需要稍微调整下设备朝向方法。以下是给想尝试的朋友的一份综述:

Controls

The VR controls are quite simple to set up. We can just assign a new VRControls object to the controls variable we used earlier. The orbit controls and device orientation controls should not be necessary as the Boilerplate should now take care of browsers without VR capabilities. This means your scene should still work quite well on Google Cardboard too!

controls = new THREE.VRControls(camera);

VR Effect

The effect is very similar to implement as the StereoEffect was. Just replace that effect with our new VREffect one:

effect = new THREE.VREffect(renderer);
effect.setSize(window.innerWidth, window.innerHeight);

However, we do not render through that effect in this method. Instead, we render through our VR manager.

控制器

VR 控制器是很容易创建的,我们只需要通过创建一个 VRControls 对象给我们之前使用的 controls 变量就可以了。由于 Boilerplate 目前应该注意浏览器没有 VR 功能,因此轨迹控制器和设备方式控制器不是必须的。这意味着你的动画应该依然在 Google Cardboard 上能够很好的运行

controls = new THREE.VRControls(camera);

VR Effect

Effect 是非常类似于实现了 StereoEffect 类的类。只不过用新的 VREffect 类替换了原来的:

effect = new THREE.VREffect(renderer);
effect.setSize(window.innerWidth, window.innerHeight);

然而,在这个方法里我们不会通过 Effect 渲染,而是,通过我们的 VR 管理器来渲染。

VR Manager

The VR manager takes care of all our VR entering/exiting and so forth, so this is where our scene is finally rendered. We initially set it up via the following:

manager = new WebVRManager(renderer, effect, {hideButton: false});

The VR manager provides a button which lets the user enter VR mode if they are on a compatible browser, or full screen if their browser isn’t capable of VR (full screen is what we want for mobile). The hideButton parameter says whether we want to hide that button or not. We definitely do not want to hide it!

Our render call then looks like so, it uses a timestamp variable that comes from our three.js’ update() function:

function update(timestamp) {
  controls.update();

  manager.render(scene, camera, timestamp);}

With all of that in place, you should have a working VR implementation that translates itself into various formats depending on the device.

VR管理器

VR 管理器关注我们所有进入或退出 VR 等等诸如此类的,因此这是我们的场景最终渲染的地方。我们通过下面的方式初始化管理器:

manager = new WebVRManager(renderer, effect, {hideButton: false});

如果VR管理器在一个可兼容的浏览器里,那么它会提供一个可以让我们进入VR 模块的按钮,如果它们的浏览器不支持 VR,那么进入全屏(全屏是我们为移动端准备的)。hideButton 参数表示我们是否想隐藏按钮或不隐藏按钮,我们定义为不隐藏!

我们像这样去调用渲染,它使用的 timestamp 变量是来自 three.js 的 update() 方法:

function update(timestamp) {
  controls.update();

  manager.render(scene, camera, timestamp);}

在所有的地方,你都应该让 VR 根据设备的不同而转化它本身的实现。

返回顶部
顶部