• Stars
    star
    721
  • Rank 62,814 (Top 2 %)
  • Language
    JavaScript
  • License
    Other
  • Created about 10 years ago
  • Updated about 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Functional GLSL Linker

shadergraph

Functional GLSL linker

Shader Graph

ShaderGraph is a library for linking together GLSL snippets into stand-alone shaders. It is mainly meant to build complicated shaders 100% programmatically. But it can also act as the back-end to a live graph-based shader editor, as its graph model is persistent.

Snippets can be simple one-liners, or multi-function source files. Snippets can also declare callbacks, as functions without bodies, linked in from elsewhere. This allows complicated execution flows to be built very easily.

vec3 getColor();
void main() {
  gl_FragColor = vec4(getColor(), 1.0);
}

ShaderGraph is designed to play well with Three.js, but does not depend on it. It merely follows the same code/object conventions.

There is no editing UI included, only a way to display a graph as an HTML/CSS/SVG diagram.


Live Examples

ShaderGraph

ShaderGraph 2 drives all shaders in MathBox² (in development). For more info, see the articles on acko.net:

Here's a real-world vertex shader for a line primitive, sampling color and position from two textures:

MathBox 2 - Audio Visualizer example

You can also use ShaderGraph's graph visualizer directly for other purposes:

Basic Use

Install via npm:

npm install shadergraph

Include build/shadergraph.js.

To use ShaderGraph, you initialize it once with a given snippet library. A snippet library is either a dictionary of named snippets, or a fetch function.

// Dynamic fetch
var fetch = function (name) {
  return "...";
};

// Static fetch
var fetch = {
  getColor: "...",
  setColor: "...",
  getRampColor: "...",
};

var shadergraph = ShaderGraph.load(fetch);

You can use the chainable Factory API to build graphs. It's a smart wrapper around a partially built graph. It allows you to make splits and joins, hook up callbacks via requires, import other factories, etc.

Instead of including snippets by name, you can also pass in GLSL code directly to .pipe(…) and .require(…) regardless of whether you are using a fetch function/library or not.

Snippets are instanced by default, letting you bind unique uniforms to specific snippets in the chain:

Uniform example

// Prepare new shader
var shader = shadergraph.shader();

// Prepare uniform (three.js style)
var uniforms = {
  diffuseColor: { type: "v3", value: { x: 0.5, y: 0.75, z: 1.0 } },
};

// Build shader graph
shader
  // Require a callback
  .require("getRampColor")

  // Build two-step chain that uses the callback and the uniform
  .pipe("getColor", uniforms)
  .pipe("setColor");

var program = shader.link();

Instancing behavior can be configured globally or per shader (see below).

Materials

ShaderGraph also includes a material helper, to build a vertex/fragment shader simultaneously:

Material example

// Prepare new material (vertex + fragment shader)
var material = shadergraph.material();

// Build vertex shader graph
material.vertex.pipe("vertex");

// Build fragment shader graph
material.fragment.pipe("getColor").pipe("setColor");

// Link both shaders and combine into a three.js style material
var program = material.link();

The returned program object is compatible with Three.js' ShaderMaterial objects.

Caveats

  • Call shadergraph.inspect(…) anywhere to insert an inspector for a graph, and find missing/wrong connections.
  • Preprocessing directives like #ifdef and #define are ignored, but do pass through. Be careful when using them. Consider using snippets and/or callbacks instead.
  • Structs are not supported, glsl-parser seems to choke on them. Array types are probably a bit buggy still.

Reference

Constructor

var fetch = function (name) { return … };
var fetch = { name: "...", name: "..." };
var config = {
  globalUniforms:   false, // Make uniforms   global
  globalVaryings:   true,  // Make varyings   global
  globalAttributes: true,  // Make attributes global
  globals:          [],    // Make specific symbols global
  autoInspect:      false, // Pop-up a graph inspector if compilation fails
}
shadergraph = ShaderGraph.load(fetch, config);

ShaderGraph

  • .shader(config = {})

    Returns an empty shader graph wrapped in a factory. Override global config options.

  • .material(config = {})

    Returns an empty material wrapping two factories: material.vertex and material.fragment. Override global config options.

  • .visualize(graph/factory/material)

    Draw the given graph(s), returns an HTML element. Call element.update() after inserting.

  • .inspect(graph/factory/material)

    Draw the graph and insert it into the body as a floating inspector.

