Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node Graph Editors with ImGui #306

Open
emoon opened this issue Aug 24, 2015 · 152 comments
Open

Node Graph Editors with ImGui #306

emoon opened this issue Aug 24, 2015 · 152 comments

Comments

@emoon
Copy link
Contributor

emoon commented Aug 24, 2015

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:https://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!

@ocornut
Copy link
Owner

ocornut commented Aug 24, 2015

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:https://carlivan.com/engine-tools/visual-scripting
http:https://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.

@emoon
Copy link
Contributor Author

emoon commented Aug 24, 2015

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.

@ocornut
Copy link
Owner

ocornut commented Aug 25, 2015

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.

node_graph_editor

Code
https://gist.github.com/ocornut/7e9b3ec566a333d725d4

@emoon
Copy link
Contributor Author

emoon commented Aug 25, 2015

👍 thanks! :)

@emoon
Copy link
Contributor Author

emoon commented Aug 25, 2015

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.

@NocturnDragon
Copy link

Hi,
Rectangular links could also be a (simpler) possibility.
i.e. https://youtu.be/KvExDzISYUc?t=9s

@MrSapps
Copy link

MrSapps commented Aug 25, 2015

@ocornut nice!! 👍 @NocturnDragon what algorithm does the rect layouts use? I notice it somehow seems to avoid overlapping itself?

@ocornut
Copy link
Owner

ocornut commented Aug 25, 2015

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.

@dumblob
Copy link

dumblob commented Aug 25, 2015

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.

@emoon
Copy link
Contributor Author

emoon commented Aug 25, 2015

#306 (comment)

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.

@emoon
Copy link
Contributor Author

emoon commented Aug 25, 2015

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.

@ocornut
Copy link
Owner

ocornut commented Aug 25, 2015

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.

@emoon
Copy link
Contributor Author

emoon commented Aug 25, 2015

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.

@emoon
Copy link
Contributor Author

emoon commented Aug 25, 2015

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.

@bkaradzic
Copy link
Contributor

Awesome work! 👍

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. :)

@bagobor
Copy link

bagobor commented Aug 27, 2015

Any plans to switch to nanovg renderer? )

@emoon
Copy link
Contributor Author

emoon commented Aug 27, 2015

ImGui already does anti-aliased text and lines so I'm not sure why that would be needed?

@ocornut
Copy link
Owner

ocornut commented Aug 27, 2015

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!

@Flix01
Copy link

Flix01 commented Oct 26, 2015

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.
nge
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.

@adam4813
Copy link

adam4813 commented Oct 26, 2015 via email

@bkaradzic
Copy link
Contributor

@Flix01 Awesome! 👍

@ocornut
Copy link
Owner

ocornut commented Oct 26, 2015

Adam: they are just lines. You can just draw shapes or images and that's a background done..

@Hevedy
Copy link

Hevedy commented Oct 29, 2015

@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

@Flix01
Copy link

Flix01 commented Oct 29, 2015

@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.

@Flix01
Copy link

Flix01 commented Oct 29, 2015

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:

  1. the popup menu position is wrong. I've managed to solve this using PushID()/PopID() guards around it.
  2. 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.

@Flix01
Copy link

Flix01 commented Nov 2, 2015

@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.

@irenekaea
Copy link

untitled
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.

@enquel
Copy link

enquel commented May 31, 2022

Thank you, the differences are staggering.

@sphaero
Copy link

sphaero commented Jun 1, 2022

wow, hadn't expect such huge differences. Is your test code available somewhere?

@ahmidou
Copy link

ahmidou commented Jun 1, 2022

it's not, and it also have other stuff going on but they are constant in the three implementations.
It's easy to replicate tho :)
BTW drawing all the cubic bezier connections is super expansive.

@thedmd
Copy link
Contributor

thedmd commented Jun 2, 2022

That is true. imgui-node-editor is drawing only visible nodes and links.

In my implementation of blueprint editor (in tye engine) I fade out labels when zoomed out, drawing only Dummy instead of Text.
Drawing icons are expensive too, they are vector graphic, could be moved to textures or geometry cached for certain sizes.

I didn't spent much time optimizing speed further. Probably there are more opportunities to take advantage of when necessary.

