Visual shader editor wip

link -> http://dusanbosnjak.com/test/nodes/


I’ve been working on a node editor and i’ve cooked up a version that generate’s three’s ShaderMaterials. It’s super WIP and clunky, but i think it’s more or less complete as in that it can persist whatever’s being created, display the result using three, and spit out a JS class into the clipboard (export) although that bit is most likely broken.

This is my pet project that i’m using to experiment with various web technologies. I had it hooked up quickly with react initially. It looked much nicer, and was relatively easy to work with, but barfed after creating a handful of nodes. I then tried to do it all with three, but that actually barfed as well and was pretty complicated to work with. I ended up rendering this with a mixture of three, html and canvas. Ive been wanting to give pixi.js a shot, but i’ve already had too much going on.

As is, it should be working pretty fast with a lot of nodes and edges, with some visual bugs.

Feature wise, atm, there’s only one material - MeshBasicMaterial and most of the GLSL functions, along with one custom (simplex noise) and one very specific to this editor - swizzle.

Red sockets can take multiple types, the others represent float,vec2,3,4 and sampler. If you want to output the depth to the color of the material you have to pipe it through the swizzle node (set to .xxx). I’m really curious if this feels clunky.

The sampler can load textures, but it’s super crude.

Obviously there’s a whole bunch of stuff to do here. When moving away from react i lost some pretty informative features from the nodes in the main view. Like a big plus sign that says that the math operator is adding instead of multiplying etc. This was sad. But clunky as it is, the graph should be valid, and there should be some output in that corner window.

The idea is that ultimately, a .js file can be exported, that describes a MyMaterial extends Material (technically ShaderMaterial) with a bunch of getters and setters already defined for you.
So whatever node you end up with in the graph that’s a leaf, under the hood it ends up on yourInstance.uniforms.yourInput.value but the interface enables you to get and set with yourInstance.yourInput.

I want to add a gltf option to the sphere,cube,cylinder preview mesh, and i’m not sure how to handle previewing custom attributes. Say something as simple as the second uv channel, but as complex as instance attributes.
Atm, this doesn’t have any vertex logic other than making some varyings, but it would be fairly easy to add some nodes that apply some vertex logic (positions,normals, instancing, maybe the option to do uvs there). I don’t know how to generate, or load data that would be useful for previewing these though.

Hopefully most of the stuff you do, you can undo, and then redo. (ctrl+z, ctrl+shift+z)

8 Likes

Pasting (or saving and loading) this json should yield the fresnel/rim looking effect from the screenshot.

