How to Use Global Uniforms in Three.js NodeMaterial

This article explains how to access and utilize global uniforms, specifically time and viewport resolution, within the modern Three.js NodeMaterial system. With the transition to WebGPU and the Three Shading Language (TSL), managing uniforms has become highly declarative, eliminating the need to manually update uniforms in an animation loop.

In the traditional ShaderMaterial, you had to manually pass and update time and resolution uniforms. In NodeMaterial, Three.js provides built-in node inputs that automatically track these global values. To use them, you import the required node functions from the three/tsl (or three/nodes) module.

Accessing Time

To get the elapsed time in seconds, use the timerLocal or timerGlobal nodes. Three.js automatically updates this value every frame.

import { SpriteNodeMaterial } from 'three';
import { timerLocal, sin } from 'three/tsl';

const material = new SpriteNodeMaterial();

// Access local elapsed time
const time = timerLocal();

// Example: Use time to animate an effect (e.g., a pulsating scale)
const pulse = sin(time);
material.positionNode = /* your node logic using pulse */;

Accessing Resolution

To access the viewport resolution (the width and height of the canvas/render target in pixels), use the viewportSize node. This node automatically handles canvas resizing.

import { MeshBasicNodeMaterial } from 'three';
import { viewportSize, viewportCoordinate } from 'three/tsl';

const material = new MeshBasicNodeMaterial();

// Get the aspect ratio of the viewport
const aspectRatio = viewportSize.x.div(viewportSize.y);

// Normalize the fragment coordinates (equivalent to uv in screen space)
const screenUV = viewportCoordinate.xy.div(viewportSize);

material.colorNode = screenUV; // Renders a screen-space gradient

Complete Implementation Example

Below is a practical example of combining both global uniforms to create a screen-space shader effect that animates over time.

import * as THREE from 'three';
import { timerLocal, viewportSize, viewportCoordinate, vec4, sin } from 'three/tsl';

// Initialize the NodeMaterial
const material = new THREE.MeshBasicNodeMaterial();

// Get global uniforms
const time = timerLocal();
const resolution = viewportSize;
const fragCoord = viewportCoordinate;

// Normalize coordinates to 0.0 - 1.0
const uv = fragCoord.xy.div(resolution);

// Create an animated color effect using time
const red = uv.x.add(sin(time).mul(0.5));
const green = uv.y;
const blue = sin(time.mul(2.0)).mul(0.5).add(0.5);

// Assign the final color to the material
material.colorNode = vec4(red, green, blue, 1.0);