Fields and Anonymous Attributes [Proposal]

As can be seen in the mockups, it is still possible to write to attributes by name and to retrieve data from attributes by name.

Loops are not part of this proposal. They can be discussed separately.

Sure.

Seeing the partially evaluated geometry in edit mode and being able to select parts of it, is not part of this proposal.

No, it just means means that the Attribute Processor would not be necessary if this proposal would be accepted. While I do not know exactly how you’d generate new geometry just from fields, I’m sure there are ways. The proposed system does not have this inherent limitation that the Attribute Processor has.

No, a list is a finite ordered sequence of values (for me in this context anyway). A field is a function that computes a single value based on some inputs. I wouldn’t say these things are the same. I might be possible to see a list as a special case of a field, but not really because a field does not have a length.

When you have a field, you usually shouldn’t think of it as multiple values, but as a single value (this is why it is possible to reuse the existing sockets). Operations on lists (like append, shift, reverse, …) don’t really make sense on fields. However, I do see value in these kinds of operations for some tasks, so I think have lists in geometry nodes in addition to the fields system would be valuable.
Just to think this a bit further: If we support lists, we can also me the field system work for them. So a vector list socket would be a vector list field. This could be useful if you want to access e.g. all the positions of connected vertices to the “current” vertex.

There is certainly a bit more overhead when everything is treated as a field internally. However, I doubt that this will have a noticeable impact on performance. That’s mainly because the overhead is in the order of O(number of sockets) instead of O(amount of data being processed).

The existing concept of attributes on geometry is not going anywhere. All the existing nodes can still work if this proposal is accepted. It’s just that they offer a much worse workflow. I do not know yet how we will handle the existing nodes. We could just change the nodes that are easy to write versioning for and just leave the others as they are.

That’s a separate topic. It is handled as part of the compact nodes discussion.

6 Likes

23 likes in 18 hours after publishing the thread. Let that be the testament of how well you’ve hit the nail in the head :slight_smile:

This single post addresses the vast majority of the workflow issues GN currently has. All I hope for is that there will be as little obstacles and bureaucracy standing in the way of you implementing it.

EDIT: Just one more thought. If this was greenlit and decided to be implemented, it’d make Attribute Processor node redundant and obsolete. In that case, wouldn’t it make sense to stop working on it? I mean if we had this set of capabilities, it would degrade Attribute Processor to be more or less user-confusing clutter.

2 Likes

What I meant by that is, would there be a way of just typing an attribute name in a value slider expecting a field? such as the “distance” property of the “extrude” node here :
https://devtalk.blender.org/uploads/default/original/3X/d/b/db777075846a1743d8c1fac2880ddc593707fc46.png
Or would this require connecting to and “attribute get” node’s output socket?

What I’m really asking here I guess, is how much more crowded would node trees become, in real-world situations with complex procedural models. I guess we’d have to use it for a little while to figure that out. Now that being said, we can now hide any complicated attribute wrangling in regular node groups, correct?

I talk about this in the Immediate Attributes and Expressions section of the proposal.

Think so, yes.

1 Like

I didn’t realize that was an attribute name you were typing in there. Awesome! Thanks for clarifying all that for me. It’s a beast to wrap your head around for someone less technically inclined like me.

Great proposal @jacqueslucke, i think we are converging on a very similar set of ideas.

Some thoughts while reading (apologies for repeating what you just said, just trying to put it in my own words):

  • Field in physics: eval’d at a position, i.e. is a function R^3 → X. If “fields” can have any type of parameter then a list can be viewed as a field over the index (natural numbers): N → X.
    In other words: Fields are still just functions.

  • What sets fields apart would be that parameters may be semantically defined, i.e. there can be an input node Get Position and it would return a vector. If you run that in a shader it would return World/Object position (which one?), in a geometry context would be vertex position. Devil is in the details here.

  • What determines the parameter at which the field is evaluated? It’s an implicit argument, it has to be defined somewhere as part of the context the node is eval’d in.
    We’ve had a few approaches to this now:

    • Shader nodes have a well defined and rigid set of input parameters that can be accessed through Texture Coordinate nodes and the like. Geometry attributes are only partially supported and inconsistent between renderers.
      The context in shader nodes is always the currently rendered object, no surprises there.
    • GN right now always pass along a Geometry input, that is the context for evaluating attributes.
    • Attribute Processor makes a group node that provides the context - very explicit, but also quite cumbersome to work with, and group nodes can’t be shared with other nodetree types.
    • Ideas floating around for deducing context from target nodes: it can be back-propagated to any input node that doesn’t define such context itself.
      In your examples this is quite clear in the Delete Geometry node: it would have a Domain setting and the output of the Element Index node’s Domain Size would depend on that context.
  • Important caveat: Without an explicit context socket (like Geometry) a node may be evaluated in multiple different contexts.
    Compare: Color computation connected to multiple Shader-type nodes. A natural concept in shaders, but GN currently does not generally do this.
    Say you would connect the nodes of the Delete Geometry example to two separate Delete Geometry nodes, now you have to evaluate twice for the two different contexts (not a problem per se, just pointing this out).

