Skip to content

TextureNode: allow for non-mergeable uniforms - #34450

Merged
sunag merged 1 commit into
mrdoob:devfrom
Mirei3D:non-mergeable-texture-uniforms
Sep 17, 2026
Merged

sunag merged 1 commit into
mrdoob:devfrom
Mirei3D:non-mergeable-texture-uniforms

Conversation

@Mirei3D

@Mirei3D Mirei3D commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Related issue: #34393

Description

Right now two texture uniforms always will be merged if they use the same texture at compile-time.
This means that a material might need to be rebuilt whenever a texture uniform changes, since two uniforms that share the same texture suddenly might not.

I think the best solution here is to optionally merge texture uniforms based on a shared reference node instead of a shared texture. This allows for changing texture uniforms without needing a rebuild and enables better program reuse in some cases.

This PR introduces a mergeable flag on TextureNode (default is true). It also changes uniformTexture() and uniformCubeTexture() to create non-mergeable uniforms. I figured this made sense given the names and that texture() and cubeTexture() already exist to directly sample textures or create mergeable uniform (the way it works right now).

Would love feedback regarding if the change makes sense to begin with, the name of the new property and if uniformTexture() / uniformCubeTexture() behaviour should be changed or not.

This contribution is funded by BitReality

@github-actions

github-actions Bot commented Sep 3, 2026 •

Copy link
Copy Markdown

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
Core 389.51
102.17
389.51
102.17
+0 B
+0 B
WebGL 379.11
88.92
379.11
88.92
+0 B
+0 B
WebGPU 711.83
195.86
712.21
195.93
+372 B
+74 B
WebGPU Nodes 709.82
195.55
710.19
195.62
+372 B
+74 B

🌳 Bundle size after tree-shaking

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

Before After Diff
WebGL 523.73
126.08
523.73
126.08
+0 B
+0 B
WebGPU 765.78
205.43
766.09
205.5
+304 B
+66 B
WebGPU Nodes 711.87
192.09
712.18
192.14
+304 B
+53 B

@Mirei3D
Mirei3D force-pushed the non-mergeable-texture-uniforms branch 2 times, most recently from 12932a3 to f3e9e43 Compare September 3, 2026 11:46
@gkjohnson

Copy link
Copy Markdown
Collaborator

I have not bee available to respond to #34393 but I still feel very strongly that user graphs should not be modified against the users intent and that a "mergeable" flag on the node feels like a pretty heavy handed band-aid. If anything the "textureUniform" should behave only as the name implies (a new unique uniform is created always and is not merged) and a separate dedicated node should be designed that supports auto merging and implies the texture won't change - "staticTexture" or something. I'm still not convinced that's needed and that this merge behavior wasn't an early optimization.

I will try to respond to issues next week.

@Mirei3D

Mirei3D commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor Author

I still feel very strongly that user graphs should not be modified against the users intent and that a "mergeable" flag on the node feels like a pretty heavy handed band-aid.

I agree, it's a band-aid. It appears to me that this optimisation more so exists because of TSLs unique design rather than solving a real problem. I'm not sure how much support there would be for changing the system though. There probably already is a bunch of code using repeated texture() calls for the same texture.

If anything the "textureUniform" should behave only as the name implies (a new unique uniform is created always and is not merged)

This is why I was hoping we could change the behaviour of uniformTexture() (which has zero uses in Three.js itself) to create a "non-mergeable" TextureNode, while keeping the behaviour of texture() in tact. The former implies the creation of a uniform much more than the latter.

If the mergeable property on TextureNode is bothersome I guess it could be renamed to isStatic and made default false (as in default would be no optimization). texture() would then create a static TextureNode. Changing the value of a static node could also be deprecated (log a deprecation warning) and eventually disallowed?

@Mirei3D
Mirei3D force-pushed the non-mergeable-texture-uniforms branch from f3e9e43 to 2694293 Compare September 11, 2026 09:38
@Mirei3D
Mirei3D force-pushed the non-mergeable-texture-uniforms branch from 2694293 to cab68ab Compare September 11, 2026 09:43
@Mirei3D

Mirei3D commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Pushed a small fix, which should have no effect on the behaviour but is more correct regardless (passing the NodeBuilder through to getHash() properly)

@sunag sunag added this to the r187 milestone Sep 17, 2026
@sunag
sunag merged commit f913b42 into mrdoob:dev Sep 17, 2026
10 checks passed
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.

3 participants