Use HTML Canvas as Dynamic Texture in Three.js
This article explains how to use an HTML <canvas>
element as a dynamic, updatable texture within a Three.js 3D scene. You
will learn how to initialize the canvas, project it onto a 3D object
using THREE.CanvasTexture, and continuously update the
texture in real-time to reflect changes drawn on the canvas.
Step 1: Create and Draw on the HTML Canvas
First, create an HTML canvas element in your JavaScript code. You do not need to append this canvas to the DOM if you only want it to exist in memory as a texture.
// Create the canvas element
const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
// Get the 2D rendering context
const ctx = canvas.getContext('2d');
// Draw an initial background and text
ctx.fillStyle = '#1e1e1e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.font = '40px Arial';
ctx.fillText('Hello Three.js', 50, 100);Step 2: Create the CanvasTexture in Three.js
Three.js provides a specialized class called
THREE.CanvasTexture designed specifically to handle canvas
elements. Pass your canvas instance directly into this constructor.
// Create the texture from the canvas
const texture = new THREE.CanvasTexture(canvas);Step 3: Apply the Texture to a Material and Mesh
Apply the texture to a material (such as
MeshBasicMaterial or MeshStandardMaterial) and
map it to a 3D geometry.
// Create a material using the canvas texture
const material = new THREE.MeshBasicMaterial({ map: texture });
// Create a cube geometry and mesh
const geometry = new THREE.BoxGeometry(2, 2, 2);
const cube = new THREE.Mesh(geometry, material);
// Add the cube to your Three.js scene
scene.add(cube);Step 4: Update the Texture Dynamically
Three.js caches textures for performance reasons. If you modify the
HTML canvas inside your rendering loop, you must explicitly inform
Three.js that the texture needs to be uploaded to the GPU again. You do
this by setting the needsUpdate property of the texture to
true.
Here is how to update the canvas content and refresh the texture inside the animation loop:
let frameCount = 0;
function animate() {
requestAnimationFrame(animate);
// 1. Clear and redraw on the 2D canvas context
ctx.fillStyle = '#1e1e1e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw dynamic content (e.g., a moving circle)
frameCount++;
const x = 256 + Math.sin(frameCount * 0.05) * 150;
const y = 256 + Math.cos(frameCount * 0.05) * 150;
ctx.beginPath();
ctx.arc(x, y, 40, 0, Math.PI * 2);
ctx.fillStyle = '#ff0055';
ctx.fill();
// 2. Tell Three.js to update the GPU texture
texture.needsUpdate = true;
// Render the Three.js scene
renderer.render(scene, camera);
}
animate();By setting texture.needsUpdate = true after modifying
the canvas, Three.js automatically re-uploads the modified canvas buffer
to the GPU on the next render call, achieving a seamless dynamic texture
effect.