I see no reason why TSL couldn’t check if the uniform node is set at run time. I believe in the shader, there is no such thing as a “null” texture, but the TSL node could be set up to support something like that on the JavaScript side.
It was more of a question, rather than a statement.
The reason is that there are two “run-times” in TSL. The first one is when a TSL function is executed – this is done before it is compiled to a shader; and the second is when the shader itself is executed.
Some node data is only available during the first phase, while other node data is passed down to the second phase.
If isSet uses data that is not passed down, then isSet is run only during the first phase, so the texture check is done only once and the result is hardcoded in the shader. In this case you do not need TSL If.
If isSet uses data that exists in the low-level shader, then the check is done many times during rendering. As only fragments of node data are passed down the shader code, I’m not aware whether mapNode as a node exists there. Honestly, I’d be surprised. But it depends on TSL internals which I’m not familiar with.
TSL couldn’t check if the uniform node is set at run time
Yes, I also believe so. TSL could check this but only once and only during function compilation, as this is the only moment when a TSL function is run.
Yes, I also believe so. TSL could check this but only once and only during function compilation, as this is the only moment when a TSL function is run.
I would just assume uniform.isSet() or just simply uniform.isSet would function identically to how (for example) node.greaterThan(0) works. It would probably be better for it to just be a property (not a function) like uniform.isSet.
I see what you mean. These two cases look very different: node.greaterThan(0) can be compiled as there is shader operation for comparing numbers; but I do not remember any instruction to test whether a uniform is set … because there is no such thing – uniforms are always initialized either by the user, or automatically with 0. The only way to find whether a uniform is being explicitly initialized is to dedicate a special magic unexpected value and check against it. As for textures the trick was (if I remember it correctly) to query for the texture size and if it is 0, then there is no valid texture. I hope someone with a better TSL understanding would provide more accurate info, as mine might be outdated.
If you have a proposal for node.isSet, you can file it as an issue in Three.js GitHub, so the developers would consider implementing it.
So the solution for now (but possibly forever?) is to make a uniform bool “isFooSet” and check for null in JavaScript? This is because WebGL, opengl, vulkan, metal etc don’t specify an “is uniform ‘set’” instruction - a uniform is either created or not?
And null itself is ambiguous, I think threejs itself creates a null texture object rather than using the null value itself.
Maybe, although it could be possible for TSL to have single uniform node at TSL level (e.g. named foo), but to automatically manage two uniform variables at shader level (e.g. foo and isFooSet). So, technically it is possible, but I’m not sure whether this is a good idea or bad idea – most uniforms do not need this.
One specific use case is if you have a material applied to an object in your scene, that switches between a solid color and a diffuse map. For example, an unlit billboard that can either be “off” (solid black color, no diffuse map) or “on” (diffuse map is set).
This way you could set many billboards to use the same material, and be able to turn all the billboards on and off by setting/unsetting the diffuse map.
But you can do that by just setting a Boolean uniform. I still don’t see why you would want to change how the underlying API and hardware basically work. Or, by multiplying a color with your texture. (Black is null white is not null).
I would not implement some sort of “setness” to the next generation of graphics cards if all I want to do is multiply color A (texture) with color b (black/white mask). Any shader language including TSL and any programmable pipeline can do that.
I have an object with a floor, ceiling, walls, etc.
If you use the material as normal it works as expected, but what if you wanted to have a different texture on the floor?
Well you make a wallTexture and then a floorTexture, then all the rest.
I have to pass a bool too each time which is annoying, and doubles the uniforms I have to create.
Yes theres ways like buffers or bit conditionals etc. but I get the issue.
texture actually does this internally, but when you pass null it tells it to pass nothing. I think if you did undefined or set the UV’s outside the constructor it would do what you want.
To check is another thing though, you can do texture.value which will return the reference object, and if its the empty texture the uuid should be the same regardless of instance. So you could make a utility function like IfTextureSet(texture, secondAction); that gets the uuid of the empty texture and checks if the uuid of the texture is the same etc.
I’m playing with this idea now, if I find a cleaner pattern I’ll update