{
  "version": "0.1",
  "nodes": [
    {
      "id": "k3n0e5lv",
      "type": "DOT",
      "data": {
        "position": {
          "x": -759.0000000000001,
          "y": 109.00000000000013
        },
        "name": "dot - 0",
        "options": null,
        "values": {}
      }
    },
    {
      "id": "k3n0e79k",
      "type": "NORMALIZE",
      "data": {
        "position": {
          "x": -1100.9999999999995,
          "y": 112.00000000000004
        },
        "name": "normalize - 0",
        "options": null,
        "values": {}
      }
    },
    {
      "id": "k3n0eefd",
      "type": "MATH_OPERATOR",
      "data": {
        "position": {
          "x": -937.9999999999994,
          "y": 110.00000000000013
        },
        "name": "mathOp - 0",
        "options": {
          "0": 2
        },
        "values": {
          "1": [
            -1,
            -1,
            -1,
            0
          ]
        }
      }
    },
    {
      "id": "k3n0ehu0",
      "type": "VIEW_POSITION",
      "data": {
        "position": {
          "x": -1263.9999999999995,
          "y": 112.00000000000018
        },
        "name": "viewPos",
        "options": null,
        "values": {}
      }
    },
    {
      "id": "k3n0ejf4",
      "type": "NORMAL",
      "data": {
        "position": {
          "x": -936.9999999999994,
          "y": 194.00000000000006
        },
        "name": "normal_view",
        "options": {
          "0": 2
        },
        "values": {}
      }
    },
    {
      "id": "k3n0ficm",
      "type": "BASIC_MATERIAL",
      "data": {
        "position": {
          "x": -101.00000000000006,
          "y": 92
        },
        "name": "basicMat - 1",
        "options": null,
        "values": {
          "1": [
            1
          ],
          "2": [
            1
          ],
          "3": [
            1,
            1,
            1
          ],
          "4": [
            1
          ],
          "5": [
            1
          ]
        }
      }
    },
    {
      "id": "k3n0fpjd",
      "type": "swizzle",
      "data": {
        "position": {
          "x": -277,
          "y": 92.00000000000009
        },
        "name": "swizzle - 0",
        "options": {
          "0": 1,
          "1": 1,
          "2": 1
        },
        "values": {}
      }
    },
    {
      "id": "k3n0gssd",
      "type": "MATH_OPERATOR",
      "data": {
        "position": {
          "x": -599.9999999999998,
          "y": 90.99999999999999
        },
        "name": "mathOp - 1",
        "options": {
          "0": 1
        },
        "values": {
          "0": [
            1,
            0,
            0,
            0
          ]
        }
      }
    },
    {
      "id": "k3n0he12",
      "type": "POWER",
      "data": {
        "position": {
          "x": -437.00000000000006,
          "y": 91.00000000000007
        },
        "name": "power - 0",
        "options": null,
        "values": {
          "1": [
            2.3000000000000003,
            0,
            0,
            0
          ]
        }
      }
    }
  ],
  "edges": [
    {
      "output": [
        "k3n0ehu0",
        0
      ],
      "input": [
        "k3n0e79k",
        0
      ]
    },
    {
      "output": [
        "k3n0e79k",
        1
      ],
      "input": [
        "k3n0eefd",
        0
      ]
    },
    {
      "output": [
        "k3n0ejf4",
        0
      ],
      "input": [
        "k3n0e5lv",
        1
      ]
    },
    {
      "output": [
        "k3n0eefd",
        2
      ],
      "input": [
        "k3n0e5lv",
        0
      ]
    },
    {
      "output": [
        "k3n0e5lv",
        2
      ],
      "input": [
        "k3n0gssd",
        1
      ]
    },
    {
      "output": [
        "k3n0gssd",
        2
      ],
      "input": [
        "k3n0he12",
        0
      ]
    },
    {
      "output": [
        "k3n0he12",
        2
      ],
      "input": [
        "k3n0fpjd",
        0
      ]
    },
    {
      "output": [
        "k3n0fpjd",
        1
      ],
      "input": [
        "k3n0ficm",
        0
      ]
    }
  ],
  "viewer": {}
}
1 Like

I know nothing at shaders, but it looks very cool.
How to delete a node ?

This looks awesome, nice work on the node canvas!

I’m running into some kind of issue where setting the color of a selected color node has no effect, and it reverts to white after I reselect it:

I want to add a gltf option to the sphere,cube,cylinder preview mesh, and i’m not sure how to handle previewing custom attributes. Say something as simple as the second uv channel, but as complex as instance attributes.

If it’s helpful i’ve got a WIP PR to the Blender glTF addon that lets you write custom vertex attributes from one or more vertex color sets. So for example, you can paint custom weights with a brush in Blender, then use them for some effect in your shader. Currently looking for more feedback on that proposal: https://github.com/KhronosGroup/glTF-Blender-IO/pull/807

1 Like

You just have to be thoughtful when you place them

delete key

1 Like

it’s awsome,

can’t remove sampler

select it, press delete - selection clears and I get this:
image

tools looks really neat though

I think i fixed the sampler and texturemap issue just now.

I just hooked the color as well, i think it will work for the color node and for the sockets on the material, but may not export. I wanted instance.material to return Color not Vector3 from the appropriate uniform.value.

This is super sweet. I think most software has something like this, 3dsmax can inspect various channels, and they’re easily accessible in maxscript. If one wants to play with the attributes, they have to provide them through the gltf and using this extension. Three would probably use this further down the line since its nifty.
Not sure what else could be done for the viewer in particular, maybe loading several files, and combining them into one, but how would one generate the files (say a mesh in a gltf representing the mapping for a mesh in another gltf)?

I pushed a version that can zoom, i think it makes it easier to navigate, but ultimately i want to have a minimap in the corner.

@pailhead

All looks great - highly responsive.

I was surprised: cut and paste worked fine - once I clicked ‘allow’.

It would be great to see a bunch of examples - including a ‘hello world’. A few examples could be for ‘insanely great’ demos but most could be very simple cookbook examples - each showing how to do one simple thing.

2 Likes

Thank you @theo!

I added the lambert material and im uncovering various bugs.

There’s an additional example for this (animated) dissolve effect.

I think ctrl + v and ctrl + c work as well.

2 Likes