Skip to content

Matrix4: Optimize invert() calculation#32657

Merged
mrdoob merged 2 commits intodevfrom
matrix4-invert
Jan 3, 2026
Merged

Matrix4: Optimize invert() calculation#32657
mrdoob merged 2 commits intodevfrom
matrix4-invert

Conversation

@mrdoob
Copy link
Owner

@mrdoob mrdoob commented Jan 2, 2026

Adopts gl-matrix's invert() algorithm which uses a more efficient factorization.

Approach

Pre-computes 12 two-term minors from row pairs:

  • t1-t6: Minors from rows 1 and 2
  • t7-t12: Minors from rows 3 and 4

Each output element is then expressed as exactly 3 products of these minors.

Performance

Metric Before After
Temp variables 22 12
Multiplications ~200 ~78
Lines of code 64 51

~60% fewer multiplications.

(Made with Claude Opus 4.5)

@mrdoob mrdoob added this to the r183 milestone Jan 2, 2026
@mrdoob mrdoob requested a review from WestLangley January 2, 2026 15:47
@github-actions
Copy link

github-actions bot commented Jan 2, 2026

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 355.36
84.47
355.36
84.47
+0 B
+0 B
WebGPU 621.33
172.52
621.33
172.52
+0 B
+0 B
WebGPU Nodes 619.94
172.27
619.94
172.27
+0 B
+0 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Before After Diff
WebGL 487.5
119.33
487.23
119.23
-264 B
-98 B
WebGPU 692.54
187.87
692.28
187.78
-264 B
-92 B
WebGPU Nodes 642.34
175.09
642.08
175
-264 B
-88 B

@WestLangley
Copy link
Collaborator

I'd suggest comparing with other implementations. Also, remove the source reverenced in the inline comment.

As a start, this one seems to involve fewer computations, but I have not had the time to investigate fully.

@mrdoob
Copy link
Owner Author

mrdoob commented Jan 3, 2026

Claude says we should adopt it:


Operation Count

Aspect Current three.js gl-matrix
Pre-computed terms 4 cofactors (48 muls) 12 minors (24 muls)
Determinant 4 muls 6 muls
Output elements 12×12 + 4×1 = 148 muls 16×3 = 48 muls
Total multiplications ~200 ~78

Why gl-matrix is Better

The key insight is the choice of which 2×2 minors to pre-compute:

  • b00-b05: Minors from rows 0 and 1 (top half)
  • b06-b11: Minors from rows 2 and 3 (bottom half)

This decomposition is symmetric—every output element can be expressed as exactly 3 products of these minors. The determinant becomes a simple dot product of top minors with bottom minors.

The current three.js code computes 3×3 cofactors first (more work), then still has to compute 12 elements from scratch.

Recommendation

Adopt the gl-matrix approach. It's ~60% fewer multiplications and the code is actually shorter and clearer.

@mrdoob
Copy link
Owner Author

mrdoob commented Jan 3, 2026

Asked if there are any downsides...


Good question. Let me think through potential concerns: Memory/Variables

  • gl-matrix: 12 temporary minors
  • three.js: 4 temporary cofactors

Negligible difference—all stack-allocated locals that any JIT will optimize.

Numerical Stability
Both compute the same mathematical result (adjugate matrix / determinant). Same formula, just factored differently. No stability difference.

Code Clarity
Arguably gl-matrix is clearer—12 simple 2-term products with consistent naming (b00-b11) vs. 4 complex 6-term expressions.

Licensing
gl-matrix is MIT licensed, and the algorithm is just standard linear algebra (Laplace expansion with 2×2 minors). No concern here.

Honest assessment: I don't see any real downsides. The gl-matrix approach is simply a better factorization of the same mathematics. The only reason not to adopt it would be:

  1. Churn — changing working code has inherent risk
  2. Verification effort — need to carefully verify the adapted code is correct

But both are addressed by having good unit tests, which three.js does.

@mrdoob mrdoob merged commit 1c2a5aa into dev Jan 3, 2026
10 checks passed
@mrdoob mrdoob deleted the matrix4-invert branch January 3, 2026 03:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants