Enum Sockets [Proposal]

One of our mid-term goals is to expose all node inputs as sockets. That is currently not the case for two main reasons:

  • We do not have socket types for all different data types that we want to expose. Among others, we are missing socket types for enums, color ramps and curves.
  • Sometimes changing the values that are not exposed as sockets changes which sockets are available. We don’t have a system to change the set of visible sockets depending on other sockets.

Both of these limitations are solvable. This proposal describes one way how enum sockets can work. Enum properties are the main properties that we use in many nodes that are not exposed as sockets yet. The other mentioned limitations will be worked on separately.

image

Goal and Challenge

The goal is to add a new socket type for enums. It should work for built-in as well as user-defined enums.

What makes enums more difficult than the other socket types we have already is that different sockets show very different values. We need some system that determines which values are possible for an enum socket depending on what it is ultimately connected to.

Note how the Switch node inputs have to know what enum values are allowed.
image

Prototype

I’ve build a small prototype to test how enum sockets with inferencing can work in practice. It can be downloaded from the build-bot.

The prototype currently supports the following features:

  • Enum socket that works with built-in and user-defined enums.
  • Built-in enums are used by the Collection Info and Fill Curve nodes.
  • User-defined enums can be created with the Enum node.
  • The Switch node supports switching enums.
  • Enum sockets can be exposed to the parent node group.
  • Detection of cases where an output enum is connected to multiple incompatible enum inputs.

image

Using built-in enums is probably fairly self-explanatory. So I’ll focus on the design of the Enum node now (btw, feel free to suggest alternative names to “Enum”).

Enum Node

The new Enum node creates a new user-defined enum. In the node, one can simply add new items to the enum. By connecting the enum input socket to e.g. a Group Input node, the enum can be exposed to the outside.

The node has a bunch of outputs. First there is the Index output which gives an integer for the index of the passed in enum value. This value will be useful with an updated index-based switch node. If the passed in value is invalid, it currently outputs -1. Furthermore, for every enum item there is a boolean output. They all output false except for the one that corresponds to the passed in enum value.

One important note: when the node is copied, a completely new and incompatible user-defined enum is created, even if it has the same elements in the beginning. To reuse the same Enum node in multiple places, it has to be put into a group.

Conclusion

The approach implemented in the prototype seems to be a good solution. It would be helpful to get some feedback on the following topics:

  • Do you see any downsides with the general solution implemented in the prototype?
  • Are there other possible solutions which work just as well or better?
  • Do you have any examples from the past where you wanted to expose enum sockets but did not just because you couldn’t?
  • Would you want to use enum sockets for building node-group assets? Do you have some examples you’d like to use them for?
44 Likes

Alternative name suggestion for “enum”: I would feel much more comfortable with “Options”, “Dropdown” ore something similarly normal.

7 Likes

One thing that I would maybe change is the word “Enum”. It’s really specific to computer science I feel like. If “Enum” were to be used in the UI, I would write it out as “Enumeration” but then that could lead to confusion. There might be a better word we can use here. Something like “Named Option” maybe.

EDIT: Looks like @Grinsegold feels the same way :wink:

7 Likes

I’m not sure if I understand the prototype correctly.

  1. what if the list contains more than 2 elements? we also need a more complex switch node allowing indexing inputs?
  2. If I want to access the enum list of a “resample curve node”, which contains “evaluate” “count” & “length” mode. Do I need to duplicate resample curve node 3 times and feed all of them into a switch node. In reality I may not only need to duplicate node, but also its linkage as well?

I’ve got two some name suggestions: “option” or “choice”

I like “Dropdown” as suggested by @Grinsegold

I think setting the operation on a math node using enums could be an interesting use case that makes conditional operations easier to build:

Instead of calculating both and then using a switch to select the computation I want, I first select the operation and then do the math. Idk if this is actually more efficient, but it maps to the mental model better and saves a node.

Yes, I mentioned that.

I don’t understand what you want to do exactly.

That could work. So the socket would be called “Dropdown socket” and the node “Dropdown node”? Not sure about the node name.

Imagine a situation in which you connect an enum value to a node that has different inputs based on what the enum is.
image
I think the question is, do I need to duplicate the node N times and use a switch node to handle all combination of inputs, or could there be a way to connect the enum input directly to the node and also somehow connect all possible inputs? (e.g. in this case connect both “Index” and “Source Position” on the same node.)

@jacqueslucke
Here’s my take:

This proposal is based on the following statement :
Fundamentally an enum is just an integer with assigned labels.
I believe that we’ll end up with a much more flexible design if we work on a lower level concept-wise.

