2024-10-28 Geometry Nodes Workshop Notes

Node groups vs. Closures

There is no fundamental reason for why we have to use a new zone type for closures, but just using node groups does have some downsides and I prefer using the new zone.

  • Capturing values from the outside is trivial with zones. Node groups would require a new feature to specify which inputs should be captured when it’s created vs. which should be passed in when it’s evaluated.
  • We’d likely need a new node besides the Group node anyway, which outputs the group as socket. This makes the experience quite different from using node groups.
  • Node groups are an abstraction and reuse tool. Closures are not. It can make a lot of sense to create a closure that is not reused and the implementation of which is not hidden. They can be combined with node groups if you need reuse or abstraction or course.
  • The mapping of sockets of the inputs and outputs of a closure at the Evaluate Closure is more loose than for node groups, because the signatures might not always match. This is also quite different from how node groups behave. In that regard, closures are much more like bundles than like node groups.
  • Forcing that that closures have to be node groups also means that it becomes impossible to ungroup everything without changing behavior. Being able to have everything in a flattened tree is nice for screenshots but can also help debugging sometimes.

Bundle Link Colors

Generally a nice idea, but I think those stop working under many circumstances:

  • Many bundled links.
  • Bundles containing other bundles.
  • The exact contained data is unknown.
    image
  • The exact data might be known, but should be abstracted away.
    image

Currently, we plan to draw these links a bit thicker, but there is no final decision on that yet (we like to call them udons in our discussions, thick noodles).

Group Input Defaults

Yeah, that’s pretty much the idea currently. That does not solve the problem of updating users of the node group unfortunately either.

Note that having these inputs on the Group Input node likely won’t work, because there can only be one default for each socket, but the group input node can be copied many times. Also, I think that would make the node group harder to understand of the Group Input would have links coming into it. Hence, currently the idea is to have a new Group Defaults node with just input sockets. Only a single one of those can be in a node tree (or at least a single one can be active), just like with Group Output nodes.

18 Likes

Oh, passing a closure in a socket, I see, cool… If it were a nodegroup, you’d have to embed it inside the particle sim nodegroup. Or you could chain the nodegroups one after the other. With a closure, you can leave the particle sim nodegroup untouched, which definitely seems more sane. But then you cannot easily reuse a closure… unless you group its contents?

The other points I cannot understand, but that’s just me being a layman. Thanks for the further explanations.

Under what circumstances can this happen?

2 Likes

Groups can be instanced and used in different places. That means that from inside the group, you don’t know what an incoming bundle can contain. Could be anything.

1 Like

You can create node groups which will output any closure you want to reuse, even more you can pass closure which will generate other closure in to such a node group there will be extremely customizable behavior. This called a Factory Pattern in SOLID.

1 Like

@filedescriptor right ! didn’t think of that.

@modmoderVAAAA thanks for the documentation, much appreciated

In a programming language which supports functional programming, you can create a function B from within another function A. If you return B from A, then B is a closure.

Think about a generator for tables. We have a part that creates the table-top, and another part can create legs. We could use a group for table-top and another group for legs to keep simple our table generator. But the way we create legs or the table-top is hard-coded. If we like to change its behavior, we need to change the group directly, or indirectly by changing a group node used somewhere inside the ngroup.

With closures, this changes. There could be a generator for tables, which focus on placing table-top and legs together, taking a boundary size. Now our generator could take a closure to generate a table-top and another closure for the legs. It tells both closures about the boundary the table should have, and let the closures do the job.

Now, after some generator closures for legs (rectangular, cylindrical, lathe_ornament) or table tops (plain rectangular, planks, circle_shape) have been defined, a 3rd user still could add his own closure for creating table legs or table tops without touching anything his coworker already implemented.

1 Like

Can’t wait for all of this to come together.

About Group Input Defaults, it would be nice to have an option to restore the entire node group to its default values and, perhaps, the ability to create presets, something similar to the cloth physics panel:

2024-11-11 01_50_07-Window

9 Likes

I’ve created this extension for that exact purpose, but would be quite happy if the Blender would have it natively!

4 Likes

Oh! god! I think I got it!
Closures are injections!

3 Likes

Still quite not clear what Bundles are and what is the motivation of adding them(

1 Like

I’ve read that thrice, and trying hard to follow… but I cannot.

I do understand your simple example is meant as exactly that - a simple example, but… I can’t get to the point of “I cannot create the table easily without closures.”

IE: Right now I can create a table of a specific boundary box size, create a table top at a particular height, and legs on the corners. Within the current system, i can change the overall size of the “geo node table” and the top and legs will change positions as needed.

So - again, my apologies. I’m not trying to deflate your example, but understand the “what is new and better now.” (It probably does not help than I am barely qualified to hack away at python code, so any comparisons to “in a code function structure” are probably lost on me.)

1 Like

A non-programmer explanation:
A bundle just bundles multiple noodles together. Which saves a lot of work as you don’t have to trace all those noodles individually, and it can declutter the nodetree when there are multiple values you need at multiple locations in the tree.

example:
I have a shipbuilding nodetree where I need to pass lots of data and multiple geometries from the first stage to the next. The second stage needs the mesh geometry created by the fist stage, but also needs to access the curves it was generated from and it needs to re use a bunch of settings from the first stage node. In blender 4.2 I need to trace ~12 noodles from the first node to the second. Since they are in the same order and have the same names it can be automated, but it still leads to a big lane of noodles snaking between the 2 nodes, with other stuff happening in between. With a bundle/unbundle pair all this messyness can be hidden away inside the stage 1 and stage 2 nodes, where stage 1 just outputs a bundle with all the info stage 2 needs.

programmer explanation:
A bundle is like a struct in C++ or a dictionary in python.

2 Likes

I love this illustration! It makes it very clear what’s happening.

1 Like

Aha! Now I understand. The next thing that tickles my concern is the compatibility between bundle links. As of my understanding - two bundles with different sets of links (parameters or values) inside are incompatible with each other. However, they’ll look identical.

And it’s still unclear what is the user flow if one decides to add more or remove items from a bundle on bundle constructor node, what would happen on the unbundle node? Seems like the Bundle link appears to be instantly incompatible in that case and one or the other side would require manual fixing…

1 Like