Thanks for your benchmark. :)

Do you need to squeeze more performance from the editor?

@ChemistAion
Copy link

ChemistAion commented Jun 2, 2022

My goal with ImGui::ImGuiNodes was to create and test a minimal (as possible) state-machine for basic node-editor functionalities. While it's not a purely 'Immediate Mode' widget, since the nodes' state is maintained internally at all times.
For that cost - it allows us to implement serialization, undo/redo, representation transformation, and other features...

There are no additional caching mechanisms or complex logic involved, other then that all the nodes are sorted and kept in a Z-order to handle overlapping. Nodes and links that fall outside the visible canvas area are not drawn. Node drawing is achieved through a one-shot process using BuildNodeGeometry(...) followed by repeated calls to DrawNode(...).

For prototyping purposes, you can easily strip it down to the raw state machine by using ImGuiNodes::Update() and related functions such as UpdateCanvasGeometry() and UpdateNodesFromCanvas().

Special thanks to @gboisse for providing valuable insights.

@ahmidou
Copy link

ahmidou commented Jun 2, 2022

@thedmd I'd like to be able to draw thousands :D in my test case all links are always visible as there's one top node connected to all the 499 others.
@ChemistAion I really like it, I wasn't sure how to connect it with my evaluation graph, so I added some events similar to imnodes to inform my graph that a connection was added or removed and reflect the change.

@ChemistAion
Copy link

ChemistAion commented Jun 2, 2022

@ahmidou: for your usecase with thousands of nodes/links I would like to encourage you to try your own attack here :)
IMHO you've all the ingredients, just distill at least: @rokups, @thedmd, @Nelarius, mine... meaning: how to do canvas and states.
Forget link-curves and node-roudings and for the start spice it up (the states) with some data-cache oriented approach, e.g.: CppCon 2014: Mike Acton "Data-Oriented Design and C++"

@ahmidou
Copy link

ahmidou commented Jun 4, 2022

Hey @ChemistAion that's what I'll probably do in the long run, but for now I'm fine with your solution.
I finished the integration and it's running at 400 fps with the same data as the others :)
I had to do some minor changes to make it work with an existing graph.
It needs more "management" as now I need to reflect the graph topology changes in the Imgui one as well as the data processing one. Ideally I'd prefer to keep things de-coupled but I probably need to do a compromise here as keeping some sates around definitely gives more performance.

Thanks for the reference implementation!!

@LiamANeeson
Copy link

Hey @ocornut I'm trying to incorporate a part of your solution into my own and I was wondering how would it be possible to draw connections between the new nodes that are added to the canvas? Any help is appreciated. Thanks.

IE. Creating connection between the nodes generated I've given an example below.
Node Editor 3rd

@ocornut
Copy link
Owner

ocornut commented Nov 10, 2022

Hey @ocornut I'm trying to incorporate a part of your solution into my own and I was wondering how would it be possible to draw connections between the new nodes that are added to the canvas? Any help is appreciated. Thanks.

