Skip to content

Conversation

@sunag
Copy link
Collaborator

@sunag sunag commented Nov 17, 2025

Closes #31932
Related: #31207 (comment), #32276

Description

As we already know, TSL generates dynamic code, and this code can vary depending on the context. This facilitates global definitions since they operate in a cascading manner, allowing individual parts to better utilize system resources.

Add getOutput context

For cases where RTT using 16bpc is a problem, this should help with performance and would allow the use of material.toneMapped.

renderer.outputColorSpace = THREE.LinearSRGBColorSpace;
renderer.toneMapping = THREE.NoToneMapping;

renderer.contextNode = context( {

	getOutput: ( outputNode, { material } ) => {

		const toneMapping = material.toneMapped ? THREE.NeutralToneMapping : THREE.NoToneMapping;
		const outputColorSpace = THREE.SRGBColorSpace;

		return renderOutput( outputNode, toneMapping, outputColorSpace );

	}

} );

Add replaceDefaultUV() using getUV context

For native textures that haven't been assigned procedural UVs, you can use:

const customUV = ( /*textureNode*/ ) => uv().mul( 2 );

// per material
material.contextNode = replaceDefaultUV( customUV );

// example replacing .color * .map[uv]
material.colorNode = replaceDefaultUV( customUV, materialColor );

Hierarchy

  • Renderer
    • PassNode ( if there is one )
      • Material
        • ContextNode ( per node )
// For update, use a different context or renderer.contextNode.needsUpdate=true.
renderer.contextNode = context();

// For update, use scenePass.needsUpdate=true
scenePass.contextNode = context();

// For update, use material.needsUpdate=true
material.contextNode = context();

@sunag sunag added this to the r182 milestone Nov 17, 2025
@github-actions
Copy link

github-actions bot commented Nov 17, 2025

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 356.97
86.61
356.97
86.61
+0 B
+0 B
WebGPU 617.35
173.31
618.35
173.6
+997 B
+291 B
WebGPU Nodes 615.96
173.06
616.96
173.35
+997 B
+294 B

🌳 Bundle size after tree-shaking

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

Before After Diff
WebGL 488.7
121.39
488.7
121.39
+0 B
+0 B
WebGPU 689.46
189.19
690.39
189.46
+933 B
+272 B
WebGPU Nodes 630.87
172.37
631.81
172.64
+933 B
+270 B

@sunag sunag marked this pull request as ready for review November 17, 2025 05:34
@RenaudRohlinger
Copy link
Collaborator

This sounds awesome, is there a limitation that restrict this to UV? Or could we introduce something more flexible where any property could be altered by overriding context, for example positionLocal, normalLocal and such?

@sunag sunag merged commit 47a70dc into mrdoob:dev Nov 21, 2025
10 checks passed
@sunag
Copy link
Collaborator Author

sunag commented Nov 21, 2025

This sounds awesome, is there a limitation that restrict this to UV? Or could we introduce something more flexible where any property could be altered by overriding context, for example positionLocal, normalLocal and such?

That's a very interesting suggestion, I'll check it out in another PR. Do you already have any use cases?

@mrdoob
Copy link
Owner

mrdoob commented Nov 21, 2025

Was getting this:

src/Three.Core.js, src/Three.WebGPU.Nodes.js → build...
(!) src/nodes/core/ContextNode.js (169:23): A comment

"/*@__PURE__*/"

in "src/nodes/core/ContextNode.js" contains an annotation that Rollup cannot interpret due to the position of the comment. The comment will be removed to avoid issues.
https://rollupjs.org/configuration-options/#pure
/Users/ricardocabello/Work/git/three.js/src/nodes/core/ContextNode.js:169:23
167:  * @returns {ContextNode}
168:  */
169: export const context = /*@__PURE__*/ ( nodeOrValue = null, value = {} ) => {
                            ^
170: 
171:   let node = nodeOrValue;
created build in 1.3s

Fixed: bd2462f

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.

UVNode, normalNode prefragment ? TSL

3 participants