Use HTML Video Stream as Three.js Texture
Rendering live video onto 3D geometry is a powerful way to create
immersive, interactive WebGL experiences. This article provides a
direct, step-by-step guide on how to capture an active HTML
<video> element—whether from a local file, stream, or
webcam—and apply it as a real-time animated texture onto a 3D object
using the Three.js VideoTexture class.
1. Setup the HTML Video Element
To use a video as a texture, you first need an HTML
<video> element. You can define this in your HTML
file. It is often hidden using CSS so that only the 3D canvas is visible
to the user.
<video id="my-video" src="path/to/video.mp4" autoplay loop muted playsinline style="display:none;"></video>Note: The muted, autoplay, and
playsinline attributes are crucial. Modern browsers block
autoplaying videos that have audio enabled or are not triggered by a
user interaction.
2. Initialize the Video Element in JavaScript
Select the video element in your JavaScript code and ensure it is playing.
const video = document.getElementById('my-video');
video.play().catch(error => {
console.log("Autoplay was prevented. A user interaction is required to play the video:", error);
});3. Create the Three.js VideoTexture
Three.js provides a built-in VideoTexture class. This
class automatically uploads the current frame of the video to the GPU on
every render tick, eliminating the need to manually update the
texture.
import * as THREE from 'three';
// Create the video texture
const videoTexture = new THREE.VideoTexture(video);
// Set appropriate filters for texture scaling
videoTexture.minFilter = THREE.LinearFilter;
videoTexture.magFilter = THREE.LinearFilter;
videoTexture.colorSpace = THREE.SRGBColorSpace; // Ensures correct color reproduction4. Apply the Texture to a 3D Object
Now, assign the VideoTexture to the map
property of a material, and apply that material to a mesh.
// Create a 3D geometry (e.g., a flat screen)
const geometry = new THREE.PlaneGeometry(16, 9);
// Create a material and map the video texture to it
const material = new THREE.MeshBasicMaterial({ map: videoTexture, side: THREE.DoubleSide });
// Combine geometry and material into a mesh
const screenMesh = new THREE.Mesh(geometry, material);
// Add the mesh to your Three.js scene
scene.add(screenMesh);5. Update the Animation Loop
Because THREE.VideoTexture internally handles the
texture updates, your standard Three.js render loop does not require any
special video handling code. Just ensure your video element is playing
and the scene is rendering.
function animate() {
requestAnimationFrame(animate);
// Optional: Rotate the mesh to show it is in 3D space
screenMesh.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();Using a Webcam or MediaStream instead of a File
If you want to apply a live webcam feed instead of a pre-recorded
file, replace the video element’s source with a MediaStream
using the browser’s getUserMedia API:
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
const constraints = { video: { width: 1280, height: 720, facingMode: 'user' } };
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
video.srcObject = stream;
video.play();
})
.catch((error) => {
console.error('Unable to access the camera/webcam.', error);
});
}