imgui
imgui copied to clipboard
Node Graph Editors with ImGui
Hi,
So I'm thinking of using ImGui for doing a basic node graph that can be used to edit materials. There are lots of programs that does this but for example:
http://keenleveldesign.com/pimp/protools/shaderfusion/ShaderFusionReleasePromo/shaderfusion01.jpg
I wonder how one would go about doing something similar with ImGui. Having separate windows for each box is likely (?) the best approach as it would allow the user to move them around and what not.
I guess adding some custom stuff for doing the connections + lines as well shouldn't be too hard but I just wanted your thoughts about it.
Cheers!
EDITED 2019
GENERALLY SPEAKING YOU CAN HEAD TO THE WIKI FOR LISTINGS https://github.com/ocornut/imgui/wiki/Useful-Extensions
Listing relevant links posted the thread. Dig in the thread for details!
https://github.com/thedmd/imgui-node-editor https://github.com/rokups/ImNodes https://github.com/Nelarius/imnodes https://github.com/Flix01/imgui/tree/imgui_with_addons https://github.com/DCubix/Twist http://carlivan.com/engine-tools/visual-scripting http://carlivan.com/engine-tools/blueprints/ https://gist.github.com/ChemistAion/0cd64b71711d81661344af040c142c1c https://gist.github.com/spacechase0/e2ff2c4820726d62074ec0d3708d61c3 https://github.com/CedricGuillemet/Imogen https://galloscript.itch.io/texgraph
(Original 2015 answer)
You can start with actual ImGui Windows but as you dig into connections and more features they will likely get in your way? It may be more awkward to restrict them within a given spot, etc. One benefit is that they will handle overlapping for you.
Creating your own mini-window not too hard:
- do your drawing via the drawlist API
- perhaps push a clipping rectangle
- use InvisibleButton() + IsItemActive() (or MouseClickedPos and GetMouseDragDelta) to handle moving.
If you can avoid overlapping it'll be simpler. If you can't the next easiest thing would probably be to handle ordering/sorting them yourself.
Thanks for the reply. That seems reasonable. I think I will just go for non-overlapping as this is mostly for a prototype so that should be fine.
Here's a proof of concept demo. It's quite incomplete but shows that it is possible. You'll need to update to latest because I have fixed a bug with the ImDrawList / channel API. Drawing channels are very convenient to allow out-of-order rendering (here we draw the node background after the nodes are filled with contents).
I'm declaring some ImVec2 operators to make the code simpler. If you have your own math types with conversions via IM_VEC2_CLASS_EXTRA you are probably better off using them.
Sort of work but I'm not very happy with it because it wasn't that trivial to pull off (3 hours including bugfix) and I had to dodge a few non-obvious trap. I'll probably keep massaging that code.
I'll move the hermite curve rendering to new drawing API. Do you know of a good non-stupid reference for API that handle various types of curves? (bezier, hermite, catmull rom. etc.). They are easy to implement but I wonder if there's a way of ordering parameters that's more standard or obvious. An API to handle multiple points should be available so that thick splines can have their end connecting nicely.

