Use alphaTest to Discard Transparent Pixels in Three.js

In Three.js, rendering transparent textures can sometimes lead to unexpected visual artifacts, such as pixels sorting incorrectly or casting solid, boxy shadows. This article explains how to use the alphaTest property on Three.js materials to discard pixels below a specific opacity threshold, resolving common transparency issues and improving rendering performance.

Understanding alphaTest

The alphaTest property is a value between 0.0 and 1.0 set on a material. When rendering, Three.js looks at the alpha (transparency) value of each pixel in your texture. If a pixel’s alpha is lower than the alphaTest threshold, that pixel is completely discarded (not drawn at all) rather than blended with the background.

Unlike standard semi-transparent blending, which requires complex depth sorting, alphaTest performs a binary cut-off. Pixels are either fully rendered or completely ignored.

How to Implement alphaTest

To use alphaTest, you need a texture that contains an alpha channel (like a PNG). Apply this texture to a material, and set the alphaTest property in the material’s constructor.

import * as THREE from 'three';

// 1. Load your texture with transparency
const textureLoader = new THREE.TextureLoader();
const treeLeaveTexture = textureLoader.load('path/to/leaves.png');

// 2. Create the material and define the alphaTest threshold
const material = new THREE.MeshStandardMaterial({
    map: treeLeaveTexture,
    alphaTest: 0.5, // Discards any pixel with an alpha value below 0.5
    side: THREE.DoubleSide
});

// 3. Create the mesh and add it to the scene
const geometry = new THREE.PlaneGeometry(5, 5);
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

When to Use alphaTest vs. transparent

Choosing between alphaTest and setting transparent: true depends on your texture’s visual requirements:

Performance and Depth-Sorting Benefits

A major advantage of using alphaTest without setting transparent: true is that Three.js treats the object as opaque. This prevents depth-sorting bugs, where objects in the background are accidentally rendered in front of transparent objects. It also improves rendering performance because the GPU does not have to calculate complex color blending.

Fixing Shadow Issues

If your transparent object needs to cast shadows, the shadow map will render as a solid block by default. To make shadows respect the transparent cutouts, you must ensure alphaTest is set on the material casting the shadow.

Three.js automatically applies the material’s alphaTest value to its shadow map calculations.

// Enable shadow map rendering on the mesh
mesh.castShadow = true;
mesh.receiveShadow = true;

If you modify the alphaTest value dynamically after the material has already been rendered, you must tell Three.js to compile the shader again by setting the update flag:

material.alphaTest = 0.8;
material.needsUpdate = true;