How to Animate Scrolling Backgrounds in Three.js
Animating a scrolling background in Three.js is a powerful technique for creating dynamic environments, such as moving skies, infinite roads, or flowing water effects. This article provides a straightforward guide on how to manipulate texture offsets within your rendering loop to achieve a seamless, continuous scrolling effect on your 3D materials.
To create a scrolling background, you must load a texture, enable texture wrapping, and incrementally update the texture’s offset coordinates within your animation loop.
Step 1: Load the Texture and Enable Repeating
By default, textures in Three.js do not repeat. To make a texture
scroll infinitely without stretching or stopping, you must configure its
wrapping behavior. Set both wrapS (horizontal wrapping) and
wrapT (vertical wrapping) to
THREE.RepeatWrapping.
import * as THREE from 'three';
// Initialize texture loader
const textureLoader = new THREE.TextureLoader();
// Load your background texture
const backgroundTexture = textureLoader.load('path/to/your/texture.jpg');
// Enable infinite repeating
backgroundTexture.wrapS = THREE.RepeatWrapping;
backgroundTexture.wrapT = THREE.RepeatWrapping;Step 2: Apply the Texture to a Material
Apply the configured texture to a material, then map that material onto a 3D object. Typically, a flat plane or a large sphere surrounding the scene is used for backgrounds.
// Create a plane geometry for the background
const geometry = new THREE.PlaneGeometry(10, 10);
// Create a material using the texture
const material = new THREE.MeshBasicMaterial({ map: backgroundTexture });
// Create the mesh and add it to the scene
const backgroundMesh = new THREE.Mesh(geometry, material);
scene.add(backgroundMesh);Step 3: Manipulate Offsets in the Animation Loop
The texture.offset property controls the starting point
of the UV mapping. It is a THREE.Vector2 object with
x (horizontal) and y (vertical) properties.
Values range from 0 to 1.
To animate the scroll, increment the x or y
offset inside your requestAnimationFrame loop.
// Define the scrolling speed
const scrollSpeedX = 0.05;
const scrollSpeedY = 0.02;
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
// Get delta time to ensure smooth animation regardless of frame rate
const delta = clock.getDelta();
// Update texture offset
backgroundTexture.offset.x += scrollSpeedX * delta;
backgroundTexture.offset.y += scrollSpeedY * delta;
// Optional: Reset offset to keep values small and prevent precision loss
backgroundTexture.offset.x %= 1;
backgroundTexture.offset.y %= 1;
// Render the scene
renderer.render(scene, camera);
}
animate();Using clock.getDelta() ensures that the background
scrolls at a consistent speed regardless of the user’s monitor refresh
rate or system performance. Utilizing the modulo operator
(% 1) keeps the offset values between 0 and
1, preventing potential rendering glitches caused by
extremely high float values over long periods of execution.