Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TSL - Clarity For Accessor Methodology #30778

Open
Bug-Reaper opened this issue Mar 21, 2025 · 4 comments
Open

TSL - Clarity For Accessor Methodology #30778

Bug-Reaper opened this issue Mar 21, 2025 · 4 comments
Labels
TSL Three.js Shading Language

Comments

@Bug-Reaper
Copy link
Contributor

Bug-Reaper commented Mar 21, 2025

Description

I keep getting footgunned in TSL and think maybe there's some soft goals we can clarify to provide a more intuitive developer experience.

Namely I'd propose we roadmap this goal:

  1. Attributes, Varyings, and Uniforms that are used in the default shader logic for a node should be available to the developer when they add custom shader logic Fn() for a node.

💁‍♂️

I know the default colorNode can access the texture-uniform controlled by the material's map property. However I cannot access it when declaring custom-logic designed to replace that node.

Similarly I know that the vertexNode can access the instanceMatrix for an instanced mesh. However I cannot access it when declaring custom-logic designed to replace that node.

Sure you could re-import the map prop in a tsl texture() constructor (redundant) or roll your own custom shared instancebufferattributes (painful). The problem is muddled greatly by the fact these are technically possible and thus it can cause us as developers to guess at the intention.

In the current low-documentation/example climate it also creates a longer than usual wild-goose chase for the developer. You naturally assume that the custom logic will have access to the same attribs/uniforms/varyings the default logic has. Especially since so many times you can access the attrib/uniform/varying used in the default logic.

Solution

A clearly stated goal of the language to expose attribs/varys/uniforms in TSL-world Fn() context if they are already exposed to the developer on an object3D like a mesh/material/geometry etc.

Hopefully discourages an ecosystem full of hacky work-arounds to re-create GPU communication in TSL that is already available just not exposed. I also think it'll really help provide clarity to non-core contributors on where they can assist to fill in some low hanging fruit.

I am happy to assist in organization of some type of tracker of this and at the very least add a clarification note to our TSL readme.

Alternatives

I was kind of surprised TSL did not have a more generalized solution to solve the mapping of GPU<->CPU communication. Perhaps there's something there like:

  1. Some generalized way to add/subtract arbitrary props from a material
  2. Lookup table of property-name and type (uniform/attribute/etc),
  3. Some magic more generalized "grab some variable" behavior we see in attribute()
  4. ???
  5. Profit

I've pondered this briefly

Additional context

r174 longterm three.js nerd

Ty for your consideration! Long live TSL!

@Mugen87 Mugen87 added the TSL Three.js Shading Language label Mar 22, 2025
@Makio64
Copy link
Contributor

Makio64 commented Mar 23, 2025

Hi @Bug-Reaper , I also think a super simple example for basic modification of core material is important as well as the capacity to 'hijack' the core materials.

From my understanding the pain point is the uniform for the map ( texture(map) ) is not created with the material but at the building of the material if the colorNode is null so you can't grab it as it doesnt exist yet.. see the code bellow :
https://github.com/mrdoob/three.js/blob/dev/src/materials/nodes/NodeMaterial.js#L744

In my recent TSL project I'm creating more vanilla material answering my need.
Also external libs of more specialized NodeMaterial or part of it ( colorNode / bending / ao etc.. ) will probably appear like tsl-texture.

So for me creating and contributing to this libs is a good way to solve it. A bit like trokita for sdf text in legacy threejs.

@Bug-Reaper
Copy link
Contributor Author

👍 :: Agree w/you @Makio64 some common use-cases are a welcome addition and it felt odd to not have them in the docs. <- Open ears if anyone has example use-case reqs.

👍 :: Great reference info on texture(map) circumstance too. If that is the case then maybe we have TSL variables that are resolved "at the building" step. From the code you reference I made some interesting observations :

/**
* Returns a texture-typed material reference node for the given property name.
*
* @param {string} property - The name of the material property.
* @return {MaterialReferenceNode} A material reference node representing the property access.
*/
getTexture( property ) {
return this.getCache( property === 'map' ? 'map' : property + 'Map', 'texture' );
}

It should be possible to expose getTexture()or I guess more specifically getCache() to custom TSL Fn context. TSL Fn must be declared prior to it being built so surely this is possible. I think it'd also enable us to make custom materials with properties to control uniforms more seamlessly like how built-in materials handle their props. Very nice.

👍 :: In my recent TSL projects I too found myself doing odd work-arounds. That's part of why I put so much thought into this thread. I feel like if I get too many good workarounds I'm never gonna make the improvements to benefit everyone.

Have some stuff to do today/tomorrow. Will see if anyone else has thoughts over the next couple of days. Ty for reading my post!

@Bug-Reaper
Copy link
Contributor Author

Hey @Makio64 did you ever figure out how to update a texture uniform? You mention it in #30050 (comment) but I don't see a proper resolution?

In glsl i will do : uniformBrushMap.value = textureBrush2

In tsl : I didn’t find the solution as I can’t use uniform in textureNode, also I don’t want to pass the texture directly else I can’t change it.

Would love to have a basic example with this one! I couldn't figure it out tho 😳

More generally feel clarity on my goal here. Find all cases where "I could do this in GLSL" and ensure+document how to do. it in TSL.

@Makio64
Copy link
Contributor

Makio64 commented Mar 26, 2025

Yes it was confusing , so texture(...) is an uniform therefore you dont have to pass it into uniform(...) and can simply change his .value. Here a very simple code :

let txt = new TextureLoader().load(url) // threejs texture

// here the shader/node part start
let utxt = texture( txt ) // glsl : uniform sampler2D utxt 
material.colorNode = utxt.sample( uv() ) // glsl : output = texture(utxt, vUv);

//... later in your code update the texture, for example with a new one : 
utxt.value =  new TextureLoader().load( anotherURL ) 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
TSL Three.js Shading Language
Projects
None yet
Development

No branches or pull requests

3 participants