API

WebXR Movement

Movement Module

The movement feature allows movement in the scene with controllers. It is separate from the teleportation module and is not designed to be used at the same time.

In order to enable this feature you must first ensure that teleportation is not switched on.

Teleportation can be disabled in the default XR experience:

const xr = await scene.createDefaultXRExperienceAsync({
disableTeleportation: true,
});

You can also disable teleportation manually before enabling the movement feature.

import { WebXRFeatureName } from "@babylonjs/core/XR/webXRFeaturesManager";
const featureManager = xrHelper.baseExperience.featuresManager;
featureManager.disableFeature(WebXRFeatureName.TELEPORTATION);

The movement feature enables the camera's position to be changed with the controllers. Default configuration (can be changed in the options below):

  1. Left controller - rotate counterclockwise or clockwise
  2. Right controller - move forward/backward/left/right
import { WebXRFeatureName } from "@babylonjs/core/XR/webXRFeaturesManager";
const featureManager = xrHelper.baseExperience.featuresManager;
featureManager.enableFeature(WebXRFeatureName.MOVEMENT, "latest", {
xrInput: xrHelper.input,
});
Movement with controllers

It is also possible to use the controller to set the movement direction. To do that, you need to disable the head-direction settings. You can optionally define which hand will control the rotation:

import { WebXRFeatureName } from "@babylonjs/core/XR/webXRFeaturesManager";
const featureManager = xrHelper.baseExperience.featuresManager;
const movementFeature = featureManager.enableFeature(WebXRFeatureName.MOVEMENT, "latest", {
xrInput: xr.input,
// add options here
movementOrientationFollowsViewerPose: false, // default true
movementOrientationFollowsController: true, // enable controller direction
orientationPreferredHandedness: "left", // the preferred hand for rotation. Defaults to right. If hand is not found it will use the first found controller.
});
Movement with controllers, direction with controller

Movement Configuration Options

The current options for the plugin can always be found in the WebXR movement feature source code. Most of them are explained here.

One important option is movementOrientationFollowsViewerPose, which defaults to true. When configured to false, the forward direction will not adjust to the viewer pose, but only to the controller rotation. This can be useful for experiences where the viewer pose should not affect movement direction. For example, if you are moving forward and look left, you should not drift left but continue straight. You can try this in the playground above by changing the option.

The controllers themselves can be configured differently. For example, if you want to swap which hand controls rotation and which controls movement, override the customRegistrationConfigurations array. The feature handles movement and rotation state automatically and ignores them when rotation (rotationEnabled) or movement (movementEnabled) is not enabled. Speed is controlled by rotationSpeed and movementSpeed.

This swaps the handedness of the default configuration while maintaining the feature sensitivity thresholds:

import { WebXRControllerComponent } from "@babylonjs/core/XR/motionController/webXRControllerComponent";
import { WebXRFeatureName } from "@babylonjs/core/XR/webXRFeaturesManager";
const swappedHandednessConfiguration = [
{
allowedComponentTypes: [WebXRControllerComponent.THUMBSTICK_TYPE, WebXRControllerComponent.TOUCHPAD_TYPE],
forceHandedness: "right",
axisChangedHandler: (axes, movementState, featureContext, xrInput) => {
movementState.rotateX = Math.abs(axes.x) > featureContext.rotationThreshold ? axes.x : 0;
movementState.rotateY = Math.abs(axes.y) > featureContext.rotationThreshold ? axes.y : 0;
},
},
{
allowedComponentTypes: [WebXRControllerComponent.THUMBSTICK_TYPE, WebXRControllerComponent.TOUCHPAD_TYPE],
forceHandedness: "left",
axisChangedHandler: (axes, movementState, featureContext, xrInput) => {
movementState.moveX = Math.abs(axes.x) > featureContext.movementThreshold ? axes.x : 0;
movementState.moveY = Math.abs(axes.y) > featureContext.movementThreshold ? axes.y : 0;
},
},
];
const featureManager = xrHelper.baseExperience.featuresManager;
featureManager.enableFeature(WebXRFeatureName.MOVEMENT, "latest", {
xrInput: xrHelper.input,
customRegistrationConfigurations: swappedHandednessConfiguration,
});

