Three Shader Material
Hand-rolled GLSL, right inside the graph
- material
Every node-based 3D system hits the same wall: someone needs an effect the canned materials can't do - a custom dissolve, a hologram shimmer, water that responds to a uniform you control. WASThreeShaderMaterial is the Three family's door out of that wall. It lets you write a GLSL shader as a plain text input and wire it straight into a mesh, no plugin, no compile step, no external tooling. If you've ever written a ShaderToy effect, this is your home turf.
How it works
A shader material is two programs: a vertex shader that runs per vertex and a fragment shader that runs per pixel. You paste GLSL into both fields. The vertex shader must set gl_Position; the fragment shader must set gl_FragColor - or, under glsl_version set to "glsl3," declare an out vec4 instead. The defaults are honest scaffolding: the default vertex shader just passes uv through as vUv, so you start from a working shape and edit.
The clever part for animation is uniforms_json - typed values the shader reads, as JSON like:
{"time": {"type": "float", "value": 0}}
Types available are float, color, vec2, vec3 and vec4. And four uniforms are filled in for you automatically: time, progress, timeline and resolution. That means an animated shader can just read time without you wiring up a clock - the family's timeline drives it.
The inputs that matter
- vertex_shader and fragment_shader - the GLSL itself.
- uniforms_json - typed values the shader reads; the auto-filled
time,progress,timeline,resolutionare on top of what you declare. - glsl_version - "default" is GLSL 1 with
gl_FragColor; "glsl3" wants anout vec4. - side - which faces draw. "front" for closed shapes, "double" for planes seen from behind.
- transparent / depth_write / depth_test - the blend-and-sort trio. The tooltips are the cheat sheet:
transparentblends alpha with what's behind;depth_writefalse suits glow and additive passes;depth_testfalse draws the surface over everything.
Where it fits
Shader Material outputs a THREE_MATERIAL, so it goes wherever a standard or physical material goes - straight into Three Mesh. The geometry feeds it vertices and UVs, so a Three Plane Geometry with enough segments gives a displacement shader something to move. The mental model: Standard Material is the physically-correct workhorse, Physical Material is glass-and-paint, and this one is where you stop asking the pack to do it for you.
The honest note
GLSL is a real programming language and the debugging loop here is browser-side: a shader that fails to compile typically shows up as a black or magenta surface rather than an error in your console of choice. Start from the working defaults and change one line at a time. And the automatic uniforms are keyed to the Three family's timeline, so a shader animated for a 4-second loop behaves predictably across Three Render frames.
Install
WASThreeShaderMaterial ships with WAS Node Suite v3. Install via ComfyUI Manager (search WAS Node Suite v3) or:
cd ComfyUI/custom_nodes
git clone https://github.com/WASasquatch/was-node-suite-comfyui.git
Restart after. Requires ComfyUI 0.14.0+ and Python 3.10+. Missing from Add Node? Check features.threejs in <ComfyUI user dir>/was-node-suite/config.yaml.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| vertex_shader | STRING | varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } | GLSL for each vertex. It must set `gl_Position`; the default passes `uv` through as `vUv`. |
| fragment_shader | STRING | uniform float time; uniform vec3 color; varying vec2 vUv; void main() { float pulse = 0.65 + 0.35 * sin(time * 2.0 + vUv.y * 10.0); gl_FragColor = vec4(color * pulse, 1.0); } | GLSL for each pixel. It must set `gl_FragColor`, or `out vec4` under the `glsl3` version. |
| uniforms_json | STRING | {"time": {"type": "float", "value": 0}, "color": {"type": "color", "value": "#6fdcff"}} | Typed values the shader reads, as `{"time": {"type": "float", "value": 0}}`. Types are float, color, vec2, vec3 and vec4. `time`, `progress`, `timeline` and `resolution` are filled in each frame, and so are `uTime`, `uProgress`, `uTimeline` and `uResolution`. |
| transparent | BOOLEAN | false | `true` blends the shader's alpha with what is behind; `false` draws it solid. |
| depth_write | BOOLEAN | true | `true` records depth so later objects sort behind; `false` suits glow and additive passes. |
| depth_test | BOOLEAN | true | `true` hides the surface behind nearer objects; `false` draws it over everything. |
| side | COMBO | front | Which faces are drawn. 'front' for closed shapes, 'double' for planes seen from behind. |
| glsl_version | COMBO | default | 'default' is GLSL 1 with `gl_FragColor`; 'glsl3' is GLSL 3 and wants an `out vec4` instead. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| material | THREE_MATERIAL | The surface, for the material socket on Three Mesh. |