Nodes/WAS Node Suite v3/Three Shader Material
ComfyUI Node Runs on cloud

Three Shader Material

Hand-rolled GLSL, right inside the graph

By WASasquatch·Created 3 years ago·Updated 4 days ago· 1,844
Three Shader Material
    • material
    vertex_shadervarying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }
    fragment_shaderuniform 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); }
    uniforms_json{"time": {"type": "float", "value": 0}, "color": {"type": "color", "value": "#6fdcff"}}
    transparentfalse
    depth_writetrue
    depth_testtrue
    sidefront
    glsl_versiondefault

    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, resolution are on top of what you declare.
    • glsl_version - "default" is GLSL 1 with gl_FragColor; "glsl3" wants an out 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: transparent blends alpha with what's behind; depth_write false suits glow and additive passes; depth_test false 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.

    CategoryWAS Suite/Three

    Inputs (8)

    NameTypeDefaultDescription
    vertex_shaderSTRINGvarying 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_shaderSTRINGuniform 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_jsonSTRING{"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`.
    transparentBOOLEANfalse`true` blends the shader's alpha with what is behind; `false` draws it solid.
    depth_writeBOOLEANtrue`true` records depth so later objects sort behind; `false` suits glow and additive passes.
    depth_testBOOLEANtrue`true` hides the surface behind nearer objects; `false` draws it over everything.
    sideCOMBOfrontWhich faces are drawn. 'front' for closed shapes, 'double' for planes seen from behind.
    glsl_versionCOMBOdefault'default' is GLSL 1 with `gl_FragColor`; 'glsl3' is GLSL 3 and wants an `out vec4` instead.

    Outputs (1)

    NameTypeDescription
    materialTHREE_MATERIALThe surface, for the material socket on Three Mesh.