In the example below if an integer is connected, the enum value would automatically change to the given index, becoming read-only, if no integer is connected, enum is accessible by user.
( If the given index is below/above min/max enum index range, we’d use the modulo, or simply clamp the values to range automatically )

Capture d’écran 2021-11-10 135146

Creating enum displays can be simply done by assigning labels to int values. i believe the concept is much more simple to understand / straightforward than what is currently proposed, perhaps a bit convoluted imo.

there’s two way we could assign labels to integer:

  1. creating a new enum from index node like this, we’d need to implement a new enum socket :

  1. display Int as enum only from the group input N panel, no special sockets needed, i much prefer this design personally, it fit much better the idea that an enum are simple representations of Integer afterall, which is the main goal of this proposal:

Users are free to use the switch by index node to switch toward their different methods :slight_smile:

Capture d’écran 2021-11-10 135146

Working with indexes also allow for field values to be used when possible
giving us the possibility to use multiple methods on different areas of an array/geo.

In Conclusion

working in a lower level (with indexes) would give us more flexibility.
And i strongly believe that flexibility should be key focus in such nodal system :grinning_face_with_smiling_eyes:
it is perhaps less beginner-friendly (to understand that counting in programming is starting from 0),
but the tradeoff is worth it, especially considering the compatibility with field.
Field support, is an important point missing in the initial post, this proposal is bringing new possibilities on the table (calculation method that would vary dynamically).

19 Likes

I would agree with @BD3D, at least in so much as working with ints seems more flexible. So if we do end up with an enum socket, I would love it if the socket could take in integers/floats (convert from) and output an integer (convert to)

No, you only need the node once. My current plan is “just” show all the sockets when the enum controlled from somewhere else. This is part of the second limitation mentioned in the beginning of the original post.

@BD3D I didn’t talk about it in the original post in detail, because it’s more an implementation detail. We have to be careful with designing the system in a way that still makes versioning impossible. Over time, for example when enum items are renamed, or their order changes or an enum item is added, we don’t want to break everything that used it. That’s why the internal value for the enum items is not exposed to the user by design.

The enum node in my original design can also work with fields. In fact internally enums are fields already in the prototype. It’s not exposed as a field yet because there isn’t really a way to use them.

If you rather work with indices, you can just build your node groups to use indices instead of enums, but then you need to keep track of name changes, reordering, etc in all nodes yourself. We could also have nodes that allow converting between enums and integers, but at these points you’ll just loose many of the benefits a proper enum abstraction can provide.

7 Likes

I am confused. On the screenshots, I don’t see any enum switch. I see just the good old bool switch node with some Enum dropdown, but not an actual enum switch node. The proper enum switch node would take an Enum, either built in or user defined, and based on that would dynamically change the input node sockets.

For examples, let’s say, I, as a user, would define this Enum “Shapes”:

  • Triangle
  • Circle
  • Square
  • Rectangle
  • Pentagon

This is what I’d expect to see:
image
A node which would let me select the enum, which would dynamically create node inputs for every enum case, and have an input index to select which of the enum case inputs it outputs.

This would be complemented by a very simple enum input node, which simply converts enum case to an integer index. It would be similar to constant value input nodes we have already have, such as float (which is still called value :rage:), vector, integer and so on. It would have Enum dropdown exactly like the Enum switch node concept picture I made above, so that the user can select which enum is used. Along with that, another dropdown to pick one of the enum cases, and one index output.

This leaves us with how are the enums defined. I am starting to think they should be treated like a new enum data type, which can be exposed to the top level UI of node groups and modifiers, which is major selling point of the enums.


I’ve read the post in its entirety, but I still can’t figure whether the proposed Enum node is something that would be temporary before we get proper enum node, or if that would become the permanent state of things. In former case, I would not mind that much, but the latter case would be very unfortunate.

1 Like

Thanks for the feedback. I think we may be talking about two different things here which are a bit mixed together. A Switch node like one you mention with an index input is planned and is already being worked on. This does not solve the problem of “enum sockets” though. In your mockup there is no enum socket that could be exposed to the parent node group.
Also I assume you intended to use geometry sockets for Triangle, Circle, etc.?

The Enum node from the original post together with a Switch node that supports an index input would be similar to your “Enum Switch” node.

Defining the enum items at the node group level is not entirely unreasonable. It may be a bit problematic when the node that is actually using the enum moves to a different group (e.g. a subgroup), which then lost information about the enum values. Also it’s not clear how you’d create a socket for the enum. I assume it may be possible to replace the Index input in your Enum Switch node with an enum socket. Still thinking about it…

2 Likes

I really like the mockup and I love the smoothness of the solution (thank you for the video).

