Page MenuHome

Attribute Node: access geometry node instance attributes.
ClosedPublic

Authored by Alexander Gavrilov (angavrilov) on Sep 30 2022, 12:52 PM.

Details

Summary

The Instancer mode of the node is intended for varying material
behavior between instances. Since Geometry Nodes support arbitrary
named instance attributes, this mode should include them in lookup.

To implement this it is sufficient to store references to Geometry
Node data in DupliObject, and check it during dupli attribute lookup.

In order to reduce the memory usage of DupliObject, only 4 array
entries are allocated, even though the current dupli recursion stack
limit is 8. This assumes that not every entry would be associated with
a GeometrySet instance. Hopefully, soon the whole system will be
rewritten to remove the hard limits altogether.


Test file:

All cubes should have different colors, because the shader uses Color provided by the original cube vertex colors, and uv_map generated by the Grid node. The inner Color hides the Color added to the grid by a node, which in turn hides the Color custom property on the object.

Diff Detail

Repository
rB Blender
Branch
temp-angavrilov-geonode-shader-attr (branched from master)
Build Status
Buildable 24045
Build 24045: arc lint + arc unit

Event Timeline

Alexander Gavrilov (angavrilov) requested review of this revision.Sep 30 2022, 12:52 PM
Alexander Gavrilov (angavrilov) created this revision.
  • Reorder geonode attribute lookup after particle system.

After checking the code closely, it seems particle system is always the innermost
nesting layer, so it should go first (followed by geonodes and then instancer object).

  • Figured out how to simplify code by using standard type conversions.
Brecht Van Lommel (brecht) requested changes to this revision.Sep 30 2022, 3:49 PM
Brecht Van Lommel (brecht) added inline comments.
intern/cycles/blender/object.cpp
396

Can we make this entire lookup_instance_property the Blender API function, so that any renderer or exporter can use the same logic?

source/blender/makesrna/intern/rna_depsgraph.c
652

I could not find functions named lookup_ in API, but there is some find_ so I think we should be consistent with that.

652

It's not ideal to have an API function that always returns a float4. It's not obvious how this could be extended in the future to cover e.g. strings or matrices, read integers with precision loss, or use more compact storage in the renderer float/float2/float3.

Maybe we can use FloatAttributeValue, ByteColorAttributeValue, StringAttributeValue from rna_attribute.c? These would need to be given an AttributeValue base class, to be used as the return type for this function.

The function would then return an RNA pointer with the appropriate type, and a direct pointer (assuming that possible?).

This revision now requires changes to proceed.Sep 30 2022, 3:49 PM
intern/cycles/blender/object.cpp
396

It's a good idea but I think it is out of the scope of this patch, since the same logic is already duplicated in eevee twice? If you like I can make an independent cleanup patch after this and D15941.

source/blender/makesrna/intern/rna_depsgraph.c
652

I think this is complicating it beyond need - this is specifically for shader attribute nodes, which essentially always output RGBA due to the output sockets they have. Compact storage is worthless at least unless renderers are refactored to treat instances in a coalesced manner, i.e. get them from the dupli system as grouped arrays rather than looping over individual instances, because currently per-instance metadata occupies same or more space than the data.

Maybe the function could be called find_color_attribute to reflect its fixed output type?

source/blender/blenkernel/intern/object_dupli.cc
1768–1771

Wouldn't expect you to have found this, the multiple attribute APIs make this confusing. But this can be even simpler:

const bke::AttributeAccessor attributes = component->attributes();
const VArray data = attributes.lookup<ColorGeometry4f>(name);
copy_v4_v4(r_value, data[dupli->instance_idx[i]];

Didn't compile that to test, but the big picture should work. Looking up with a specific data type means the attribute API handles the conversions for you. It will only convert the value for the single index you request.

Rebased and simplified the code more.

source/blender/blenkernel/intern/object_dupli.cc
1768–1771

I simplified it more, but note that:

  • I don't want any 'builtin' attributes to be included in the interest of reducing user surprise.
  • Lookup should fail hard if the attribute doesn't exist or the type is incompatible and can't be converted, no 'defaults' allowed.

I'm not sure how your code fares on this front.

source/blender/blenkernel/intern/object_dupli.cc
1768–1771

I don't want any 'builtin' attributes to be included in the interest of reducing user surprise.

The attribute API should be consistent between editors. If you can retrieve a builtin attribute in geometry nodes or in the attribute list in the UI, it should also be possible to retrieve it in shaders. The only builtin attribute for instances is "position" anyway.

Lookup should fail hard if the attribute doesn't exist or the type is incompatible and can't be converted, no 'defaults' allowed.

lookup<T>() returns an empty virtual array that will be "false" if the attribute doesn't exist.

source/blender/blenkernel/intern/object_dupli.cc
1804

There's no Cycles code remaining now so nothing really for me to review.

It does worry me a bit that DupliObject is growing in size so much, even if we may replace it with something else longer term. I imagine it will become an array of instances created by the depsgraph, that is no longer generated on the fly.

However in either case, you wouldn't want to store 8 ints + pointers for every instance. I'm not familiar enough with the geometry instancing data structures to know how to make this more compact. If for example there is some way for each instance to refer to its parent, or for iteration over instances to somehow keep track of this stack as it iterates.

  • Use the simplest attribute lookup method.
  • Only store non-null GeometrySet entries in DupliObject and reduce the stack to 4 entries to save memory. I think this should be ok for now, given that meaningless entries are omitted.

A bigger refactor of that part will be necessary at some point of course to improve performance significantly, but for now I can't think of a better way to get this functionality working.

source/blender/blenkernel/BKE_duplilist.h
65

Why does it use 4 here and MAX_DUPLI_RECUR in DupliContext?

source/blender/blenkernel/intern/object_dupli.cc
159

Use geometry instead of gset. Same below everywhere.

160

instance_index

238
1804

You might have to iterate over the instances in reverse so that "inner" instances have higher priority.

Jacques Lucke (JacquesLucke) requested changes to this revision.Oct 3 2022, 2:45 PM
This revision now requires changes to proceed.Oct 3 2022, 2:45 PM

Update according to review.

Alexander Gavrilov (angavrilov) marked 6 inline comments as done.Oct 3 2022, 3:19 PM
Alexander Gavrilov (angavrilov) added inline comments.
source/blender/blenkernel/BKE_duplilist.h
65

It is trying to save space in DupliObject due to concerns by only storing non-null entries here, while DupliContext stores all entries. This basically bets half of entries in the stack won't be bound to geometry node instances (e.g. technical entries for persistent id numbering).

source/blender/blenkernel/intern/object_dupli.cc
1804

The list in DupliObject is already reversed.

source/blender/blenkernel/BKE_duplilist.h
65

Ok, I think it would be good to mention that in a comment. And also mention the it in the patch/commit description. Hopefully we can get rid of these limits soonish (want to work on this at some point), but until then it would be nice if the limit is more obvious.

source/blender/blenkernel/intern/object_dupli.cc
1804

Ah ok, please mention that in a comment, just to make the intend clear.

source/blender/blenkernel/intern/object_dupli.cc
245

This requires less thinking about the order of things, and easier changes if this code is ever refactored later.

This revision is now accepted and ready to land.Oct 3 2022, 4:49 PM