Three.js MathUtils.smoothstep for Non-Linear Transitions
In Three.js, creating natural, organic animations often requires
non-linear interpolation rather than rigid linear movement. The
MathUtils.smoothstep function is a built-in utility that
calculates a smooth, S-shaped transition between two boundary values.
This article explains how MathUtils.smoothstep works under
the hood, details its syntax, highlights how it differs from linear
interpolation, and demonstrates how to implement it for fluid animations
in your 3D scenes.
What is MathUtils.smoothstep?
The MathUtils.smoothstep function is the Three.js
implementation of the standard smoothstep formula commonly used in
computer graphics and GLSL shaders. It performs Hermite interpolation
between two limits.
When you pass an input value to smoothstep, the function
normalizes the value between a specified minimum and maximum range,
clamps it between 0 and 1, and then applies the following cubic
polynomial formula:
\[f(t) = 3t^2 - 2t^3\]
This mathematical curve results in a smooth “ease-in, ease-out” behavior. The transition starts slowly, accelerates in the middle, and decelerates smoothly as it approaches the target value.
Syntax and Parameters
The syntax for using smoothstep in Three.js is
straightforward:
import * as THREE from 'three';
const result = THREE.MathUtils.smoothstep(value, min, max);The function accepts three parameters:
value: The input variable you want to evaluate (often time, scroll position, or frame count).min: The lower boundary of the transition zone. Any input value less than or equal tominreturns0.max: The upper boundary of the transition zone. Any input value greater than or equal tomaxreturns1.
If the value is between min and
max, the function returns a smoothly interpolated float
between 0.0 and 1.0.
Linear Interpolation (lerp) vs. Smoothstep
To understand the visual benefits of smoothstep, it
helps to compare it to linear interpolation (lerp):
MathUtils.lerp: Moves at a constant speed from start to finish. This creates abrupt starts and stops, which can look mechanical and jarring in animations.MathUtils.smoothstep: Gradually increases speed at the beginning and gradually decreases speed at the end. This mimics real-world physics, where objects require time to accelerate and decelerate.
Implementing smoothstep in Three.js Animations
MathUtils.smoothstep is highly versatile. It is commonly
used to animate mesh positions, scale, material opacity, or camera
movements.
Here is a practical example of how to use smoothstep to
smoothly fade a mesh’s opacity in an active render loop:
import * as THREE from 'three';
// Set up scene, camera, renderer, and a mesh
const scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({
color: 0x00ff00,
transparent: true,
opacity: 0
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const elapsedTime = clock.getElapsedTime();
// Fade in the mesh opacity between 1.0 and 4.0 seconds of elapsed time
// The opacity will smoothly transition from 0 to 1
mesh.material.opacity = THREE.MathUtils.smoothstep(elapsedTime, 1.0, 4.0);
renderer.render(scene, camera);
}
animate();In this setup, before elapsedTime reaches
1.0, the opacity remains strictly 0. Between
1.0 and 4.0 seconds, the opacity smoothly
ramps up to 1. After 4.0 seconds, the opacity
stays at 1. The transition avoids any sudden jumps,
producing a professional, eased transition.