Three.js Shading Language
github.com
github.com
> TSL is not really a language to be pedantic, because it is an EDSL
where the "L" in "EDSL" stands for "language" :)
EDIT: I wish I were smart enough to have come up with these references, but I'm entirely riffing on https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule and https://en.wikipedia.org/wiki/Jamie_Zawinski#Zawinski's_Law . I can say from personal experience that both adages are resoundingly true.
One from Waterloo Univeesity in the early 2000s became RapidMind: http://web.cs.ucla.edu/~palsberg/course/cs239/papers/rapidmi...
There were a few others, but I can not remember their names.
Generally these techniques work, but for some reason they tend to die out.
I think the reason is questionable value.
Native GPU programming languages, HLSL and GLSL, have a simple and readable syntax. The complexity is not in the language, it’s in the runtime and surrounding infrastructure: weird execution model with these wavefronts and interleaved programmable/fixed function blocks in the graphics pipeline, weird memory model with load/store coalescence and manually managed groupshared, weird IO without even printf() available, and poor tooling (I think only CUDA did it right).
Replacing the programming language does nothing with execution model, memory model, and IO. These quirks come from the hardware not software and are inevitable. Custom languages break tooling: RenderDoc HLSL debugger is not great but much better than nothing. Sometimes they break other things as well, for example WebGPU derived their shader language from Rust which is IMO unreadable by design.
It's my hope, having casually followed the development of the three.js shader nodes and now TSL, that they will end up getting wrapped up into a visual node editor of high quality. As far a I'm aware, they have made some attempt at following the MaterialX spec which should help here.
So even if writing code in TSL has limited utility over pure shader code (I don't have an opinion here but I've seen it brought up a few times), it should make writing a three.js visual node editor much simpler.
The reason why typical Rust code is so unreadable is not because the type is on the right side ;)
The same 'readability argument' could be brought up with HLSL and MSL too because of their similarity to C++ - "modern C++" code typically isn't very readable either unless the reader closely followed C++ development since around 1998 or so.
FWIW I consider WGSL syntax a pretty good balance between simplicity and convenience (much better than "GLSL 300 es" anyway).
The surrounding infrastructure is atrocious on top of that, but the idea that shading languages are fine is just off-base. They don't have real module systems, they don't let you compose, and the norm is still just to use preprocessor hacks to produce shader variants.
(this is why I built Use.GPU around a modular WGSL linker)
It could be a good base for a noodle graph shader editor though (or even for a language compiler outside of three.js which compiles to "TLS" Javascript code - but at that point (of having an offline compile step) why not get rid of the middleman and compile from (yet another) custom shading language to GLSL or WGSL directly).
Funny enough, the new work graph stuff in D3D12 is also configured in a similar way (by essentially building an AST-like tree of operations via API calls).
We really came around full circle ;)
Unless I missed it somewhere, the two nodes that seem to be missing here are an if() node and a loop() node. I’m guessing a loop() node can be done on the JavaScript side for small loops - it’d be the same as loop unrolling. For big loops or loops with unknown bounds at compile time, it’s not clear if there’s a way with TSL. You can simulate if() behavior using the nodes provided, but you can’t avoid executing both sides of the if().
It’s been a long time since I wrote a three.js shader, so I’m not sure what the “old” example is doing. It looks like it might be a little dynamic code injection to convert from a typical GLSL shader to something three.js needs.
That’s not allowed in webgl, so I doubt TSL can make it work somehow.
Probably just for introductory ease. Although, admittedly, appears to give the impression of nerfed features, rather than easy.
On the other side, it is business as usual given GLSL, HLSL, MSL, Slang, PSSL,...
Naturally ThreeJS has to now take care how to provide shaders that work across both backends.
Metal and HLSL are more modern. Mostly because Metal started as such and HLSL was updated. Both C++ inspired or even using clang. WGSL has a rust-like syntax but Metal-like semantics and structure.
I bet the main goal is generating both GLSL and WGSL shaders depending on the 3D backend. Usually shader language transpilation is done through native libraries like SPIRVCross (C++), Tint (C++) or Naga (Rust), but those are too heavy for being included in a three.js webpage and offline compilation probably doesn't quite fit three.js' spirit (or requirements if they need to stamp out a different shader variation based on runtime parameters).
I want to be able to step through a shader and see the values at each step (ideally for any / every pixel)
The best case scenario would be while it's actually running, but simulating it seems like a great solution too.
These are the best I could find: https://github.com/burg/glsl-simulator and https://github.com/cdave1/shdr - both seem to be missing a fair amount of features, though shdr seems like much better support.
There's also: https://glsl-debugger.github.io/ but it doesn't support OS X and feels quite out of date.
There's "print statements" for wgsl: https://github.com/looran/wgsl-debug
I guess WGSL is the up and comer... as opposed to GLSL - but both would be great.
Anyone else have this hope/dream?
The hacks I use today are crazy - like conditionally exiting early based on a time variable and mapping values to colors.
So many folks I talk to are like, "yeah that's how it is". But this just seems not good enough to me...
Once it's done, you'll be able to use the regular Chrome's Devtools debugger to step through TSL logic.
A nice thing is that would also allow you to unit-test your shading code using regular JS frameworks for testing.
Don't see a OS X client and the web version seems quite buggy - a number of the ones I tried to open loaded infinitely (with errors in the console).
I'll give it a shot on Windows...
Edit: Yeah, this is certainly a step forward compared to what I've been doing.
Being able to choose a quad/triangle/pixel and step through breakpoints is fantastic.
Not the best interface / ux, but it's motivating.
The only thing that exists is SpectorJS and is barely maintained.
So you're left with having a native implementation of the 3D coding, face the challenge to differentiate between browser and web app calls, or classical print pixel debugging.
I fully agree that is crazy Khronos and browser vendors don't see this as an issue, after a decade.