Use LightProbe Spherical Harmonics in Three.js

This article explains how to utilize spherical harmonics (SH) coefficients within a Three.js LightProbe to create realistic, low-frequency ambient lighting in a 3D scene. You will learn how to instantiate a light probe, populate its spherical harmonics data from an environmental source using the LightProbeGenerator, and apply this light to illuminate your scene’s materials efficiently.

Understanding LightProbes and Spherical Harmonics

In Three.js, a LightProbe is an alternative way of adding light to a 3D scene. Instead of emitting light from a single point or direction, it uses Spherical Harmonics (SH) to approximate diffuse indirect light from all directions. This is highly efficient because it represents complex global illumination using just 9 color coefficients (3rd-order SH), providing realistic ambient shading with minimal performance cost.

Implementing a LightProbe in Three.js

To use spherical harmonics to illuminate your scene, follow these steps:

1. Create the Light Probe

First, instantiate the LightProbe object and add it to your scene.

import * as THREE from 'three';

const lightProbe = new THREE.LightProbe();
scene.add(lightProbe);

2. Generate Spherical Harmonics Coefficients

While you can manually set the SH coefficients if you have raw data, the most common approach is to generate them from an envmap (such as a CubeTexture) using the LightProbeGenerator utility.

import { LightProbeGenerator } from 'three/addons/lights/LightProbeGenerator.js';

// Load an environment cube texture
const cubeTextureLoader = new THREE.CubeTextureLoader();
cubeTextureLoader.load([
    'px.png', 'nx.png',
    'py.png', 'ny.png',
    'pz.png', 'nz.png'
], (cubeTexture) => {
    // Generate the spherical harmonics and copy them to the light probe
    const generatedProbe = LightProbeGenerator.fromCubeTexture(cubeTexture);
    lightProbe.copy(generatedProbe);
});

3. Manually Setting Coefficients (Optional)

If you already have pre-calculated SH coefficients from an external baking tool, you can pass them directly into the light probe’s sh property. The sh.coefficients array contains 9 THREE.Vector3 objects representing the RGB channels of the 9 spherical harmonic bases.

// Setting coefficients from a flat array of 27 floats (9 vectors * 3 RGB channels)
const rawCoefficients = [
    // 27 float values representing your 9 Vector3s
]; 
lightProbe.sh.fromArray(rawCoefficients);

Adjusting Influence and Materials

Once the light probe has its spherical harmonics coefficients set, any physically-based materials in your scene (such as MeshStandardMaterial or MeshPhysicalMaterial) will automatically detect and use this data for diffuse indirect lighting.

You can control the overall contribution of the light probe using its intensity property:

lightProbe.intensity = 1.2; // Adjust to match the desired ambient brightness