In Blender, an enum can be presented as a dropdown or as radio buttons. So I’d avoid the name dropdown. Plus, other types are already presented the same way as they are in computer science : float, integer, etc. Enumeration sounds better to me. We can always refer to it as “enum” informally, but having a full name is preferrable for accessibility.

Also, I wouldn’t be shocked it used an integer socket. Enums work like integers in Maya, it’s not particularly destabilizing

I’m very glad you’re working on this. It’ll allow building really nice interfaces for node groups. (The curve and ramp widgets would be nice too, but I’m not sure : would they need their own socket type, or could they be used as float/color fields ?)

2 Likes

If new options in dropdown are added, it would indeed break the principle! good point.
except if the addition are always added in the end of dropdown enum, or only in breaking updates?
perhaps there are solutions that could solve these downsides? (ex: freezing enums )

having variable/dynamic operation assignation through fields is a very powerful ability!

Here below is an abstract visualization of what “dynamic” calculation method would look like, for ex, we could use a remapped field connected to math nodes calculation method input.
Any nodes that are doing individual calculations (via drop down methods) per array/geo element would benefit field input for methods.

I think field supports deserve a bit more research :slight_smile:
(I understand this might be more challenging to implement)

Perhaps we can work with field of strings instead of integers? not as friendly IMO

3 Likes

Damn, a different operation for each geometry component ? that’s mad, I love it
Curious how technically feasible this is…

1 Like

it would highly depend on the method of course, the node would need to iterate over elements. :slight_smile:

+perhaps it would come at a performance costs? ex: if the CPP function needs to check for a condition each iteration unnecessarily… (Old switch node had this problem i recall, even if input was a single value, glad the issue was solved.)

I’d be afraid this break constant folding but what do I know. It’s getting real meta with this idea

Yes, I’ve mistaken what’s being talked about.

The struct I used as an example was really just an example. Not necessarily meant to be geometry data type, but ultimately, I’d expect the enum node to work with both geometry, constant and field types.

The more I think about it, the more I think that Enums should actually be data blocks, which could be useful not only for this case, but for all future node systems. So the enum selection UI element in the nodes would be same as for example image datablock selection UI element. This would come with its own baggage though, as it’d mainly mean there has to be some sort of “enum editor” somewhere.

I really, really wish I could post examples from a certain popular game engine which has a node based scripting language which handles in an amazing to use, yet very simple manner.

I am a bit confused here as well. Do we want sockets for enum or for enum values? I mean enum socket would not make sense, as in that it would not make sense for some user using a GN-made modifier to select the type of enum that’s being used for example for the enum switch node I mocked up above. In that case, changing the enum itself would change the input slots of the enum switch node and therefore break the node network.

So I assume what you are talking about is the enum index. Something that carries enum value/case information instead of just integer, so that the UI interprets it as a dropdown menu of named entries rather than an integer value input UI element.

So here’s what I am thinking would work:

  • The enums themselves should not be data type in GN in a sense of being somethings you can pass around through node links and node sockets. But they should be a data block you can create to create user defined enum.
  • The enum case/index should be a data type that you can pass around through node sockets and links in GN. For example, using my example of “Shapes” enum described above, creating a GN node network input of “Shapes” enum type, use would see a drop down UI element containing those 5 shapes in the GN modified UI in properties editor. In the GN node editor, wire from this input would carry the enum case/index of currently selected shape.
  • If this enum data type is connected into enum input socket in a node like Enum Switch showcased above, it’d work as expected. If it was connected to integer input socket, it would be implicitly converted from enum case into the integer index. GN is already doing implicit type conversions, and it communicates them to the user using node link color transitions.

So that leaves me with the question - if you create an enum input in a node group or GN node network, how do you specify which enum datablock it uses? There should be enum datablock selector in the node group/node network input settings UI somewhere.

This brings me back to the unfortunate aspect of Blender development, where the essential features are omitted for ages. For years, I, and many others have been asking for an ability to be able to edit node group/node network input types:
image
image
image
Right now, the workflow is embarrassing, where the only way to define the type of the input is by grabbing random node which has socket of the type you want, and dragging it over to the empty node socket of the input node. And once you do that, you are commited to that input type, and only way to change it is to delete it and start from scratch.

On the screenshots above, you can see that each input type has its unique UI with whatever it needs. Vector has Vector input UI element, Color has Color selector, and so on. If we had this already in place, and users could simply select the type of the input, then the last missing piece of puzzle would simply be for the Enum input socket type to have Enum datablock selector to define which Enum the given input has. That would be the proper place to specify it.

The enum input socket type would have:

  • Enum datablock selector to select which enum it is
  • Enum default value selector to specify which Enum case is the default when the input socket is empty (or in the GN modifier in properties panel)
2 Likes