It looks like you would be better off using one of the several existing solutions (linked at the top of this thread and https://github.com/ocornut/imgui/wiki/Useful-Extensions) instead of starting from my old quick proof-of-concept.

@reformstudios
Copy link

while less flexible as a lib, https://gist.github.com/ChemistAion/0cd64b71711d81661344af040c142c1c is by far the fastest
probably because it's caching some of the data.
ImGuiNodes ~400 fps

This link is dead now. @ChemistAion Could you repost it possibly? I'm curious to see how you achieve the performance boost!
Thanks

@ChemistAion
Copy link

ChemistAion commented May 28, 2023

@reformstudios:
...actually it is ok by itself 😅 ...just copy it and use its text-contents as a link
It was somehow mistakenly omitted in [url] part of the github::link-prompt by @ahmidou above 🤔
For the note, here is the working one (already corrected in: #306 (comment)):
https://gist.github.com/ChemistAion/0cd64b71711d81661344af040c142c1c

Details on how to test it: #306 (comment)

Finally, mentioned here and there its "speed" comes from the fact that this is a v. simple state-machine: #306 (comment)

Additionally, please find the list of other ideas/approaches: #306 (comment)

@reformstudios
Copy link

https://gist.github.com/ChemistAion/0cd64b71711d81661344af040c142c1c

Thanks for that! I have to confess, I have no idea how to add your node editor to my simple imgui app.
I assume I add #include "nodes.h" to my header file, and then call it in some way? Or is it not designed like that yet?

@ChemistAion
Copy link

ChemistAion commented May 28, 2023

@reformstudios: yep, that will work...
Just add these two files (nodes.h and nodes.cpp) into your app and make an object ImGui::ImGuiNodes provided by them.
Details: #306 (comment)

@reformstudios
Copy link

@reformstudios: yep, that will work - just add these two files (nodes.h and nodes.cpp) into your app and make an object ImGui::ImGuiNodes and you are ready to go, details: #306 (comment)

Thank you so much for such quick replies!

@Fattorino
Copy link

Another Node Editor but with a different approach. To be as customizable as possible while requiring very few lines of code to create custom nodes.
ImNodeFlow
ImNodeFlowDemo

@ocornut
Copy link
Owner

ocornut commented Feb 1, 2024

Thank you Gabriele, and thanks for adding this the wiki section with an image.

@Fattorino
Copy link

@ocornut I would like to work on adding Zoom support for ImNodeHandler. I've had a look at imgui-node-editor implementation. But it's quite hefty and doesn't work with combos and similar. Could you point me in the right direction to develop such feature?

@nem0
Copy link
Contributor

nem0 commented Feb 1, 2024

@Fattorino see https://github.com/nem0/LumixEngine/blob/master/external/imgui/imgui_user.inl#L1337 for inspiration

@ChemistAion
Copy link

@Fattorino
Copy link

@Fattorino: also here: https://gist.github.com/ChemistAion/0cd64b71711d81661344af040c142c1c#file-nodes-cpp-L5

@ChemistAion if I understand correctly you do not render the ImGui widgets but only custom graphics, right?

My goal is to allow the user to create the node's body as you create an ordinary ImGui window. (I haven't had the chance to have a look at nem0's project yet)

@ChemistAion
Copy link

ChemistAion commented Feb 2, 2024

@Fattorino: yes, my example is shown with exclusively custom graphics - the goal was to build nodes-editor state machine/engine not the frontend.

Regarding your actual question, I wanted only to direct your attention to the foundations of the zoom calculations/idea: ImGuiNodes::UpdateCanvasGeometry()

@Fattorino
Copy link

Fattorino commented Feb 2, 2024

Thanks for the help, especially @nem0 whose solution was extremely fitting and allowed me to implement an almost identical solution ImNodeFlow Zoom.
I'll take advantage of this conversation to ask one last question tho. Any idea on how to void the blurry or rough rendering when zoomed in or out? And how to block a window from moving without relying on the NoMove flag?

@meshula
Copy link

meshula commented Feb 3, 2024

My solution for zooming out was to fade the elements in the nodes at the point they are unusable/illegible. I put a ramp, so there's a threshold at the point the interior elements become more and more transparent.

        uint32_t text_color = 0xffffff;
        uint32_t text_color_highlighted = 0x00ffff;
        text_color |= (uint32_t)(255 * 2 * (root.canvas.scale - 0.5f)) << 24;
        text_color_highlighted |= (uint32_t)(255 * 2 * (root.canvas.scale - 0.5f)) << 24;
image image

For zooming in, I didn't want to spend memory on enormous fonts, so I just let it get blurry.

@Fattorino
Copy link

Yes, I think that is the smartest decision. When I find the time I'll see how it looks. And thanks

@ocornut
Copy link
Owner

ocornut commented Feb 6, 2024

Note that 1.90 introduced a ImFontConfig::RasterizerDensity field, which is convenient for the situation where you want to load fonts in multiple sizes and yet have their metrics matches. See #6925

This makes it easy to e.g. load one font at 100%, one font at 400% size, and swap between them when you cross over the 200% lines. All other font metrics will appears identical so there's much less juggling with sizes.

@Fattorino
Copy link

Fattorino commented Feb 14, 2024

New styling system, and therefore new looks for ImNodeFlow, any feedback?
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests