Since v2.5 Babylon.js supports WebVR using the WebVRFreeCamera.
In Babylon v3.0 we fully support the WebVR 1.1 specifications (https://w3c.github.io/webvr/) which is supported by the latest version of Microsoft Edge, Chromium and Firefox.
The WebVR camera is Babylon's simple interface to interaction with Windows Mixed Reality, HTC Vive, Oculus Rift, Google Daydream and Samsung GearVR.
Babylon.js also supports the VR devices' controllers - The Windows Mixed Reality controllers, HTC Vive's controllers, the Oculus touch, GearVR controller and Daydream controller - using the gamepad extension. Further details below.
To quickly get started creating WebVR scene the WebVR Experience Helper class can be used to automatically setup the WebVR camera and enable other features such as teleportation out of the box.
WebVR 1.1 is enabled in specific versions of Microsoft Edge, Chromium and Firefox. To get constant status updates, please visit WebVR rocks at https://webvr.rocks/ . We support any browser that implements WebVR 1.1.
The WebVR controllers are offered in browsers that support the WebVR gamepad extensions - https://w3c.github.io/gamepad/extensions.html . In Chromium you must enable this API in chrome://flags in order to get it working. Make sure to visit https://mozvr.com/ for full installation instructions.
The WebVRFreeCamera is being initialized the same as a standard free camera:
var camera = new BABYLON.WebVRFreeCamera("camera1", new BABYLON.Vector3(0, 0, 0), scene);
This will initialize a new WebVR camera and will enable WebVR in the engine.
Just like any other camera, to get the camera working correctly with user input and interactions, we will need to attach the camera (and the VR device) to the canvas and the scene. To do that we use the same method we know from the free camera:
camera.attachControl(canvas, true);
Most browsers only support attaching the VR device to the scene during a user interaction (a mouse click, for example). To get that working correctly, a simple solution would be:
scene.onPointerDown = function () {
scene.onPointerDown = undefined
camera.attachControl(canvas, true);
}
What it does is attach control once the user click on the canvas, and disables the onPointerDown callback.
This can be done with an HTML or a Canvas2D button as well, and using vanilla javascript event listeners. Any intentional user interaction is allowed. A mouse-move event will not trigger it, so don't bother trying. A simple example would be:
// after creating a button with vrButton as ID:
let button = document.getElementById('vrButton');
function attachWebVR() {
camera.attachControl(canvas, true);
window.removeEventListener('click', attachWebVR, false);
}
button.addEventListener('click', attachWebVR, false );
Don't forget to remove the event listener, other wise any click on the button will trigger the attach function. It won't attach again, but it a waste of function calls and is not needed.
You should now be able to see your scene in the WebVR device. If not, go to troubleshooting!
The WebVR camera is an extended FreeCamera. Apart from all of the abilities a standard FreeCamera has, the WebVR camera has 2 major extensions - an extra position and an extra rotation, which are the pose data broadcasted by the VR device connected to the browser. This means that the camera has actually two transformation - one is controlled by you, and the other by the device. They are accumulated - position is being added and rotation multiplied - in order to combine the developer's input and the VR device's pose data.
To understand that think of your head and your body. Without moving your body, your head can move in all directions, and rotate in all directions. The WebVR device is your head. Your body is the regular position and rotationQuaternion we all know and love. If you rotate your body, the head rotates with it. But if you move the head, the body stays in the same position.
This is exactly how you should see the WebVR extra transformation - your head position is set by the VR device (and cannot be interfered with). Your body (or position in the world) is fully controlled by you.
This allows you to use the same code you use for a game based on the FreeCamera with the WebVR camera. the only difference is that the user will have the ability to rotate the camera locally using the VR device and not the mouse.
This also allows the WebVR to be controlled by the same input devices that control the FreeCamera - keyboard, mouse (with rotation exception), XBOX controller and so on.
The device's "front" position is set by the device itself (it is set during the device's setup and has not a lot to do with WebVR directly). The developer, however, has the ability to change the "front" rotation with a simple function call:
camera.resetToCurrentRotation()
.
This will set the current Y axis (and Y axis direction only!!) to be the current front rotation of the user.
camera._vrDevice
, a public hidden member in the camera.camera.rawPose
. The rawPose has the following interface (a dream for physics lovers!):export interface DevicePose {
readonly position?: Float32Array;
readonly linearVelocity?: Float32Array;
readonly linearAcceleration?: Float32Array;
readonly orientation?: Float32Array;
readonly angularVelocity?: Float32Array;
readonly angularAcceleration?: Float32Array;
}
Note: Raw pose values are not modified based on the webVRCamera's rotation or position. To reference modified position and rotation in Babylon space, use the devicePosition and deviceRotationQuaternion fields.
webVRCamera.devicePosition
webVRCamera.deviceRotationQuaternion
webVRCamera.leftController.devicePosition
webVRCamera.leftController.deviceRotationQuaternion
Each VR device currently available (Windows Mixed Reality, Oculus Rift, Vive, Daydream and GearVR) has controllers that complement its usage. Windows Mixed Reality controllers, Vive controllers, Oculus touch controllers, Daydream Controller and GearVR Controller are supported by using the gamepad extensions.
During the WebVRFreeCamera initialization it will attempt to attach the controllers and detect them if found. If found, the controllers will be located at camera.controllers
which is an array that will either have a length of 2 or 0 (GearVR and Daydream support only 1 controller). If the controllers are attached and were not detected, you could also try to manually call camera.initControllers()
at a future time.
To fire a callback when the controllers are found you can use the optional camera.onControllersAttached
callback:
onControllersAttached = function(controllers) {
console.log(controllers.length === 2); // outputs true;
}
Initializing the controllers using the camera will also attach them to the camera, which will allow moving the controllers together with the WebVR camera, if moved by the user.
There are a few high level implementations that are automatically assigned to a WebVR controller:
WindowsMotionController
for the Windows Mixed Reality controllers.
OculusTouchController
for the Oculus touch.
ViveController
for the Vive controllers.
GearVRController
for the Samsung Gear VR controller.
DaydreamController
for the Google Daydream controller.
each extends the WebVRController
class, which extends the PoseEnabledController
.
To cut a long story short - Each controller is assigned the same set of functions, with the only different being the button mappings. The type of the device can be retrieved using controller.controllerType
, which has the following values:
export enum PoseEnabledControllerType {
VIVE,
OCULUS,
WINDOWS,
GEAR_VR,
DAYDREAM,
GENERIC
}
This enum will be extended when needed.
A controller button has the following set of data:
interface ExtendedGamepadButton extends GamepadButton {
readonly pressed: boolean;
readonly touched: boolean;
readonly value: number;
}
These values will be sent to the observers of any specific button when either on of them was changed.
The controllers also have Axes-data, which can be compared to the stick value of an x-box controller. They consist of a 2D vector (with x and y values). Stick values (SHOULD BE) are between -1, -1 and 1, 1, with 0,0 being the default value.
Abstract mapping
The following observables exist on all types of WebVR controllers, in case you wish to develop an abstract solution to all VR devices and not focus on a specific device:
onTriggerStateChangedObservable
is the main trigger observableonMainButtonStateChangedObservable
the main button observable onSecondaryButtonStateChangedObservable
- you get the point...onPadStateChangedObservable
- stick-button observable (NOT the Stick Values)onPadValuesChangedObservable
- stick values changed observableTo use any of them, simple register a new function with the desired observable. For example, to monitor the trigger and observe pad value changes:
controller.onPadValuesChangedObservable.add(function (stateObject) {
console.log(stateObject); // {x: 0.1, y: -0.3}
});
controller.onTriggerStateChangedObservable.add(function (stateObject) {
let value = stateObject.value;
console.log(value);
});
Windows Mixed Reality Controller mapping
The Windows Mixed Reality controller supports:
onPadValuesChangedObservable
.onPadStateChangedObservable
.onTouchpadValuesChangedObservable
and onTrackpadValuesChangedObservable
(aliases).onTouchpadButtonStateChangedObservable
and onTrackpadChangedObservable
(aliases).onTriggerStateChangedObservable
onMainButtonStateChangedObservable
and onGripButtonStateChangedObservable
(aliases)onSecondaryButtonStateChangedObservable
and onMenuButtonStateChangedObservable
(aliases).Vive Controller mapping
The vive supports:
onPadStateChangedObservable
onTriggerStateChangedObservable
onMainButtonStateChangedObservable
, onRightButtonStateChangedObservable
and onLeftButtonStateChangedObservable
(aliases to the same observable object!);onSecondaryButtonStateChangedObservable
and onMenuButtonStateChangedObservable
(aliases).Oculus touch mapping
The oculus touch supports 6 different buttons:
onPadStateChangedObservable
.onTriggerStateChangedObservable
.onSecondaryTriggerStateChangedObservable
.onMainButtonStateChangedObservable
, onAButtonStateChangedObservable
on the right hand and onXButtonStateChangedObservable
on the left hand.onSecondaryButtonStateChangedObservable
, onBButtonStateChangedObservable
on the right hand and onYButtonStateChangedObservable
on the left hand.onThumbRestChangedObservable
.Gear VR Controller mapping
The Gear VR controller supports:
onPadValuesChangedObservable
and onTrackpadChangedObservable
onTriggerStateChangedObservable
Google Daydream Controller mapping
The Google Daydream controller supports:
onPadValuesChangedObservable
and onTriggerStateChangedObservable
note: The Daydream controller home and app buttons are not mapped in WebVR.
Instead of forcing you to use the controller meshes (which will prevent you from implementing a single app for many types of devices), we have decided to allow you to attach the controller to a mesh. This will make the controller the mesh's "parent" (but not using the parenting system! As a controller is not a node). The controller's actions (rotation and position changes) will reflect directly to the mesh.
To attach the controller to a mesh:
controller.attachToMesh(mesh);
Note that this will create a new quaternion to the mesh .
Controllers without WebVR camera
The controllers can also be initialized without using a WebVR camera, which means - you can use them to control your regular WebGL game or 3D application.
To do that, simply initialize the Gamepads Class:
new BABYLON.Gamepads((gp) => {
if (gp.type === BABYLON.Gamepad.POSE_ENABLED) {
// Do something with the controller!
}
});
Note that the position will be relative to the initial VR Device that is related to those controllers.
Pose data
Just like the WebVR camera, the controllers export their (right handed!!) raw pose data. The data is updated each frame at controller.rawPose
.
Enjoy!
My WebVR camera is not working!!
Seems like a very common problem - a WebVRFreeCamera class is initialized, but you can't see a thing in the device.
navigator.getVRDevices().then((vrs) => {console.log(vrs.length)})
. If you got 0 or an error, the device is not properly connected.The camera's rotation is changing, but i can't see a thing in my display
This error occurs when you didn't attach control to the VR device.
My (Vive) controllers are not detected!! HELP!!!!
Ah, I know this problem.
camera.initControllers()
!navigator.getGamepads()
in your console. Is the list empty? are there controllers in the list? what controllers?Gear VR or Daydream controller models are not showing
These are 3 DoF devices (no position). The models positions aren't yet determined, but you have the rays from controller orientation and functional trigger buttons.