From 605b5895954346fc8fd68541ab35bf6c855fefc5 Mon Sep 17 00:00:00 2001 From: Om Mishra Date: Tue, 2 Dec 2025 00:22:08 +0530 Subject: [PATCH 1/8] Fix: Handle zero scale in Matrix4.extractRotation --- src/math/Matrix4.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/math/Matrix4.js b/src/math/Matrix4.js index d0ad3d41c49830..9e46ff3e915dae 100644 --- a/src/math/Matrix4.js +++ b/src/math/Matrix4.js @@ -277,9 +277,9 @@ class Matrix4 { const te = this.elements; const me = m.elements; - const scaleX = 1 / _v1.setFromMatrixColumn( m, 0 ).length(); - const scaleY = 1 / _v1.setFromMatrixColumn( m, 1 ).length(); - const scaleZ = 1 / _v1.setFromMatrixColumn( m, 2 ).length(); + const scaleX = 1 / ( _v1.setFromMatrixColumn( m, 0 ).length() || 1 ); + const scaleY = 1 / ( _v1.setFromMatrixColumn( m, 1 ).length() || 1 ); + const scaleZ = 1 / ( _v1.setFromMatrixColumn( m, 2 ).length() || 1 ); te[ 0 ] = me[ 0 ] * scaleX; te[ 1 ] = me[ 1 ] * scaleX; From 2c2c43a21b7bb9f98b3ec37412a2f52251573af4 Mon Sep 17 00:00:00 2001 From: Om Mishra Date: Tue, 2 Dec 2025 04:39:39 +0530 Subject: [PATCH 2/8] Fix: Apply zero-scale safety to decompose() for consistency --- src/math/Matrix4.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/math/Matrix4.js b/src/math/Matrix4.js index 9e46ff3e915dae..aae884daaf25e9 100644 --- a/src/math/Matrix4.js +++ b/src/math/Matrix4.js @@ -1041,9 +1041,9 @@ class Matrix4 { // scale the rotation part _m1.copy( this ); - const invSX = 1 / sx; - const invSY = 1 / sy; - const invSZ = 1 / sz; + const invSX = 1 / ( sx || 1 ); + const invSY = 1 / ( sy || 1 ); + const invSZ = 1 / ( sz || 1 ); _m1.elements[ 0 ] *= invSX; _m1.elements[ 1 ] *= invSX; From d5d18b43c6e41c7c93847370e9386288aee08e30 Mon Sep 17 00:00:00 2001 From: Om Mishra Date: Wed, 3 Dec 2025 22:58:32 +0530 Subject: [PATCH 3/8] Refactor: Use identity basis fallback in extractRotation, revert decompose --- src/math/Matrix4.js | 81 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/src/math/Matrix4.js b/src/math/Matrix4.js index aae884daaf25e9..5f200bf2592ed7 100644 --- a/src/math/Matrix4.js +++ b/src/math/Matrix4.js @@ -277,24 +277,69 @@ class Matrix4 { const te = this.elements; const me = m.elements; - const scaleX = 1 / ( _v1.setFromMatrixColumn( m, 0 ).length() || 1 ); - const scaleY = 1 / ( _v1.setFromMatrixColumn( m, 1 ).length() || 1 ); - const scaleZ = 1 / ( _v1.setFromMatrixColumn( m, 2 ).length() || 1 ); + const lengthX = _v1.setFromMatrixColumn( m, 0 ).length(); + const lengthY = _v1.setFromMatrixColumn( m, 1 ).length(); + const lengthZ = _v1.setFromMatrixColumn( m, 2 ).length(); - te[ 0 ] = me[ 0 ] * scaleX; - te[ 1 ] = me[ 1 ] * scaleX; - te[ 2 ] = me[ 2 ] * scaleX; - te[ 3 ] = 0; + // x - te[ 4 ] = me[ 4 ] * scaleY; - te[ 5 ] = me[ 5 ] * scaleY; - te[ 6 ] = me[ 6 ] * scaleY; - te[ 7 ] = 0; + if ( lengthX === 0 ) { - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - te[ 11 ] = 0; + te[ 0 ] = 1; + te[ 1 ] = 0; + te[ 2 ] = 0; + te[ 3 ] = 0; + + } else { + + const scaleX = 1 / lengthX; + + te[ 0 ] = me[ 0 ] * scaleX; + te[ 1 ] = me[ 1 ] * scaleX; + te[ 2 ] = me[ 2 ] * scaleX; + te[ 3 ] = 0; + + } + + // y + + if ( lengthY === 0 ) { + + te[ 4 ] = 0; + te[ 5 ] = 1; + te[ 6 ] = 0; + te[ 7 ] = 0; + + } else { + + const scaleY = 1 / lengthY; + + te[ 4 ] = me[ 4 ] * scaleY; + te[ 5 ] = me[ 5 ] * scaleY; + te[ 6 ] = me[ 6 ] * scaleY; + te[ 7 ] = 0; + + } + + // z + + if ( lengthZ === 0 ) { + + te[ 8 ] = 0; + te[ 9 ] = 0; + te[ 10 ] = 1; + te[ 11 ] = 0; + + } else { + + const scaleZ = 1 / lengthZ; + + te[ 8 ] = me[ 8 ] * scaleZ; + te[ 9 ] = me[ 9 ] * scaleZ; + te[ 10 ] = me[ 10 ] * scaleZ; + te[ 11 ] = 0; + + } te[ 12 ] = 0; te[ 13 ] = 0; @@ -1041,9 +1086,9 @@ class Matrix4 { // scale the rotation part _m1.copy( this ); - const invSX = 1 / ( sx || 1 ); - const invSY = 1 / ( sy || 1 ); - const invSZ = 1 / ( sz || 1 ); + const invSX = 1 / sx; + const invSY = 1 / sy; + const invSZ = 1 / sz; _m1.elements[ 0 ] *= invSX; _m1.elements[ 1 ] *= invSX; From 1843933c92753a985f9e39d59622633f964cad4c Mon Sep 17 00:00:00 2001 From: Om Mishra Date: Sat, 6 Dec 2025 11:29:14 +0530 Subject: [PATCH 4/8] Feat: Apply identity fallback to extractBasis as requested --- src/math/Matrix4.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/math/Matrix4.js b/src/math/Matrix4.js index 5f200bf2592ed7..8db2db1d21303e 100644 --- a/src/math/Matrix4.js +++ b/src/math/Matrix4.js @@ -235,8 +235,19 @@ class Matrix4 { extractBasis( xAxis, yAxis, zAxis ) { xAxis.setFromMatrixColumn( this, 0 ); + if ( xAxis.lengthSq() === 0 ) { + xAxis.set( 1, 0, 0 ); + } + yAxis.setFromMatrixColumn( this, 1 ); + if ( yAxis.lengthSq() === 0 ) { + yAxis.set( 0, 1, 0 ); + } + zAxis.setFromMatrixColumn( this, 2 ); + if ( zAxis.lengthSq() === 0 ) { + zAxis.set( 0, 0, 1 ); + } return this; From 011159797a97b429eb387f09fcedea94012a6a71 Mon Sep 17 00:00:00 2001 From: Om Mishra Date: Sat, 6 Dec 2025 11:52:54 +0530 Subject: [PATCH 5/8] Style: Fix ESLint padded-blocks errors --- src/math/Matrix4.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/math/Matrix4.js b/src/math/Matrix4.js index 8db2db1d21303e..7f69c19012f7d6 100644 --- a/src/math/Matrix4.js +++ b/src/math/Matrix4.js @@ -235,18 +235,27 @@ class Matrix4 { extractBasis( xAxis, yAxis, zAxis ) { xAxis.setFromMatrixColumn( this, 0 ); + if ( xAxis.lengthSq() === 0 ) { + xAxis.set( 1, 0, 0 ); + } yAxis.setFromMatrixColumn( this, 1 ); + if ( yAxis.lengthSq() === 0 ) { + yAxis.set( 0, 1, 0 ); + } zAxis.setFromMatrixColumn( this, 2 ); + if ( zAxis.lengthSq() === 0 ) { + zAxis.set( 0, 0, 1 ); + } return this; From 7bf0c6f7e9d05f0bfbadf6f580caa27c13c80662 Mon Sep 17 00:00:00 2001 From: Om Mishra Date: Sat, 6 Dec 2025 14:04:55 +0530 Subject: [PATCH 6/8] Refactor: Use determinant check for zero-scale robustness --- src/math/Matrix4.js | 99 +++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 72 deletions(-) diff --git a/src/math/Matrix4.js b/src/math/Matrix4.js index 7f69c19012f7d6..a545ab20941ca4 100644 --- a/src/math/Matrix4.js +++ b/src/math/Matrix4.js @@ -234,30 +234,20 @@ class Matrix4 { */ extractBasis( xAxis, yAxis, zAxis ) { - xAxis.setFromMatrixColumn( this, 0 ); - - if ( xAxis.lengthSq() === 0 ) { + if ( this.determinant() === 0 ) { xAxis.set( 1, 0, 0 ); - - } - - yAxis.setFromMatrixColumn( this, 1 ); - - if ( yAxis.lengthSq() === 0 ) { - yAxis.set( 0, 1, 0 ); + zAxis.set( 0, 0, 1 ); + + return this; } + xAxis.setFromMatrixColumn( this, 0 ); + yAxis.setFromMatrixColumn( this, 1 ); zAxis.setFromMatrixColumn( this, 2 ); - if ( zAxis.lengthSq() === 0 ) { - - zAxis.set( 0, 0, 1 ); - - } - return this; } @@ -294,6 +284,12 @@ class Matrix4 { */ extractRotation( m ) { + if ( m.determinant() === 0 ) { + + return this.identity(); + + } + const te = this.elements; const me = m.elements; @@ -301,65 +297,24 @@ class Matrix4 { const lengthY = _v1.setFromMatrixColumn( m, 1 ).length(); const lengthZ = _v1.setFromMatrixColumn( m, 2 ).length(); - // x + const scaleX = 1 / lengthX; + const scaleY = 1 / lengthY; + const scaleZ = 1 / lengthZ; - if ( lengthX === 0 ) { - - te[ 0 ] = 1; - te[ 1 ] = 0; - te[ 2 ] = 0; - te[ 3 ] = 0; - - } else { - - const scaleX = 1 / lengthX; - - te[ 0 ] = me[ 0 ] * scaleX; - te[ 1 ] = me[ 1 ] * scaleX; - te[ 2 ] = me[ 2 ] * scaleX; - te[ 3 ] = 0; - - } - - // y - - if ( lengthY === 0 ) { - - te[ 4 ] = 0; - te[ 5 ] = 1; - te[ 6 ] = 0; - te[ 7 ] = 0; - - } else { - - const scaleY = 1 / lengthY; - - te[ 4 ] = me[ 4 ] * scaleY; - te[ 5 ] = me[ 5 ] * scaleY; - te[ 6 ] = me[ 6 ] * scaleY; - te[ 7 ] = 0; - - } - - // z - - if ( lengthZ === 0 ) { - - te[ 8 ] = 0; - te[ 9 ] = 0; - te[ 10 ] = 1; - te[ 11 ] = 0; - - } else { - - const scaleZ = 1 / lengthZ; + te[ 0 ] = me[ 0 ] * scaleX; + te[ 1 ] = me[ 1 ] * scaleX; + te[ 2 ] = me[ 2 ] * scaleX; + te[ 3 ] = 0; - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - te[ 11 ] = 0; + te[ 4 ] = me[ 4 ] * scaleY; + te[ 5 ] = me[ 5 ] * scaleY; + te[ 6 ] = me[ 6 ] * scaleY; + te[ 7 ] = 0; - } + te[ 8 ] = me[ 8 ] * scaleZ; + te[ 9 ] = me[ 9 ] * scaleZ; + te[ 10 ] = me[ 10 ] * scaleZ; + te[ 11 ] = 0; te[ 12 ] = 0; te[ 13 ] = 0; From b96ed8892b157a3d90c008443bb7a88ffa497f93 Mon Sep 17 00:00:00 2001 From: Om Mishra Date: Sat, 6 Dec 2025 16:34:28 +0530 Subject: [PATCH 7/8] Refactor: Add determinant guard to decompose() as requested --- src/math/Matrix4.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/math/Matrix4.js b/src/math/Matrix4.js index a545ab20941ca4..4f12d186f941cb 100644 --- a/src/math/Matrix4.js +++ b/src/math/Matrix4.js @@ -1046,6 +1046,19 @@ class Matrix4 { const te = this.elements; + position.x = te[ 12 ]; + position.y = te[ 13 ]; + position.z = te[ 14 ]; + + if ( this.determinant() === 0 ) { + + scale.set( 1, 1, 1 ); + quaternion.identity(); + + return this; + + } + let sx = _v1.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); const sy = _v1.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); const sz = _v1.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); @@ -1054,10 +1067,6 @@ class Matrix4 { const det = this.determinant(); if ( det < 0 ) sx = - sx; - position.x = te[ 12 ]; - position.y = te[ 13 ]; - position.z = te[ 14 ]; - // scale the rotation part _m1.copy( this ); From 2fa0485b7b350eb2152fb329d56b7fa2eb2ef18a Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Sat, 6 Dec 2025 14:56:49 +0100 Subject: [PATCH 8/8] Update Matrix4.js Clean up. --- src/math/Matrix4.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/math/Matrix4.js b/src/math/Matrix4.js index 4f12d186f941cb..471f9295278253 100644 --- a/src/math/Matrix4.js +++ b/src/math/Matrix4.js @@ -293,13 +293,9 @@ class Matrix4 { const te = this.elements; const me = m.elements; - const lengthX = _v1.setFromMatrixColumn( m, 0 ).length(); - const lengthY = _v1.setFromMatrixColumn( m, 1 ).length(); - const lengthZ = _v1.setFromMatrixColumn( m, 2 ).length(); - - const scaleX = 1 / lengthX; - const scaleY = 1 / lengthY; - const scaleZ = 1 / lengthZ; + const scaleX = 1 / _v1.setFromMatrixColumn( m, 0 ).length(); + const scaleY = 1 / _v1.setFromMatrixColumn( m, 1 ).length(); + const scaleZ = 1 / _v1.setFromMatrixColumn( m, 2 ).length(); te[ 0 ] = me[ 0 ] * scaleX; te[ 1 ] = me[ 1 ] * scaleX;