Factory

  • .pipe(name/code, uniforms = {}, namespace = null, defines = {})
    .pipe(name/code, namespace = null, uniforms = {}, defines = {})
    .pipe(name/code, uniforms = {}, defines = {})
    .pipe(factory)

    Add the given code/snippet/factory to the graph and connect it to what came before. Binds dictionary of uniforms. Set the namespace.

    Connections are made first between connectors of the same type and name, and then between connectors of the same type (in the order specified in the shader). Any callbacks previously added to the graph are also connected, if possible.

    Pipe example

  • .require(name/code, uniforms = {}, namespace = null, defines = {})
    .require(name/code, namespace = null, uniforms = {}, defines = {})
    .require(name/code, uniforms = {}, defines = {})
    .require(factory)

    Add the given code/snippet/factory to the graph as a callback for what comes next. Binds dictionary of uniforms. Set the namespace.

    Require example

  • .isolate().….end()

    Create a finished, isolated subgraph and add it to the graph.

    This is useful, for example, to force the attaching of callbacks to a subgraph:

    var shader = shadergraph.shader();
    shader.require("getColor"); // Require two instances of callback
    shader.require("getColor");
    shader.isolate();
    shader.require("getColorSum"); // Define callback with two open callback inputs
    shader.end(); // Hook up both callbacks
    shader.pipe("setColor"); // Connect to main snippet

    Isolate example

  • .callback().….end()

    Create an isolated subgraph and add it to the graph as a callback.

    Callback example

  • .split().….next().….end()

    Create two or more branches and split connections across them 1-to-1. Connectors which are connected to a branch will not be available for any subsequent branch.

    Split example

  • .fan().….next().….end()

    Create two or more branches and fan connections across them 1-to-N. All connectors are available in each branch.

    Fan example

  • .pass()

    Use this instead of .end() to make additional passthrough connections that skip the entire block. In other words, all connectors at the beginning of the branch will be available again for subsequent nodes.

    Pass example

  • .graph()

    Finalize the graph and return it. The factory is reset to an empty state.

  • .compile(name)

    Finalize the graph and compile it immediately (no callbacks). Returns a GLSL shader string. The factory is reset to an empty state.

  • .link(name)

    Finalize the graph and link it with its subgraphs immediately (with callbacks). Returns a complete GLSL shader string with a main function. The factory is reset to an empty state.

Graph

  • .compile(name)

    Compile the graph (no callbacks). The graph is retained.

  • .link(name)

    Compile and link the graph and its subgraphs (with callbacks). The graph is retained.

Material

  • .link(options = {})

    Link the material's vertex and fragment shader. Returns Three.js style ShaderMaterial options, merged with any existing options passed in.

Manual Use

If you want to build graphs by hand instead of with factories, this is possible, but not as nice. You will need to construct objects and inject a few dependencies. Use the Factory API as a guide.

The underlying namespaces are exposed as ShaderGraph.Graph, ShaderGraph.Block, … Block and its subclasses are the logical pieces of the shader. Each block has a Node associated with it that lives in the Graph and contains a set of Outlets. Connections can be made node-to-node with node.connect(node) (auto-matching by name and type), or outlet-to-outlet with outlet.connect(outlet).

To compile Graphs created without a factory, you will need to call .compile() or .link() on the graph's tail block directly.


Steven Wittens - http://acko.net/

More Repositories

1

TermKit

Experimental Terminal platform built on WebKit + node.js. Currently only for Mac and Windows, though the prototype works 90% in any WebKit browser.
JavaScript
4,433
star
2

MathBox.js

MathBox is a (work in progress) library for making presentation-quality math diagrams in WebGL.
JavaScript
1,942
star
3

mathbox

Presentation-quality WebGL math graphing
JavaScript
1,328
star
4

ThreeAudio.js

ThreeAudio helps you create music visualizations in Three.js or tQuery.
JavaScript
531
star
5

CSS3D.js

CSS 3D renderer for Three.js.
JavaScript
366
star
6

fullfrontal

MathBox-based conference talks
JavaScript
339
star
7

fuse10

Front-end for Acko.net 2013
JavaScript
246
star
8

threestrap

Minimal Three.js Bootstrapper
JavaScript
237
star
9

console-extras.js

Enhancements to the JavaScript console object.
JavaScript
127
star
10

NFSpace

Procedural planet generator
C
123
star
11

ShaderGraph.js

(deprecated) Library to build GLSL shaders out of reusable building blocks.
JavaScript
123
star
12

ThreeRTT.js

ThreeRTT helps you create advanced render-to-texture effects in Three.js.
JavaScript
73
star
13

NeverSeenTheSky

Source code for the WebGL demo Never Seen The Sky
JavaScript
53
star
14

iremotepipe

Command-line tool that streams button presses from Apple IR remotes on OS X.
Objective-C
48
star
15

imgui-wgpu-rs

Dear imgui renderer for wgpu-rs.
Rust
29
star
16

DarkSunrise

Music visualizer demo for Christmas Experiments 2013
JavaScript
26
star
17

ThreeBox.js

(dead) ThreeBox provides an improved boilerplate set up for tQuery / Three.js.
JavaScript
23
star
18

jsFsck

Makes Douglas Crockford cry and gives JavaScript debuggers nightmares.
JavaScript
21
star
19

headspace

TypeScript
12
star
20

pixelfactory

MathBox2-based talk about Pixels, MathBox and GPUs.
JavaScript
12
star
21

WikiTLDR

Chrome/Safari Extension. Reformats WikiLeaks cables for readability.
JavaScript
11
star
22

uncolorblind

Uncolor blindness goggles (Web / JS / GLSL)
JavaScript
11
star
23

vscode-headspace

Headspace audio VSCode plugin
JavaScript
4
star