From 706172153246379ab980e673549e3d5584b95423 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Wed, 18 Feb 2026 21:50:05 -0600 Subject: [PATCH 1/5] Simplified lightTargetDirection TSL calculation. --- src/nodes/accessors/Camera.js | 13 ++++++++++++- src/nodes/accessors/Lights.js | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/nodes/accessors/Camera.js b/src/nodes/accessors/Camera.js index 331d331c297a79..31ebce37c5071b 100644 --- a/src/nodes/accessors/Camera.js +++ b/src/nodes/accessors/Camera.js @@ -1,7 +1,7 @@ import { uniform } from '../core/UniformNode.js'; import { renderGroup, sharedUniformGroup } from '../core/UniformGroupNode.js'; import { Vector3 } from '../../math/Vector3.js'; -import { Fn, vec4 } from '../tsl/TSLBase.js'; +import { Fn, vec4, mat3 } from '../tsl/TSLBase.js'; import { uniformArray } from './UniformArrayNode.js'; import { builtin } from './BuiltinNode.js'; import { screenSize } from '../display/ScreenNode.js'; @@ -197,6 +197,17 @@ export const cameraViewMatrix = /*@__PURE__*/ ( Fn( ( { camera } ) => { } ).once() )(); +/** + * TSL object that represents the world-to-view rotation matrix of the camera used for the current render. + * + * It is the upper-left 3x3 of {@link cameraViewMatrix} (translation removed) and is typically used to transform + * direction vectors (e.g. normals) from world space into view space. + * + * @tsl + * @type {Node} + */ +export const worldToViewRotation = /*@__PURE__*/ mat3( cameraViewMatrix[ 0 ].xyz, cameraViewMatrix[ 1 ].xyz, cameraViewMatrix[ 2 ].xyz ).toVar(); + /** * TSL object that represents the world matrix of the camera used for the current render. * diff --git a/src/nodes/accessors/Lights.js b/src/nodes/accessors/Lights.js index ac4245aca26faa..b805213cfd1610 100644 --- a/src/nodes/accessors/Lights.js +++ b/src/nodes/accessors/Lights.js @@ -1,7 +1,7 @@ import { uniform } from '../core/UniformNode.js'; import { renderGroup } from '../core/UniformGroupNode.js'; import { Vector3 } from '../../math/Vector3.js'; -import { cameraViewMatrix } from './Camera.js'; +import { worldToViewRotation } from './Camera.js'; import { positionWorld } from './Position.js'; let uniformsLib; @@ -136,4 +136,4 @@ export function lightViewPosition( light ) { * @param {Light} light -The light source. * @returns {Node} The light's target direction. */ -export const lightTargetDirection = ( light ) => cameraViewMatrix.transformDirection( lightPosition( light ).sub( lightTargetPosition( light ) ) ); +export const lightTargetDirection = ( light ) => worldToViewRotation.mul( lightPosition( light ).sub( lightTargetPosition( light ) ) ).normalize(); From 3e37d95b52d0cd2f363d107b7d0fa97ab0022524 Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Thu, 19 Feb 2026 22:05:15 -0600 Subject: [PATCH 2/5] Using worldToViewRotation in Normal.js. --- src/nodes/accessors/Normal.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nodes/accessors/Normal.js b/src/nodes/accessors/Normal.js index 9ba97f3f44a879..acaf8263308859 100644 --- a/src/nodes/accessors/Normal.js +++ b/src/nodes/accessors/Normal.js @@ -1,5 +1,5 @@ import { attribute } from '../core/AttributeNode.js'; -import { cameraViewMatrix } from './Camera.js'; +import { cameraViewMatrix, worldToViewRotation } from './Camera.js'; import { modelNormalMatrix, modelWorldMatrix } from './ModelNode.js'; import { mat3, vec3, Fn } from '../tsl/TSLBase.js'; import { positionView } from './Position.js'; @@ -194,7 +194,7 @@ export const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) = const transformedNormal = modelNormalMatrix.mul( normal ); - return cameraViewMatrix.transformDirection( transformedNormal ); + return worldToViewRotation.mul( transformedNormal ); } ); From 2754e5ac3ae50906c8790e0102ec04c5055f694f Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Tue, 3 Mar 2026 17:59:29 -0600 Subject: [PATCH 3/5] Ensure normalize() is called where needed. --- src/nodes/accessors/Normal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nodes/accessors/Normal.js b/src/nodes/accessors/Normal.js index acaf8263308859..b59c909988852e 100644 --- a/src/nodes/accessors/Normal.js +++ b/src/nodes/accessors/Normal.js @@ -194,7 +194,7 @@ export const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) = const transformedNormal = modelNormalMatrix.mul( normal ); - return worldToViewRotation.mul( transformedNormal ); + return worldToViewRotation.mul( transformedNormal ).normalize(); } ); From f45e9e54b057ed2164884cb173c717fbf561d08b Mon Sep 17 00:00:00 2001 From: PoseidonEnergy Date: Wed, 4 Mar 2026 17:08:14 -0600 Subject: [PATCH 4/5] Renamed to 'cameraViewRotationMatrix'. --- src/nodes/accessors/Camera.js | 12 ++++++++++-- src/nodes/accessors/Lights.js | 4 ++-- src/nodes/accessors/Normal.js | 4 ++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/nodes/accessors/Camera.js b/src/nodes/accessors/Camera.js index 31ebce37c5071b..6cfe24bb1961d8 100644 --- a/src/nodes/accessors/Camera.js +++ b/src/nodes/accessors/Camera.js @@ -198,7 +198,7 @@ export const cameraViewMatrix = /*@__PURE__*/ ( Fn( ( { camera } ) => { } ).once() )(); /** - * TSL object that represents the world-to-view rotation matrix of the camera used for the current render. + * TSL object that represents the view rotation matrix of the camera used for the current render. * * It is the upper-left 3x3 of {@link cameraViewMatrix} (translation removed) and is typically used to transform * direction vectors (e.g. normals) from world space into view space. @@ -206,7 +206,15 @@ export const cameraViewMatrix = /*@__PURE__*/ ( Fn( ( { camera } ) => { * @tsl * @type {Node} */ -export const worldToViewRotation = /*@__PURE__*/ mat3( cameraViewMatrix[ 0 ].xyz, cameraViewMatrix[ 1 ].xyz, cameraViewMatrix[ 2 ].xyz ).toVar(); +export const cameraViewRotationMatrix = /*@__PURE__*/ mat3( + + cameraViewMatrix[ 0 ].xyz, + + cameraViewMatrix[ 1 ].xyz, + + cameraViewMatrix[ 2 ].xyz + +).toVar( 'cameraViewRotationMatrix' ); /** * TSL object that represents the world matrix of the camera used for the current render. diff --git a/src/nodes/accessors/Lights.js b/src/nodes/accessors/Lights.js index b805213cfd1610..df20bd75bb8375 100644 --- a/src/nodes/accessors/Lights.js +++ b/src/nodes/accessors/Lights.js @@ -1,7 +1,7 @@ import { uniform } from '../core/UniformNode.js'; import { renderGroup } from '../core/UniformGroupNode.js'; import { Vector3 } from '../../math/Vector3.js'; -import { worldToViewRotation } from './Camera.js'; +import { cameraViewRotationMatrix } from './Camera.js'; import { positionWorld } from './Position.js'; let uniformsLib; @@ -136,4 +136,4 @@ export function lightViewPosition( light ) { * @param {Light} light -The light source. * @returns {Node} The light's target direction. */ -export const lightTargetDirection = ( light ) => worldToViewRotation.mul( lightPosition( light ).sub( lightTargetPosition( light ) ) ).normalize(); +export const lightTargetDirection = ( light ) => cameraViewRotationMatrix.mul( lightPosition( light ).sub( lightTargetPosition( light ) ) ).normalize(); diff --git a/src/nodes/accessors/Normal.js b/src/nodes/accessors/Normal.js index b59c909988852e..6f97cafd2c2a97 100644 --- a/src/nodes/accessors/Normal.js +++ b/src/nodes/accessors/Normal.js @@ -1,5 +1,5 @@ import { attribute } from '../core/AttributeNode.js'; -import { cameraViewMatrix, worldToViewRotation } from './Camera.js'; +import { cameraViewMatrix, cameraViewRotationMatrix } from './Camera.js'; import { modelNormalMatrix, modelWorldMatrix } from './ModelNode.js'; import { mat3, vec3, Fn } from '../tsl/TSLBase.js'; import { positionView } from './Position.js'; @@ -194,7 +194,7 @@ export const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) = const transformedNormal = modelNormalMatrix.mul( normal ); - return worldToViewRotation.mul( transformedNormal ).normalize(); + return cameraViewRotationMatrix.mul( transformedNormal ).normalize(); } ); From 5ff424951283fd9ce1a561456276b95698587147 Mon Sep 17 00:00:00 2001 From: sunag Date: Wed, 4 Mar 2026 23:48:03 -0300 Subject: [PATCH 5/5] re-add `worldToViewRotation` as TSL function --- src/nodes/accessors/Camera.js | 9 +++++++++ src/nodes/accessors/Lights.js | 4 ++-- src/nodes/accessors/Normal.js | 4 ++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/nodes/accessors/Camera.js b/src/nodes/accessors/Camera.js index 6cfe24bb1961d8..4264831b7d469f 100644 --- a/src/nodes/accessors/Camera.js +++ b/src/nodes/accessors/Camera.js @@ -216,6 +216,15 @@ export const cameraViewRotationMatrix = /*@__PURE__*/ mat3( ).toVar( 'cameraViewRotationMatrix' ); +/** + * TSL function that transforms a vector from world space to view space. + * + * @tsl + * @param {Node} vector The vector to transform. + * @returns {Node} + */ +export const worldToViewRotation = Fn( ( [ vector ] ) => cameraViewRotationMatrix.mul( vector ) ); + /** * TSL object that represents the world matrix of the camera used for the current render. * diff --git a/src/nodes/accessors/Lights.js b/src/nodes/accessors/Lights.js index df20bd75bb8375..bd970476c9eead 100644 --- a/src/nodes/accessors/Lights.js +++ b/src/nodes/accessors/Lights.js @@ -1,7 +1,7 @@ import { uniform } from '../core/UniformNode.js'; import { renderGroup } from '../core/UniformGroupNode.js'; import { Vector3 } from '../../math/Vector3.js'; -import { cameraViewRotationMatrix } from './Camera.js'; +import { worldToViewRotation } from './Camera.js'; import { positionWorld } from './Position.js'; let uniformsLib; @@ -136,4 +136,4 @@ export function lightViewPosition( light ) { * @param {Light} light -The light source. * @returns {Node} The light's target direction. */ -export const lightTargetDirection = ( light ) => cameraViewRotationMatrix.mul( lightPosition( light ).sub( lightTargetPosition( light ) ) ).normalize(); +export const lightTargetDirection = ( light ) => worldToViewRotation( lightPosition( light ).sub( lightTargetPosition( light ) ) ).normalize(); diff --git a/src/nodes/accessors/Normal.js b/src/nodes/accessors/Normal.js index 6f97cafd2c2a97..b8fe28399750cb 100644 --- a/src/nodes/accessors/Normal.js +++ b/src/nodes/accessors/Normal.js @@ -1,5 +1,5 @@ import { attribute } from '../core/AttributeNode.js'; -import { cameraViewMatrix, cameraViewRotationMatrix } from './Camera.js'; +import { cameraViewMatrix, worldToViewRotation } from './Camera.js'; import { modelNormalMatrix, modelWorldMatrix } from './ModelNode.js'; import { mat3, vec3, Fn } from '../tsl/TSLBase.js'; import { positionView } from './Position.js'; @@ -194,7 +194,7 @@ export const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) = const transformedNormal = modelNormalMatrix.mul( normal ); - return cameraViewRotationMatrix.mul( transformedNormal ).normalize(); + return worldToViewRotation( transformedNormal ).normalize(); } );