Code https://gist.github.com/ocornut/7e9b3ec566a333d725d4
:+1: thanks! :)
Yeah I have been thinking about what curves to actually use for the lines. I thought about just using b-spline or something similar but I have no idea what "real" editors are using.
Hi, Rectangular links could also be a (simpler) possibility. i.e. https://youtu.be/KvExDzISYUc?t=9s
@ocornut nice!! :+1: @NocturnDragon what algorithm does the rect layouts use? I notice it somehow seems to avoid overlapping itself?
I'm not sure those node/graph should or will be a concept of core ImGui by the way. It's more of an example code.
My intuition is the real value will be to keep massaging and improving the lower-level stuff so that it becomes more easier and natural to create this sort of thing from scratch.
Do you know of a good non-stupid reference for API that handle various types of curves? (bezier, hermite, catmull rom. etc.).
I asked the creator of Fog framework who has a lot of experience with vector libraries (Cairo, AGG, etc.) and he told me, that in Fog (and also it's successor Blend 2D) he supports only quad and cubic Bezier curves, because it's enough (and it's much easier to translate these into any other curve needed e.g. by the rendering engine). He also told me, that e.g. Cairo supports only cubic curves.
So, in the name of simplicity, feel free to take a look at the API of Bezier curves in Fog.
https://github.com/ocornut/imgui/issues/306#issuecomment-134672020
Fully agree that this shouldn't be part of core ImGui but an interesting use-case to support with the API itself as you say.
Small comment. I tested your prototype and when dragging the color values it seems to always reset back to default. I haven't investigated yet but just wanted to let you know.
Yeah they are just dummy values, didn't want to clutter the example with too much things.
ImGui::SliderFloat("##value", &node->Value, 0.0f, 1.0f, "Alpha %.2f");
float dummy_color[3] = { node->Pos.x / ImGui::GetWindowWidth(), node->Pos.y / ImGui::GetWindowHeight(), fmodf((float)node->ID * 0.5f, 1.0f) };
ImGui::ColorEdit3("##color", &dummy_color[0]);
If you aren't in a hurry I'll keep working on that in the future, add the linkage, move curves rendering to the main api and generally simplify / clean up / clarify where I can.
Not in a major hurry no so great stuff here :) I also think it's good in general to have a example that "bends" the regular use-case a bit.
Add yeah I agree that general curve rendering would fit good in the API, and getting linkage in the example would be great of course.
Awesome work! :+1:
Rectangular links could also be a (simpler) possibility.
+1 for rectangular and 45 degree angle links. I find them way more readable than curves/spaghetti stuff. :)
Any plans to switch to nanovg renderer? )
ImGui already does anti-aliased text and lines so I'm not sure why that would be needed?
Probably not because NanoVG is rather runtime heavy for the performance we are aiming for. But as emoon say is there is a specific reason/feature you would want it? Also please open a new topic for that. Thanks!
Just to say that I'm also developing my own version based on the code posted by Omar.
It's still w.i.p., but at least the node types are not hard-coded.
My code is here: https://github.com/Flix01/imgui/tree/imgui_with_addons
And a live test is here (you have to click on a button to start it): Demo.
Just thought i'd say I love the background.
How'd you do that (add a background that is).
@Flix01 Awesome! :+1:
Adam: they are just lines. You can just draw shapes or images and that's a background done..
@Flix01 @ocornut Is possible an example of Zoom In/Back / Resize effect to the complete viewport/window of the nodes ? and relative mouse displacement based in the zoom level
@Hevedy Partially using:
ImGui::GetIO().FontAllowUserScaling = true;
CTRL+mouse wheel should increase the font size and the node sizes, but their position stays the same.
I've just implemented a basic node copy/paste functionality.
However there are some problems with the popup menus: if I right-click on a node and then right-click on another without closing the first menu, a (wrong) menu appears in the position of the old one. It should close the old one and open the correct menu on the new node instead... I don't know how to fix it.
You can check the live test linked above, that keeps updating too (even if it does not support serialization).
[Edit] I discovered that the problem is composed by two sub-issues:
- the popup menu position is wrong. I've managed to solve this using PushID()/PopID() guards around it.
- the popup menu is wrong (the "add node" menu appears instead of the "Node Copy/Paste/Delete"). This happens because while one menu is open, another node in the node graph window can't receive the "mouse hover state" (probably because the focus goes to the open popup window): so the editor thinks that the user has clicked on an empty space and not on a node, and incorrectly shows him the "add node" menu. I don't know how to fix this: is it possible at least to detect if a popup menu is currently being displayed ? If so, I could prevent another menu to open, and the click could probably just cause the first menu to close. [Edit] No matter: I think I can add a custom variable to detect if a menu is being displayed.
@Hevedy I've added proper zoom. It's still WIP ATM, but if you have Firefox you can test it using CTRL+mouse wheel in the test demo above.
Hello, I am currently using Imgui to create decision trees for my school game project, and this is the WIP (which is due next week). I am really interested in making the zooming (CTRL + MW) and I read through @Flix01 's code, however I only found a part whereby it commented "fixes zooming a bit", I read the code and I couldnt understand how the zooming is done. Is it possible to explain on how the zooming is done? Is it just zooming the font size as what @Flix01 previously mentioned?
Thank you.
Irene, one issue you'll be running into is that ImGui currently render fonts into a texture when you create the font atlas and so those have a fixed resolution. So zooming is possible but the zooming quality will be quite poor. If you want to zoom the font you should add a secondary font using a smoother font that has anti-aliasing (e.g. Arial), render it in higher size (e.g. 30) and then scale it down using e.g. SetWindowFontScale(). It isn't a very well supported path and will probably be a little awkward, but it should work.
I haven't looked at Flix01's code so I can't help on the other details yet.
@ocornut Thank you for the quick response, I will go and try it out! :smile:
I haven't looked at Flix01's code so I can't help on the other details yet.
Nope, of course I didn't mind having bad quality fonts while zooming. The main problem was that by applying the default ImGui zooming functionality with:
ImGui::GetIO().FontAllowUserScaling = true;
alone, not all the parts of the nodes zoom properly.
So basically in my code I had to zoom everything else: node widths, connection circles, the control point distance of Bezier lines, and so on, and I used "currentFontWindowScale" (referenced by the comment "Fixes zooming a bit") as a scale factor.
However it's still not perfect: now if you change the zoom level and then create a node, the node position is wrong for example.