2 Likes

@LukasTonne Thanks for the feedback. Not sure if you wanted to ask any specific question in your comment. Just wanted to say that I can confirm everything you said.

Do we need to expect downgrades with this proposal? Perhaps some nodes that will be removed ?

I remember reading from the workshop report that there was something along the lines of “Attribute Processor discussion did not get consensus” and it seems they were talking about “alternative” in the final day. And Jacques also said this in this thread:

It seems to me that Attribute Processor is very unlikely to make it to the master now.

I really hope that will be the case :slight_smile:

This proposal does not require us to remove any existing nodes. We might want to remove some (with automatic patching of existing files), but we don’t have to.

12 Likes

Glad to hear this Well played ! :+1:

I like this proposal a lot, it introduces a lot of flexibility, but keeps things understandable when you don’t understand all of the concepts. I wanted to add a comment with some mockups of how it solves some problems I’ve been thinking about recently:

Creating Curves From Math Formulas
Often don’t already have a curve, but you want to create on with a specific shape. Maybe one defined by specific math you already know. Originally I thought something like this would work:
image
That’s nice, but it forces you to use expressions, and it has an awkward implementation of these separate variables “a” and “b”, which now can’t vary per point. So useful, but not flexible enough!


This is a similar setup as above with the fields proposal. You get all of the flexibility from the fields, but it’s quite readable, since you can just use regular nodes. You can also have an arbitrary number of constant or per-point inputs to the field. You could sample a volume, a curve, use a falloff, or anything mentioned above to build the curve on each axis.

Creating Volumes from Scratch
Creating volumes and operating on them is often a very heavy process, so we have to think a bit more about how systems are design to decrease the amount of temporary copying, resampling, etc.


With a field, you can define a function at every point, and simply sample it with a volume creation node. That means that assembling a volume can look like doing regular math operations, a lot like shader nodes, which IMO is an intuitive way to handle this sort of creation.

EDIT: One thing that could use work in these mockups is how the “factor” input is read by the fields. In the mockup it is implicit based on unconnected float input sockets.

21 Likes

What is the most fundamental idea on the implementation? I am trying to get the basic grasp of it.

// https://github.com/blender/blender/blob/594f47ecd2d5367ca936cf6fc6ec8168c2b360d0/source/blender/makesdna/DNA_node_types.h#L540

#include <iostream>
#include <math.h>
using namespace std;


struct bNodeSocketValueFloat {
  float value;
  float min, max;

  uint fnparamcount = 0;
  float* fnparams = nullptr;
  float (*function)(float* x);
  
  float getValue() {
      if (function) {
        return function(fnparams);
      }
      return value;
  }
};

float sigmoid(float* x) {
    // say for example this is the output
    // function of a complex node setup
    return 1.0f / (1.0f + exp(-x[0]));
}

int main() {
    auto v = bNodeSocketValueFloat();
    v.value = 10.23f;
    
    // by default returns the value
    cout << v.getValue() << endl;
    
    v.function = sigmoid;
    v.fnparamcount = 1;
    v.fnparams = new float();
    v.fnparams[0] = 5.0f;
    
    // now since it has a function assigned
    // it will use the function instead
    cout << v.getValue() << endl;
    
    return 0;
}

// output
// 10.23
// 0.993307

What I understood is that, you might be able to take a much more functional programming approach, and have the option to interchange between functions and values. Not only be limited to values.

@cconst The implementation will probably look quite different. There is a difference between the value that is stored in DNA for the socket (bNodeSocketValueFloat) and the value that is computed during evaluation (currently float, with this proposal something like FloatField).

I’d prefer not to discuss the exact implementation details yet here and keep this discussion on a more conceptual level. If you are interested in these details, just can ask on blender.chat in the geometry-nodes channel.

From the point of view of an artist, this feels like this is how it should work. I can apply logic learned from shader nodes as is and get results. That was not the case with the current iteration of geometry nodes. I expected to be be able to get attributes and pass them around the same way in shader nodes I use texture coordinates or object info like material index. Attributes and text fields feels more like a programming concept, separate from node logic. The closer we can get to matching how the two node trees work, the easier they will be to learn and use for everyone.

6 Likes

Do we need to expect downgrades with this proposal? Perhaps some nodes that will be removed ?

And it will be possible to convert every node that we currently have to this new system just in time for 3.0? :face_with_raised_eyebrow:

And it will be possible to convert every node that we currently have to this new system just in time for 3.0?

As I already said, it’s not strictly necessary to convert anything.
Supporting fields in all the math/utility nodes should be fairly straight forward and probably does not even need changes to all the nodes, just in one central place.

2 Likes

But fields doesn’t mean that we can’t work like actually with the list of elements. Or yes?

No, fields are not lists. The concept of lists can be added with or without this proposal.