[HN Gopher] Three.js Shading Language
___________________________________________________________________
Three.js Shading Language
Author : bpierre
Score : 154 points
Date : 2024-05-29 10:41 UTC (1 days ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| stanleykm wrote:
| Almost like the old days of fixed function pipelines. The example
| at the top seems a little contrived, I wonder why you would build
| a shader like that.
| bhouston wrote:
| Huh? It allows for programming via JavaScript which is then
| transpiled for WebGL or WebGPU. It doesn't seem fixed function
| at all.
| stanleykm wrote:
| Yeah I get what it is, I was just making an observation of
| how the api appears.
| esperent wrote:
| By this logic we could call any API "fixed function"
| though.
| flohofwoe wrote:
| It _does_ look quite similar to how pixel rendering was
| configured in OpenGL 1.x or Direct3D up to D3D7 (you
| basically had a set of hardwired pixel operations which you
| could stack and combine via API calls).
|
| 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 ;)
| dahart wrote:
| It's common in lots of modern tools to build shader trees using
| UI, this is analogous to that. It's not really fixed function
| because you can make your tree/shader as big as you want and it
| has all of the math functions that GLSL has. Fixed function
| usually means something like a limited fixed set of nodes and
| you can turn the constant knobs.
|
| 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.
| hansworst wrote:
| > big loops or loops with unknown bounds at compile time
|
| That's not allowed in webgl, so I doubt TSL can make it work
| somehow.
| dahart wrote:
| What do you mean, and are you sure? It works in ShaderToy.
| Big loops will happily unroll until the compiler crashes.
| There's a standard trick for doing variable length loops
| (and preventing unrolling): https://shadertoyunofficial.wor
| dpress.com/2017/11/19/avoidin...
| araes wrote:
| Some of the other examples in Three.js are quite a bit more
| complex. https://threejs.org/examples/#webgl_lights_physical
|
| Probably just for introductory ease. Although, admittedly,
| appears to give the impression of nerfed features, rather than
| easy.
| lifthrasiir wrote:
| TSL is not really a language to be pedantic, because it is an
| EDSL to build a common AST that can be translated to the target
| shader language later. All caveats for the overly eager
| evaluation and usual impedance mismatch between JS and TSL data
| model also apply here.
| javawizard wrote:
| Without discounting any of your other points, I just have to
| note the irony in saying:
|
| > TSL is not really a language to be pedantic, because it is an
| EDSL
|
| where the "L" in "EDSL" stands for "language" :)
| btown wrote:
| Just like any sufficiently complex program inevitably grows
| to have both a reimplementation of Lisp _and_ a homegrown
| email client... any sufficiently complex library inevitably
| grows to have people arguing about whether it deserves the
| term language or not!
|
| 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.
| bhouston wrote:
| I've seen this done in C++ for generating GLSL before a few
| times.
|
| 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.
| Const-me wrote:
| > 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.
| esperent wrote:
| > I think the reason is questionable value.
|
| 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.
| pjmlp wrote:
| That is the BabylonJS approach.
| flohofwoe wrote:
| > for example WebGPU derived their shader language from Rust
| which is IMO unreadable by design
|
| 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).
| HammadB wrote:
| a lot of game engines have higher level shading languages
| (often visually programmed) that are long-lived and widely
| used.
| flohofwoe wrote:
| You're essentially building an AST via function calls, this is
| a lot less ergonomic than having a custom programming language
| to describe the AST (especially when building conditions, loops
| and complex math expressions).
|
| 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).
| 10000truths wrote:
| One thing I'd love to see is whether bundlers can "statically
| compile" the TSL nodes via constant propagation into a single
| template literal.
| esperent wrote:
| This is the kind of thing the three.js team spend a lot of time
| discussing and working towards (far too much time in my
| opinion, I'd much rather the effort was spent on improving the
| ecosystem, although thankfully the poimandres collective jumped
| into to fill the gap, for React at least) so I'd say it's
| reasonably likely.
| chii wrote:
| I wonder if it's possible to have a typescript library for
| making these shaders at the type level, such that at compile
| time, each variation of the shader can be generated as a
| static constant string with at most a finite number of
| concatenations etc.
| esperent wrote:
| Maybe, but not from Three.js. They are adamantly against
| Typescript.
| FractalHQ wrote:
| It's so sad too because it adds so much unnecessary suck
| to the project.
| CountHackulus wrote:
| What if we stopped adding layers of abstraction? The idea of
| renderer-agnostic shaders is cool, but in general you want to
| write your shaders for a specific renderer for best performance.
| nh23423fefe wrote:
| What if we have different objectives?
| onion2k wrote:
| If you're writing for three.js and GLSL you've already forgone
| best performance. This is for render agnostic web code - it
| could be running on anything from a low end android tablet to a
| gaming PC, in any browser engine new enough to support WebGL.
| Most developers who use it are looking for a usable API that
| works everywhere possible, and they don't really care _that_
| much about perf because it 'll be faster than all the
| alternatives (JS, canvas, SVG, CSS) even if it's pretty slow
| for a GPU.
| flohofwoe wrote:
| If the alternative is to manually maintain 2..10 (or so)
| versions of each shader for different shading languages, GLSL
| versions or shader variations manually, then code generation or
| transpilation from a common source is a pretty good compromise.
| stevebmark wrote:
| Looks interesting! There is always a tension between high level
| paradigms like this and just writing the damn GLSL. glslify is
| another solution in this space that lets you have more fine
| control over the GLSL, which is usually way less verbose than a
| high level API.
| esperent wrote:
| One major reason for creating TSL is that it's no longer just
| about WebGL and GLSL. There's also WebGPU and WGSL which is
| very different to GLSL. The goal of TSL is to compile to both
| of those plus any future targets.
| jasonjmcghee wrote:
| Has anyone taken a crack at building a shading language debugger?
|
| 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...
| kevingadd wrote:
| RenderDoc has step-through debugging at a pixel and fragment
| level. Click a pixel in the render target view, then open the
| history and select the fragment to debug.
| colonwqbang wrote:
| There is good tooling available, but it tends to be vendor-
| specific and sometimes quite expensive. Here is Arm's tool:
| https://developer.arm.com/Tools%20and%20Software/Graphics%20...
| xpl wrote:
| I think with that threejs' TSL approach there is an opportunity
| to simulate computations in JS instead of translating it to
| GLSL. Just need to write an eagerly-evaluating runtime for
| those EDSL expressions.
|
| 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.
| lights0123 wrote:
| If you're ok with debugging shaders themselves outside an
| engine, SHADERed does an excellent job cross-platform:
| https://shadered.org/blog
| jasonjmcghee wrote:
| Looks super promising.
|
| 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.
| pjmlp wrote:
| There plenty of options in native APIs, the problem is that
| browser vendors keep ignoring 3D tooling.
|
| 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.
| flohofwoe wrote:
| Safari has a (somewhat basic) canvas debugger which also
| works for WebGL. Firefox _had_ one but it was removed "due
| to lack of use" (wtf Mozilla?): https://firefox-source-
| docs.mozilla.org/devtools-user/deprec...
| flohofwoe wrote:
| Native graphics debuggers like those integrated into Xcode (for
| Metal) or Visual Studio (for D3D) allow shader step-debugging,
| as well as RenderDoc (but AFAIK not for all 3D APIs).
| pjmlp wrote:
| This is what happens when everyone decides to break compatibility
| with the shading languages for the Web, instead of what happened
| with Khronos APIs on the native side.
|
| On the other side, it is business as usual given GLSL, HLSL, MSL,
| Slang, PSSL,...
| dahart wrote:
| What do you mean? This is GLSL... a light abstraction on top of
| it anyway, but not a different shading language or breaking
| compatibility. The goal is just to write the GLSL shaders in
| JavaScript.
| pjmlp wrote:
| WebGPU uses WGSL, completely different shading language, Rust
| inspired.
|
| Naturally ThreeJS has to now take care how to provide shaders
| that work across both backends.
| rahkiin wrote:
| GLSL is pretty bad though. Terrible typing system, terrible
| inference, terrible archaic requirements. Awful
| annotations.
|
| 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.
| pjmlp wrote:
| We are all aware of the differences, that wasn't the
| point.
| flohofwoe wrote:
| > The goal is just to write the GLSL shaders in JavaScript.
|
| 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).
___________________________________________________________________
(page generated 2024-05-30 23:03 UTC)