Configure Three.js VRButton for WebXR

This article provides a straightforward, step-by-step guide on how to configure and use the VRButton utility in Three.js to initiate a WebXR session. You will learn how to import the module, enable XR on the renderer, append the button to your webpage, and set up the compatible animation loop required for an immersive virtual reality experience.

1. Import Three.js and the VRButton

To use the WebXR capabilities in Three.js, you must import the core library along with the official VRButton addon.

import * as THREE from 'three';
import { VRButton } from 'three/addons/webxr/VRButton.js';

2. Enable WebXR on the WebGLRenderer

You must explicitly tell your Three.js renderer to support XR content. Without this setting, the renderer will not transition into the VR headset when the session starts.

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);

// This line is required for WebXR
renderer.xr.enabled = true; 

document.body.appendChild(renderer.domElement);

3. Append the VRButton to the DOM

The VRButton.createButton() method creates an HTML button that automatically detects VR capabilities. It displays “ENTER VR” if a headset is connected, “VR NOT SUPPORTED” if unavailable, or “LIMITATIONS” depending on the device state.

Append this button to your document’s body:

document.body.appendChild(VRButton.createButton(renderer));

4. Set Up the WebXR Animation Loop

Standard browser-based rendering uses window.requestAnimationFrame(). However, WebXR requires the VR headset to control the frame rate. You must use Three.js’s built-in setAnimationLoop method to ensure your render loop runs correctly inside the VR environment.

// Define your update and render logic
function animate() {
    // Update your animations and physics here
    
    renderer.render(scene, camera);
}

// Start the loop
renderer.setAnimationLoop(animate);

Complete Implementation Example

Below is a complete boilerplate containing all the necessary code to get your WebXR session running:

import * as THREE from 'three';
import { VRButton } from 'three/addons/webxr/VRButton.js';

// Setup Scene, Camera, and Renderer
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x202020);

const camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 10);
camera.position.set(0, 1.6, 0); // Position at typical eye height (1.6 meters)

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true; // Enable XR
document.body.appendChild(renderer.domElement);

// Add the VR Button to the page
document.body.appendChild(VRButton.createButton(renderer));

// Add a simple object to view in VR
const geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
cube.position.set(0, 1.6, -2); // Place 2 meters in front of the camera
scene.add(cube);

// Handle window resizing
window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

// XR-compatible Animation Loop
function animate() {
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;

    renderer.render(scene, camera);
}

renderer.setAnimationLoop(animate);