From 1816e9464dd47346c02c30739cfa055ee068c87c Mon Sep 17 00:00:00 2001 From: thelazylama <67310144+thelazylamaGit@users.noreply.github.com> Date: Wed, 25 Mar 2026 13:38:46 +1100 Subject: [PATCH 1/2] TSL: add `hyperbolic` math nodes (#33233) --- src/Three.TSL.js | 6 ++++ src/nodes/math/MathNode.js | 72 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/src/Three.TSL.js b/src/Three.TSL.js index 21c31a436e02e6..9eb134670164e2 100644 --- a/src/Three.TSL.js +++ b/src/Three.TSL.js @@ -40,6 +40,7 @@ export const VarIntent = TSL.VarIntent; export const abs = TSL.abs; export const acesFilmicToneMapping = TSL.acesFilmicToneMapping; export const acos = TSL.acos; +export const acosh = TSL.acosh; export const add = TSL.add; export const addMethodChaining = TSL.addMethodChaining; export const addNodeElement = TSL.addNodeElement; @@ -55,8 +56,10 @@ export const append = TSL.append; export const array = TSL.array; export const arrayBuffer = TSL.arrayBuffer; export const asin = TSL.asin; +export const asinh = TSL.asinh; export const assign = TSL.assign; export const atan = TSL.atan; +export const atanh = TSL.atanh; export const atomicAdd = TSL.atomicAdd; export const atomicAnd = TSL.atomicAnd; export const atomicFunc = TSL.atomicFunc; @@ -140,6 +143,7 @@ export const countLeadingZeros = TSL.countLeadingZeros; export const countOneBits = TSL.countOneBits; export const countTrailingZeros = TSL.countTrailingZeros; export const cos = TSL.cos; +export const cosh = TSL.cosh; export const cross = TSL.cross; export const cubeTexture = TSL.cubeTexture; export const cubeTextureBase = TSL.cubeTextureBase; @@ -498,6 +502,7 @@ export const shiftRight = TSL.shiftRight; export const shininess = TSL.shininess; export const sign = TSL.sign; export const sin = TSL.sin; +export const sinh = TSL.sinh; export const sinc = TSL.sinc; export const skinning = TSL.skinning; export const smoothstep = TSL.smoothstep; @@ -542,6 +547,7 @@ export const subgroupShuffleXor = TSL.subgroupShuffleXor; export const subgroupSize = TSL.subgroupSize; export const subgroupXor = TSL.subgroupXor; export const tan = TSL.tan; +export const tanh = TSL.tanh; export const tangentGeometry = TSL.tangentGeometry; export const tangentLocal = TSL.tangentLocal; export const tangentView = TSL.tangentView; diff --git a/src/nodes/math/MathNode.js b/src/nodes/math/MathNode.js index 22720e143dcdf2..3688c7bd55f338 100644 --- a/src/nodes/math/MathNode.js +++ b/src/nodes/math/MathNode.js @@ -345,11 +345,17 @@ MathNode.CEIL = 'ceil'; MathNode.NORMALIZE = 'normalize'; MathNode.FRACT = 'fract'; MathNode.SIN = 'sin'; +MathNode.SINH = 'sinh'; MathNode.COS = 'cos'; +MathNode.COSH = 'cosh'; MathNode.TAN = 'tan'; +MathNode.TANH = 'tanh'; MathNode.ASIN = 'asin'; +MathNode.ASINH = 'asinh'; MathNode.ACOS = 'acos'; +MathNode.ACOSH = 'acosh'; MathNode.ATAN = 'atan'; +MathNode.ATANH = 'atanh'; MathNode.ABS = 'abs'; MathNode.SIGN = 'sign'; MathNode.LENGTH = 'length'; @@ -590,6 +596,16 @@ export const fract = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.FRACT ).s */ export const sin = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.SIN ).setParameterLength( 1 ); +/** + * Returns the hyperbolic sine of the parameter. + * + * @tsl + * @function + * @param {Node | number} x - The parameter. + * @returns {Node} + */ +export const sinh = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.SINH ).setParameterLength( 1 ); + /** * Returns the cosine of the parameter. * @@ -600,6 +616,16 @@ export const sin = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.SIN ).setPa */ export const cos = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.COS ).setParameterLength( 1 ); +/** + * Returns the hyperbolic cosine of the parameter. + * + * @tsl + * @function + * @param {Node | number} x - The parameter. + * @returns {Node} + */ +export const cosh = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.COSH ).setParameterLength( 1 ); + /** * Returns the tangent of the parameter. * @@ -610,6 +636,16 @@ export const cos = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.COS ).setPa */ export const tan = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.TAN ).setParameterLength( 1 ); +/** + * Returns the hyperbolic tangent of the parameter. + * + * @tsl + * @function + * @param {Node | number} x - The parameter. + * @returns {Node} + */ +export const tanh = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.TANH ).setParameterLength( 1 ); + /** * Returns the arcsine of the parameter. * @@ -620,6 +656,16 @@ export const tan = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.TAN ).setPa */ export const asin = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.ASIN ).setParameterLength( 1 ); +/** + * Returns the inverse hyperbolic sine of the parameter. + * + * @tsl + * @function + * @param {Node | number} x - The parameter. + * @returns {Node} + */ +export const asinh = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.ASINH ).setParameterLength( 1 ); + /** * Returns the arccosine of the parameter. * @@ -630,6 +676,16 @@ export const asin = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.ASIN ).set */ export const acos = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.ACOS ).setParameterLength( 1 ); +/** + * Returns the inverse hyperbolic cosine of the parameter. + * + * @tsl + * @function + * @param {Node | number} x - The parameter. + * @returns {Node} + */ +export const acosh = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.ACOSH ).setParameterLength( 1 ); + /** * Returns the arc-tangent of the parameter. * If two parameters are provided, the result is `atan2(y/x)`. @@ -642,6 +698,16 @@ export const acos = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.ACOS ).set */ export const atan = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.ATAN ).setParameterLength( 1, 2 ); +/** + * Returns the inverse hyperbolic tangent of the parameter. + * + * @tsl + * @function + * @param {Node | number} x - The parameter. + * @returns {Node} + */ +export const atanh = /*@__PURE__*/ nodeProxyIntent( MathNode, MathNode.ATANH ).setParameterLength( 1 ); + /** * Returns the absolute value of the parameter. * @@ -1087,11 +1153,17 @@ addMethodChaining( 'ceil', ceil ); addMethodChaining( 'normalize', normalize ); addMethodChaining( 'fract', fract ); addMethodChaining( 'sin', sin ); +addMethodChaining( 'sinh', sinh ); addMethodChaining( 'cos', cos ); +addMethodChaining( 'cosh', cosh ); addMethodChaining( 'tan', tan ); +addMethodChaining( 'tanh', tanh ); addMethodChaining( 'asin', asin ); +addMethodChaining( 'asinh', asinh ); addMethodChaining( 'acos', acos ); +addMethodChaining( 'acosh', acosh ); addMethodChaining( 'atan', atan ); +addMethodChaining( 'atanh', atanh ); addMethodChaining( 'abs', abs ); addMethodChaining( 'sign', sign ); addMethodChaining( 'length', length ); From ae1269cff9756eb97704e890f97db53fb871a5b5 Mon Sep 17 00:00:00 2001 From: sunag Date: Wed, 25 Mar 2026 00:33:08 -0300 Subject: [PATCH 2/2] WebGPURenderer: Introduce Quad cache per RendeTarget texture (#33228) --- src/renderers/common/Renderer.js | 53 ++++++++++++++++++++--- src/renderers/common/nodes/NodeManager.js | 19 -------- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/renderers/common/Renderer.js b/src/renderers/common/Renderer.js index 898ef9d0961146..a8967b5afd005e 100644 --- a/src/renderers/common/Renderer.js +++ b/src/renderers/common/Renderer.js @@ -418,15 +418,14 @@ class Renderer { this._background = null; /** + * Cache for the fullscreen quad. * This fullscreen quad is used for internal render passes * like the tone mapping and color space output pass. * * @private - * @type {QuadMesh} + * @type {Map} */ - this._quad = new QuadMesh( new NodeMaterial() ); - this._quad.name = 'Output Color Transform'; - this._quad.material.name = 'outputColorTransform'; + this._quadCache = new Map(); /** * A reference to the current render context. @@ -1788,12 +1787,52 @@ class Renderer { */ _renderOutput( renderTarget ) { - const quad = this._quad; + const cacheKey = this._nodes.getOutputCacheKey(); - if ( this._nodes.hasOutputChange( renderTarget.texture ) ) { + let quadData = this._quadCache.get( renderTarget.texture ); + let quad; + + if ( quadData === undefined ) { + + quad = new QuadMesh( new NodeMaterial() ); + quad.name = 'Output Color Transform'; + quad.material.name = 'outputColorTransform'; quad.material.fragmentNode = this._nodes.getOutputNode( renderTarget.texture ); - quad.material.needsUpdate = true; + + quadData = { + quad, + cacheKey + }; + + this._quadCache.set( renderTarget.texture, quadData ); + + // dispose logic + + const dispose = () => { + + quad.material.dispose(); + + this._quadCache.delete( renderTarget.texture ); + + renderTarget.texture.removeEventListener( 'dispose', dispose ); + + }; + + renderTarget.texture.addEventListener( 'dispose', dispose ); + + } else { + + quad = quadData.quad; + + if ( quadData.cacheKey !== cacheKey ) { + + quad.material.fragmentNode = this._nodes.getOutputNode( renderTarget.texture ); + quad.material.needsUpdate = true; + + quadData.cacheKey = cacheKey; + + } } diff --git a/src/renderers/common/nodes/NodeManager.js b/src/renderers/common/nodes/NodeManager.js index 9dc307093fb121..2caf90c8efea77 100644 --- a/src/renderers/common/nodes/NodeManager.js +++ b/src/renderers/common/nodes/NodeManager.js @@ -11,7 +11,6 @@ import { CubeUVReflectionMapping, EquirectangularReflectionMapping, Equirectangu import { hashArray } from '../../../nodes/core/NodeUtils.js'; import { error } from '../../../utils.js'; -const _outputNodeMap = new WeakMap(); const _chainKeys = []; const _cacheKeyValues = []; @@ -854,21 +853,6 @@ class NodeManager extends DataMap { } - /** - * Checks if the output configuration (tone mapping and color space) for - * the given target has changed. - * - * @param {Texture} outputTarget - The output target. - * @return {boolean} Whether the output configuration has changed or not. - */ - hasOutputChange( outputTarget ) { - - const cacheKey = _outputNodeMap.get( outputTarget ); - - return cacheKey !== this.getOutputCacheKey(); - - } - /** * Returns a node that represents the output configuration (tone mapping and * color space) for the current target. @@ -879,14 +863,11 @@ class NodeManager extends DataMap { getOutputNode( outputTarget ) { const renderer = this.renderer; - const cacheKey = this.getOutputCacheKey(); const output = outputTarget.isArrayTexture ? texture( outputTarget, screenUV ).depth( builtin( 'gl_ViewID_OVR' ) ).renderOutput( renderer.toneMapping, renderer.currentColorSpace ) : texture( outputTarget, screenUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace ); - _outputNodeMap.set( outputTarget, cacheKey ); - return output; }