From 41b32961d7362afadf55767170824581f335a49a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 09:30:23 +0100 Subject: [PATCH 1/8] Bump lodash from 4.17.21 to 4.17.23 (#32814) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 08197fa153f329..e80edf7908f772 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2599,9 +2599,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true, "license": "MIT" }, From 62299af6f67cd28fd16591acc50a394eee2b9ce6 Mon Sep 17 00:00:00 2001 From: dive2tech Date: Thu, 22 Jan 2026 03:34:45 -0500 Subject: [PATCH 2/8] Improve documentation for edge cases in MathUtils functions (#32806) Co-authored-by: Gittensor Miner Co-authored-by: Michael Herzog --- src/math/MathUtils.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/math/MathUtils.js b/src/math/MathUtils.js index 3800f4160e6b5f..009d2ca330af2a 100644 --- a/src/math/MathUtils.js +++ b/src/math/MathUtils.js @@ -64,7 +64,7 @@ function euclideanModulo( n, m ) { /** * Performs a linear mapping from range `` to range `` - * for the given value. + * for the given value. `a2` must be greater than `a1`. * * @param {number} x - The value to be mapped. * @param {number} a1 - Minimum value for range A. @@ -159,9 +159,9 @@ function pingpong( x, length = 1 ) { * * See [Smoothstep](http://en.wikipedia.org/wiki/Smoothstep) for more details. * - * @param {number} x - The value to evaluate based on its position between min and max. - * @param {number} min - The min value. Any x value below min will be `0`. - * @param {number} max - The max value. Any x value above max will be `1`. + * @param {number} x - The value to evaluate based on its position between `min` and `max`. + * @param {number} min - The min value. Any `x` value below `min` will be `0`. `min` must be lower than `max`. + * @param {number} max - The max value. Any `x` value above `max` will be `1`. `max` must be greater than `min`. * @return {number} The alternated value. */ function smoothstep( x, min, max ) { @@ -177,11 +177,11 @@ function smoothstep( x, min, max ) { /** * A [variation on smoothstep](https://en.wikipedia.org/wiki/Smoothstep#Variations) - * that has zero 1st and 2nd order derivatives at x=0 and x=1. + * that has zero 1st and 2nd order derivatives at `x=0` and `x=1`. * - * @param {number} x - The value to evaluate based on its position between min and max. - * @param {number} min - The min value. Any x value below min will be `0`. - * @param {number} max - The max value. Any x value above max will be `1`. + * @param {number} x - The value to evaluate based on its position between `min` and `max`. + * @param {number} min - The min value. Any `x` value below `min` will be `0`. `min` must be lower than `max`. + * @param {number} max - The max value. Any `x` value above `max` will be `1`. `max` must be greater than `min`. * @return {number} The alternated value. */ function smootherstep( x, min, max ) { @@ -294,7 +294,7 @@ function isPowerOfTwo( value ) { /** * Returns the smallest power of two that is greater than or equal to the given number. * - * @param {number} value - The value to find a POT for. + * @param {number} value - The value to find a POT for. Must be greater than `0`. * @return {number} The smallest power of two that is greater than or equal to the given number. */ function ceilPowerOfTwo( value ) { @@ -306,7 +306,7 @@ function ceilPowerOfTwo( value ) { /** * Returns the largest power of two that is less than or equal to the given number. * - * @param {number} value - The value to find a POT for. + * @param {number} value - The value to find a POT for. Must be greater than `0`. * @return {number} The largest power of two that is less than or equal to the given number. */ function floorPowerOfTwo( value ) { From 0768730baf6069ae342893f23a7196c98eb7d942 Mon Sep 17 00:00:00 2001 From: Tobias <124624771+TobiasNoell@users.noreply.github.com> Date: Thu, 22 Jan 2026 09:35:07 +0100 Subject: [PATCH 3/8] OrbitControls: Expose pan, rotate and dolly methods. (#32810) --- examples/jsm/controls/OrbitControls.js | 61 ++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/examples/jsm/controls/OrbitControls.js b/examples/jsm/controls/OrbitControls.js index 10bf8437214498..ff9c1b2f22cd95 100644 --- a/examples/jsm/controls/OrbitControls.js +++ b/examples/jsm/controls/OrbitControls.js @@ -594,6 +594,67 @@ class OrbitControls extends Controls { } + /** + * Programmatically pan the camera. + * + * @param {number} deltaX - The horizontal pan amount in pixels. + * @param {number} deltaY - The vertical pan amount in pixels. + */ + pan( deltaX, deltaY ) { + + this._pan( deltaX, deltaY ); + this.update(); + + } + + /** + * Programmatically dolly in (zoom in for perspective camera). + * + * @param {number} dollyScale - The dolly scale factor. + */ + dollyIn( dollyScale ) { + + this._dollyIn( dollyScale ); + this.update(); + + } + + /** + * Programmatically dolly out (zoom out for perspective camera). + * + * @param {number} dollyScale - The dolly scale factor. + */ + dollyOut( dollyScale ) { + + this._dollyOut( dollyScale ); + this.update(); + + } + + /** + * Programmatically rotate the camera left (around the vertical axis). + * + * @param {number} angle - The rotation angle in radians. + */ + rotateLeft( angle ) { + + this._rotateLeft( angle ); + this.update(); + + } + + /** + * Programmatically rotate the camera up (around the horizontal axis). + * + * @param {number} angle - The rotation angle in radians. + */ + rotateUp( angle ) { + + this._rotateUp( angle ); + this.update(); + + } + update( deltaTime = null ) { const position = this.object.position; From e1c93eecd5b5946e15431a928d932712d9454944 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Thu, 22 Jan 2026 10:06:06 +0100 Subject: [PATCH 4/8] WGSLNodeBuilder: Fix out-of-bounds access with `textureLoad()`. (#32817) --- src/math/MathUtils.js | 2 +- src/renderers/webgpu/nodes/WGSLNodeBuilder.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/math/MathUtils.js b/src/math/MathUtils.js index 009d2ca330af2a..25a898cd2fa39e 100644 --- a/src/math/MathUtils.js +++ b/src/math/MathUtils.js @@ -177,7 +177,7 @@ function smoothstep( x, min, max ) { /** * A [variation on smoothstep](https://en.wikipedia.org/wiki/Smoothstep#Variations) - * that has zero 1st and 2nd order derivatives at `x=0` and `x=1`. + * that has zero 1st and 2nd order derivatives at `x=0` and `x=1`. * * @param {number} x - The value to evaluate based on its position between `min` and `max`. * @param {number} min - The min value. Any `x` value below `min` will be `0`. `min` must be lower than `max`. diff --git a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js index 0ab20d6ed90eb0..22630473cd03d7 100644 --- a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +++ b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js @@ -525,7 +525,9 @@ class WGSLNodeBuilder extends NodeBuilder { } - uvSnippet = `${ vecType }( ${ wrapFunction }( ${ uvSnippet } ) * ${ vecType }( ${ textureDimension } ) )`; + const textureDimensionMargin = ( vecType === 'vec3' ) ? 'vec3(1,1,1)' : 'vec2(1,1)'; + + uvSnippet = `${ vecType }( ${ wrapFunction }( ${ uvSnippet } ) * ${ vecType }( ${ textureDimension } - ${ textureDimensionMargin } ) )`; return this.generateTextureLoad( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, null ); From 6e4cc1ed26697f4f74e1a346e0394a7a40d58ce5 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Thu, 22 Jan 2026 10:07:31 +0100 Subject: [PATCH 5/8] Camera: Exclude scale from view matrix. (#32805) --- src/cameras/Camera.js | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/cameras/Camera.js b/src/cameras/Camera.js index 333b0b40ec65e2..2c2569639c4476 100644 --- a/src/cameras/Camera.js +++ b/src/cameras/Camera.js @@ -1,6 +1,12 @@ import { WebGLCoordinateSystem } from '../constants.js'; import { Matrix4 } from '../math/Matrix4.js'; import { Object3D } from '../core/Object3D.js'; +import { Vector3 } from '../math/Vector3.js'; +import { Quaternion } from '../math/Quaternion.js'; + +const _position = /*@__PURE__*/ new Vector3(); +const _quaternion = /*@__PURE__*/ new Quaternion(); +const _scale = /*@__PURE__*/ new Vector3(); /** * Abstract base class for cameras. This class should always be inherited @@ -107,7 +113,19 @@ class Camera extends Object3D { super.updateMatrixWorld( force ); - this.matrixWorldInverse.copy( this.matrixWorld ).invert(); + // exclude scale from view matrix to be glTF conform + + this.matrixWorld.decompose( _position, _quaternion, _scale ); + + if ( _scale.x === 1 && _scale.y === 1 && _scale.z === 1 ) { + + this.matrixWorldInverse.copy( this.matrixWorld ).invert(); + + } else { + + this.matrixWorldInverse.compose( _position, _quaternion, _scale.set( 1, 1, 1 ) ).invert(); + + } } @@ -115,7 +133,19 @@ class Camera extends Object3D { super.updateWorldMatrix( updateParents, updateChildren ); - this.matrixWorldInverse.copy( this.matrixWorld ).invert(); + // exclude scale from view matrix to be glTF conform + + this.matrixWorld.decompose( _position, _quaternion, _scale ); + + if ( _scale.x === 1 && _scale.y === 1 && _scale.z === 1 ) { + + this.matrixWorldInverse.copy( this.matrixWorld ).invert(); + + } else { + + this.matrixWorldInverse.compose( _position, _quaternion, _scale.set( 1, 1, 1 ) ).invert(); + + } } From 2de6f3e018d8a7b52da151e5e16df0f3990983ce Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Thu, 22 Jan 2026 15:51:40 +0100 Subject: [PATCH 6/8] Revert "WGSLNodeBuilder: Fix out-of-bounds access with `textureLoad()`." (#32820) --- src/math/MathUtils.js | 2 +- src/renderers/webgpu/nodes/WGSLNodeBuilder.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/math/MathUtils.js b/src/math/MathUtils.js index 25a898cd2fa39e..009d2ca330af2a 100644 --- a/src/math/MathUtils.js +++ b/src/math/MathUtils.js @@ -177,7 +177,7 @@ function smoothstep( x, min, max ) { /** * A [variation on smoothstep](https://en.wikipedia.org/wiki/Smoothstep#Variations) - * that has zero 1st and 2nd order derivatives at `x=0` and `x=1`. + * that has zero 1st and 2nd order derivatives at `x=0` and `x=1`. * * @param {number} x - The value to evaluate based on its position between `min` and `max`. * @param {number} min - The min value. Any `x` value below `min` will be `0`. `min` must be lower than `max`. diff --git a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js index 22630473cd03d7..0ab20d6ed90eb0 100644 --- a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +++ b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js @@ -525,9 +525,7 @@ class WGSLNodeBuilder extends NodeBuilder { } - const textureDimensionMargin = ( vecType === 'vec3' ) ? 'vec3(1,1,1)' : 'vec2(1,1)'; - - uvSnippet = `${ vecType }( ${ wrapFunction }( ${ uvSnippet } ) * ${ vecType }( ${ textureDimension } - ${ textureDimensionMargin } ) )`; + uvSnippet = `${ vecType }( ${ wrapFunction }( ${ uvSnippet } ) * ${ vecType }( ${ textureDimension } ) )`; return this.generateTextureLoad( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, null ); From abea2ceaeed3545189091f2b49b742a2bb0b56c1 Mon Sep 17 00:00:00 2001 From: Michael Herzog Date: Thu, 22 Jan 2026 16:16:29 +0100 Subject: [PATCH 7/8] Update MathUtils.js Clean up. --- src/math/MathUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/MathUtils.js b/src/math/MathUtils.js index 009d2ca330af2a..25a898cd2fa39e 100644 --- a/src/math/MathUtils.js +++ b/src/math/MathUtils.js @@ -177,7 +177,7 @@ function smoothstep( x, min, max ) { /** * A [variation on smoothstep](https://en.wikipedia.org/wiki/Smoothstep#Variations) - * that has zero 1st and 2nd order derivatives at `x=0` and `x=1`. + * that has zero 1st and 2nd order derivatives at `x=0` and `x=1`. * * @param {number} x - The value to evaluate based on its position between `min` and `max`. * @param {number} min - The min value. Any `x` value below `min` will be `0`. `min` must be lower than `max`. From 1afb95601680662310716e6baec9cd1320063d2f Mon Sep 17 00:00:00 2001 From: Tobias <124624771+TobiasNoell@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:17:19 +0100 Subject: [PATCH 8/8] Fix missing iorNode in MeshPhysicalNodeMaterial copy method (#32821) --- src/materials/nodes/MeshPhysicalNodeMaterial.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/materials/nodes/MeshPhysicalNodeMaterial.js b/src/materials/nodes/MeshPhysicalNodeMaterial.js index 83d676698f6162..fd5a11f5978744 100644 --- a/src/materials/nodes/MeshPhysicalNodeMaterial.js +++ b/src/materials/nodes/MeshPhysicalNodeMaterial.js @@ -502,6 +502,8 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { this.specularIntensityNode = source.specularIntensityNode; this.specularColorNode = source.specularColorNode; + this.iorNode = source.iorNode; + this.transmissionNode = source.transmissionNode; this.thicknessNode = source.thicknessNode; this.attenuationDistanceNode = source.attenuationDistanceNode;