Prevent Three.js Texture Bleeding with ClampToEdge
When rendering textures on 3D planes in Three.js, you may notice
unsightly artifacts or “bleeding” at the outer boundaries of your
geometry. This article explains how to resolve this visual glitch by
configuring your texture’s wrapping properties to use
ClampToEdgeWrapping, ensuring your textures align perfectly
with the edges of your planes.
Why Texture Bleeding Happens
Texture bleeding occurs when the GPU’s texture sampler interpolates colors at the outer boundaries of a 3D model. By default, Three.js textures use wrapping modes that can cause the GPU to blend the pixels on one edge of the image with the pixels on the opposite edge (tiling/repeating), or average them with a default background color. This results in a thin, distracting line along the edges of your plane.
The Solution: ClampToEdgeWrapping
To stop the texture from repeating or blending with the opposite
edge, you must set the texture’s horizontal (wrapS) and
vertical (wrapT) wrapping properties to
THREE.ClampToEdgeWrapping. This tells the GPU to clamp the
edge coordinates to the range of 0 to 1, stretching the outermost pixels
to the edge of the geometry instead of wrapping them.
Step-by-Step Code Implementation
Here is how to apply ClampToEdgeWrapping to a texture in
Three.js:
import * as THREE from 'three';
// 1. Initialize the TextureLoader
const textureLoader = new THREE.TextureLoader();
// 2. Load your texture
const texture = textureLoader.load('path/to/your-texture.png');
// 3. Set wrapping behavior to ClampToEdgeWrapping
texture.wrapS = THREE.ClampToEdgeWrapping; // Horizontal wrapping
texture.wrapT = THREE.ClampToEdgeWrapping; // Vertical wrapping
// 4. (Optional) Adjust filtering if necessary
// Sometimes linear mipmap filtering causes bleeding.
// Switching to LinearFilter or NearestFilter can further sharpen edges.
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
// 5. Apply the texture to a material
const material = new THREE.MeshBasicMaterial({ map: texture });
// 6. Create the plane mesh
const geometry = new THREE.PlaneGeometry(5, 5);
const plane = new THREE.Mesh(geometry, material);
// 7. Add to your scene
scene.add(plane);Important Considerations
- Texture Coordinates: Ensure your UV coordinates are
correctly mapped. If your UVs exceed the 0-1 range,
ClampToEdgeWrappingwill stretch the final pixel row/column infinitely across the rest of the geometry. - Power of Two: While modern WebGL handles non-power-of-two (NPOT) textures well, using power-of-two texture dimensions (e.g., 512x512, 1024x1024) ensures consistent mipmapping and filtering behavior across all devices.