mrdoob/three.js · error

THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate

Error message

THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ${coordinateSystem}

What it means

Thrown by Frustum.setFromProjectionMatrix() when the coordinateSystem argument is neither WebGLCoordinateSystem nor WebGPUCoordinateSystem. The near plane is computed differently for each (WebGL uses the row-sum plane, WebGPU uses the third row directly) because the two systems use different clip-space z ranges; an unknown system has no valid near-plane formula.

Source

Thrown at src/math/Frustum.js:128

			planes[ 4 ].setComponents( me2, me6, me10, me14 ).normalize(); // far
			planes[ 5 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); // near

		} else {

			planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); // far

			if ( coordinateSystem === WebGLCoordinateSystem ) {

				planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); // near

			} else if ( coordinateSystem === WebGPUCoordinateSystem ) {

				planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize(); // near

			} else {

				throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem );

			}

		}

		return this;

	}

	/**
	 * Returns `true` if the 3D object's bounding sphere is intersecting this frustum.
	 *
	 * Note that the 3D object must have a geometry so that the bounding sphere can be calculated.
	 *
	 * @param {Object3D} object - The 3D object to test.
	 * @return {boolean} Whether the 3D object's bounding sphere is intersecting this frustum or not.
	 */
	intersectsObject( object ) {

View on GitHub (pinned to da05705fa3)

Solutions

  1. Always pass an explicit, valid coordinateSystem as the second argument, matching the renderer that produced the projection matrix.
  2. If deriving from a renderer, use renderer.coordinateSystem (THREE.WebGLCoordinateSystem or THREE.WebGPUCoordinateSystem).
  3. For manual frustum extraction, pass THREE.WebGLCoordinateSystem unless you knowingly use the WebGPU [0,1] depth convention.
  4. Ensure camera.coordinateSystem is initialized before any code that builds a frustum from its matrix.

Example fix

// before: second argument missing or invalid
frustum.setFromProjectionMatrix(camera.projectionMatrix);

// after: pass a valid coordinate system
frustum.setFromProjectionMatrix(camera.projectionMatrix, THREE.WebGLCoordinateSystem);
Defensive patterns

Strategy: validation

Validate before calling

import { WebGLCoordinateSystem, WebGPUCoordinateSystem } from 'three';

function buildFrustum(projectionMatrix, coordinateSystem) {
  if (coordinateSystem !== WebGLCoordinateSystem && coordinateSystem !== WebGPUCoordinateSystem) {
    throw new Error('coordinateSystem must be WebGL or WebGPU');
  }
  return new THREE.Frustum().setFromProjectionMatrix(projectionMatrix, coordinateSystem);
}

Type guard

function isValidCoordinateSystem(cs) {
  return cs === THREE.WebGLCoordinateSystem || cs === THREE.WebGPUCoordinateSystem;
}

Prevention

When it happens

Trigger: Calling frustum.setFromProjectionMatrix(matrix, coordinateSystem) with a missing, null, or custom coordinateSystem value. Also indirectly when library internals call it with a renderer.coordinateSystem that is non-standard.

Common situations: Calling setFromProjectionMatrix without the second argument (it is required). Passing camera.coordinateSystem before a renderer has set it. Custom projection pipelines that introduce a third convention. Stale references after switching renderers.

Related errors


AI-assisted analysis of mrdoob/three.js@da05705fa3 (2026-08-12). Data as JSON: /api/errors/3bc2907ebbd012bb. Report an issue: GitHub.