Learning shader patching for three.js

Hello Guys,

I have been using three.js for quite some time now.
Now, the obvious next goal is to create custom shaders.

I know creating a shader straight away is not an easy thing. This is where using and patching shaderLib and/or ShaderUniforms might be very helpful for starters like me.

But, there’s no any proper documentation or any tutorial available. Some handful StackOverflow questions do give some hint, but it isn’t sufficient to understand the workflow of those patchings.

Can anyone mention any resource for learning shader patching where noobs like me get some help and help others who want to understand the same thing?

Any help is highly appreciated.

3 Likes

Material.onBeforeCompile() might be useful to you. It’s still a novel feature but there is an example:

https://threejs.org/examples/#webgl_materials_modified

Also read the following issue at github for more information:

4 Likes

Id advise trying to build a simple phong shader using THREE.ShaderMaterial. onBeforeCompile assumes you already know what you’re writing, which may be a bit complicated given the size of the shaders.

1 Like

What I did to start making ShaderMaterials based on existing materials is something like follows. In the following example, in order to extend the MeshLambertMaterial, for example, I used the relevant pieces (shader chunks) that it is made of, essentially re-making the lambert shader, plus added my own parts:

new ShaderMaterial({
  vertexShader: `
    ...
    ${THREE.ShaderChunk.common}
    ... etc, all the same parts that MeshLambertMaterial has ...
    ${THREE.ShaderChunk. envmap_pars_vertex}
    ...

    main() {
      ${THREE.ShaderChunk.lights_lambert_vertex}
      ... etc ...
      ${THREE.ShaderChunk.fog_vertex}

      gl_Position = ....;
    }
  `
  fragmentShader: `... similar here as with vertex shader, add the needed parts plus yours ...`
  uniforms: THREE.UniformsUtils.merge([ THREE.ShaderLib.lambert.uniforms, {
    /* ... custom uniforms here additional to the lambert ones ... */
   // see https://github.com/mrdoob/three.js/blob/dev/src/renderers/shaders/UniformsLib.js
   // and https://github.com/mrdoob/three.js/blob/dev/src/renderers/shaders/ShaderLib.js
  }]) 
})

And then to get an idea of what ${ShaderChunk.<name>} chunks to put in your shaders, take a look at for example the shaders for MeshLambertMaterial: vertex, fragment.

In your shader string, instead of putting #include <common> you’d put ${ShaderChunk.common}, etc.

Basically, you can recreate any of the existing shaders this way, then you can tweak them by adding your own code to them. Once you get enough experience with that, you can start from scratch using only the chunks you need.

It will be lots of trial and error: you’ll get errors in the console, and will have to piece together what’s missing. None of the answers I could find online were definitive, and I could only complete my goal of making custom shaders by just trying it out like above, and seeing what errors WebGL gave, then figuring out what was missing, etc.

Node-based shaders are a new way to make shaders, and much more robust, allowing programmatic combination of multiple shaders. An intro to those by @donmccurdy is here: Three.js NodeMaterial introduction (donmccurdy.com)

2 Likes

While learning and experimenting, I also came across this book and was amazed by the way the writer has designed it.

For all the beginners trying to learn the basics of shader programming, check out this link. Trust me its amazing and noob friendly.

3 Likes