Visible node graph with ImGui
I wished my first submit on this weblog to be in regards to the node graph system that I created for my private graphics engine named “RogueEngine”.
I could discuss in regards to the engine itself in one other submit however for now I’d prefer to give attention to its UI.
As a teaser, right here’s a screenshot of the software operating our Revision 2023 demo:
A little bit of background
I began fascinated about this undertaking again in 2019 with the goal of releasing some PC demo productions.
I had heard of the demoscene for the primary time about 4 years earlier via some coworkers at Sony and it step by step grew on me to the purpose that I too wished to take part.
I actually wished to have the ability to staff up with artists and designers for making these somewhat than, say, different programmers or making an attempt to finish a manufacturing by myself.
This appeared like a greater technique to attain the next visible bar in addition to being extra entertaining total. ????
This translated in my thoughts to having an interface that anybody might use for interacting with and tweaking the content material, though on reflection, such a system is available in extraordinarily helpful for programmers too and I discover myself more and more utilizing it for a lot of functions, corresponding to analysis and experimentation.
Regardless, I began trying into interfaces for visible content material creation, which had been on the time each fairly fascinating and mysterious to me having little to no expertise with such programs.
I used to be initially not significantly keen on node graphs nonetheless, for primarily two causes:
- Many of those programs appeared to be what I’d name “coding with nodes”; whereas it might be extra visible, it isn’t basically any less complicated.
- It may get actual messy actual quick.
Node programs had been nonetheless interesting to me nonetheless for various causes;
they felt extra intuitive and fewer intimidating than different options with extra “conventional” UI and so they are inclined to look very nice on screenshots.
Then possibly it’ll be simpler for me to persuade different individuals to get on board? ????
So I began fascinated about a node system that might not be “coding with nodes”.
Node system
Having little to no expertise with node-based programs, I went forward and checked out different software program for inspiration.
Massive sources of inspiration for me can be software program corresponding to Blender, Notch, and Godot.
Specifically, I used to be questioning find out how to create a system that’d be each straightforward to make use of and expressive sufficient to permit the creation of attention-grabbing and emergent results somewhat than merely ticking obtainable engine options on or off…
In direction of the top of 2019, one thing considerably cliked in my thoughts;
I’d design the system to have solely two kinds of nodes (okay, three) and so they’d work like this:
- The root node from which the graph traversal would begin at runtime.
- The knowledge node representing a chunk of knowledge of a given kind.
- The part node that may be hooked up to an information node to change it.
The totally different node varieties.
This seemingly easy setup appeared to open up loads of prospects. ????
I might have some “geometry knowledge node” being nothing greater than an index and a vertex buffer (plus some bounding field and doubtless different issues…) whereas a “part node” related to it could act as some type of vertex shader that could possibly be used for displacement functions.
Equally, a “shading knowledge node” might signify an ordinary materials whereas a “part node” can be some piece of code to be injected into the fragment shader for varied per-pixel procedural shading results.
This felt like resolution; I might immediately see how most options might map to this setup and it most positively wasn’t a visible programming system…
As an illustration, right here’s a set of the totally different node classes obtainable within the engine on the time of writing:
The obtainable node classes in RogueEngine.
The beauty of this strategy is that the dependent nodes don’t must understand how the info from the info node got here to be (within the case of the geometry class, it could possibly be a procedurally-generated mesh, geometry loaded via some glTF file, and even metaballs generated from the particle system), the format of the info node being mounted (on this case, an index and a vertex buffer…), we all the time know find out how to function on it. ????
Metaballs created utilizing the nodes, a traditional of the demoscene.
Knowledge mannequin vs. GUI code
Now that I knew how my node system would function, I needed to discover find out how to implement it.
My plan was to make use of Dear ImGui for the UI as a result of it’s a pleasure to make use of and, I’ve to confess, I had little intention of investigating different GUI options.
ImGui is definitely an incredible match I discovered to crafting such a inventive UI system.
The primary perception to remove in my view is the necessity to separate the info (what I’d name the knowledge mannequin) from the UI logic (sometimes called the view).
Having such a separation naturally implies creating an interface for iterating the info inside your “undertaking” that may then be used each by the runtime, when enjoying again the demo content material, and the ImGui code, when operating the editor.
Our first step ought to due to this fact be to outline that knowledge mannequin, so right here goes:
Knowledge mannequin for RogueEngine’s runtime.
There are primarily solely three kinds of sources {that a} person can work together with via the interface and manipulate inside a undertaking (together with just a few extra as detailed under…):
- Belongings: A listing of all of your imported 3D fashions, textures, music information, and so forth.
- Layers: These permit to group nodes, largely to facilitate multi-scene tasks.
- Nodes: Nodes belong to their mum or dad layer and might be executed by the runtime.
Moreover, Ranges signify the collection of time segments for when a selected useful resource is lively on the timeline, whereas Properties signify, because the identify suggests, the properties of a given node, corresponding to values and colours, hyperlinks to property and/or different nodes, and so forth.
Having such a clearly outlined knowledge mannequin makes it straightforward to serialize and deserialize the content material of a undertaking (for saving and loading functions respectively) as we will depend on a properly recognized distinction between what needs to be continued vs. what’s engine particular.
The timeline panel permits the version of ranges, i.e., when is a node or layer lively or not.
Lastly, such a setup makes it somewhat easy to implement dreaded (however oh so helpful!) options corresponding to undo/redo.
I picked the identical strategy than @voxagonlabs and went forward with serializing the entire undertaking on each change to the info mannequin.
This may occasionally sound somewhat inefficient (and I’m certain it gained’t maintain up previous sure undertaking sizes…) however there isn’t actually all that a lot knowledge you sometimes must serialize when saving a undertaking.
So it’s positively ok for now and makes undo/redo certainly trivial to handle. ????
Animating the scene
Subsequent cease on the highway was to get issues shifting.
My plan right here was to permit keyframing any property that’s both a float
or a vector of floats (e.g., vec2
, vec3
, vec4
).
For this job, I just about mimicked Blender and added a “Okay” button subsequent to all keyframe-able properties.
As soon as enabled, the property area would flip inexperienced, whereas modifying it could insert a brand new keyframe on the present body index, turning the sphere orange to spotlight the change.
I additionally discovered I needed to disable the enhancing of keyframed properties throughout playback (one thing that’s in any other case potential and a good way to tweak the rendering of a scene) in order to keep away from inserting what’d be one keyframe per body. ????
Lastly, I made a decision to have the timeline content material be encoded for a 24Hz goal frequency, which means you can solely ever retailer as much as 24 keyframes inside a given second.
That is nice nonetheless, as we will merely flip our body index right into a floating-point quantity and interpolate between keyframes if the demo finally ends up operating at larger framerates.
Factors on a curve; nonetheless doing fundamental linear interpolation, cubic spline coming quickly™.
Yet another factor I added was this “M” button, which you’ll see subsequent to the keyframe toggle within the inspector panel.
Toggling it makes the property seem as a pin onto the node itself within the graph.
The person can then plug in different nodes and modify the property procedurally (including the elapsed time in seconds, multiplying with a sine wave or noise perform, and so forth.).
This can be a useful gizmo for steady, repeating, or random animation.
Issues that might in any other case be a ache to do with enhancing a curve.
Because it seems, we ended up utilizing this performance far more than the curve editor itself!
This in all probability goes a way as to explaining why this view is the one a part of the UI that hasn’t been accomplished but…
Code nodes
I’ve talked about all through this submit that I used to be largely making an attempt to steer away from visible programming, however we should need to permit using coding for these moments the place built-in nodes aren’t fairly versatile sufficient.
As a substitute of “coding with nodes” nonetheless, right here you’d merely create a “code node” letting you write precise textual content inside a area (or copy/paste from Shadertoy!).
You may then add “bindings” to create tweakable properties that may be accessed instantly from the shader:
Code node with animated binding.
Oh, and these properties are identical to another node property, in order that they too might be animated and/or plugged into different nodes… ????
Conclusion
I hope this overview was helpful, don’t hesitate to reach out or depart a remark!