Other useful options are to change movement and rotation speed and to enable/disable movement (movementEnabled) and rotation (rotationEnabled), but these ones are also available on the feature itself to change at runtime. The threshold options determine the sensitivity when the input is accepted - the default is 0.25, which prevents accidental movements and jittering.

Walking Locomotion

WebXRWalkingLocomition is an experimental Babylon.js capability which enables users to traverse VR spaces by "walking in place."

import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
import { WebXRFeatureName } from "@babylonjs/core/XR/webXRFeaturesManager";
scene.createDefaultXRExperienceAsync({ disableTeleportation: true }).then((xr) => {
const xrRoot = new TransformNode("xrRoot", scene);
xr.baseExperience.camera.parent = xrRoot;
xr.baseExperience.featuresManager.enableFeature(WebXRFeatureName.WALKING_LOCOMOTION, "latest", { locomotionTarget: xrRoot });
});
Walking Locomotion Demo

While it is highly recommended to move the WebXRCamera's parent node in order to avoid conflating virtual positional data with XR sensory readings, it is also possible to move the WebXRCamera itself.

import { WebXRFeatureName } from "@babylonjs/core/XR/webXRFeaturesManager";
scene.createDefaultXRExperienceAsync({ disableTeleportation: true }).then((xr) => {
xr.baseExperience.featuresManager.enableFeature(WebXRFeatureName.WALKING_LOCOMOTION, "latest", { locomotionTarget: xr.baseExperience.camera.parent });
});
WebXRCamera Walking Locomotion

To move, simply face in the direction you want to go and "walk in place," lifting and replacing each foot in turn much as you would if you were actually walking forward. This is a control technique and is not expected to work "magically"; it may take a small amount of practice to perform a motion that the system recognizes as walking.

Under the hood, what the XR system is actually reacting to is the user's head motion, specifically the characteristic back-and-forth "rocking" motion traced by most people's heads when walking in place (or, for example, on a treadmill). Because of this, walking-in-place motions which keep the head stationary, or which cause the head to move erratically, will not be recognized as "walking" by the WebXRWalkingLocomotion feature. However, once a recognizable motion is performed, it should be very easy and comfortable to replicate. Walking detection of a recognizable motion should also be resilient to head orientation; because walking is recognized from the movement of the head (at a guesstimated "nape of the neck" position, which remains relatively stationary as the head rotates), looking around while performing a recognizable "walking in place" motion will not disrupt the locomotion feature.

When to Use This Feature

WebXRWalkingLocomotion is a form of continuous traversal, similar to walking around in real life and distinct from discontinuous traversal alternatives such as teleportation. The most common example of continuous traversal in VR, as in other forms of interactive 3D, is controller-based and typically leverages a thumbstick to sort of "slide" the user around the world in a continuous manner. Many users find this "sliding" effect to be uncomfortable in VR, and for this reason teleportation is often chosen as the default traversal alternative in VR applications.

However, there are times when teleportation and other discontinuous traversal techniques are unsuitable, and in such circumstances WebXRWalkingLocomotion can serve as an alternative to controller-based continuous traversal. Early tests indicate that walking locomotion can feel noticeably more comfortable than controller-based continuous traversal, perhaps because the familiar "walking" motion reduces the dissonance between the visual and vestibular stimuli presented to the user.

It is also notable that WebXRWalkingLocomotion, because it assesses only head motion, can be used entirely controller-free. This is particularly powerful in combination with WebXRHandTracking because it allows for a fully traversal-enabled VR experience where users can use their natural hands without any controllers at all. This is not possible using other traversal technologies without customizing the virtual space to support point-to-point navigation and/or advanced hand gestures.