(Using Blender 3.6.12)
The proposed approach is a workaround for Instance on Points
node not transferring attributes from "input instances" to "spawned instances", unless a Realize Instance
node is inserted. It is taking advantage that attributes attached to "input points" are transferred to "spawned instances", and that instances in a collection are always picked in the same alphabetical order. From that, a lookup table is built to gather user-defined attributes in relation with instance indices.
This view illustrates that only instances are generated, as required. The "RNGType" column is coding the index of the spawned geometry picked in the "Instances" collection. It is matching the alphabetical order of the "Name" column.
Resources:
(Blender 3.6.12+)
GeometryNodes modifiers
This GeometryNodes modifier is attached to each object in the "Instances" collection to set the value of the user-defined attribute "myValue".
1. This attribute is stored in the Instance domain, as a global variable the same for all vertices.
2. To do so, the Geometry has to be converted to an Instance beforehand.
This is the core GeometryNodes modifier with the cascading Instance on Points
nodes.
1. Instead of plugging directly the Random Value
node drawing the Instance Index into the first Instance on Points
node, its returned value is cached in the attribute named "RNGType". To do so, a Store Named Attribute
node set in Point domain is inserted after the Subdivide Mesh
node.
2. Consequently, a Named Attribute
node is plugged instead in the Instance Index socket of the first Instance on Points
node. It is to observe (e.g. plugging a Viewer
node) that the "RNGType" attribute is transferred from the Point domain to each instance returned by the Instance on Points
node, along the "UVMap" attribute.
3. From this node, the "RNGType" data is travelling along the path highlighted with white stars. It is crucial to compute the Instance Index required by the second Instance on Points
node. It is to notice that the Instances to Points
node is transferring the "RNGType" and "UVMap" attributes from the Instance domain to the Point domain.
4. The lookup table is initialized as a Point Cloud made of as many points there are instances in the collection "Instances". This count is returned by a Domain Size
node with Component set to Instances. The Position of these points is set from each point index $i$ to $(i,i,i)$, i.e. (0,0,0), (1,1,1) and (2,2,2) in the demonstration case. This index is again cached in Point domain in an attribute named "IDinCollection".
5. Through a third Instance on Points
node followed by a Realize Instance
node, a single occurrence of each geometry stored in the collection "Instances" are joined together into a single mesh. Along this process, the "IDinCollection" attribute (resp. the user-defined "myValue" attribute) is transferred from the Point (Cloud) domain (resp. Instance domain) to the Point (Mesh) domain. Consequently, each resulting vertex keeps the trace of the original geometry it belongs to through the "IDinCollection" attribute, as well as the trace of any attribute attached to the same original geometry. This can be observed by plugging a Viewer
node after the Realize Instances
node (see the section "Additional results about the lookup table" below).
6. To finalize the lookup table, the Position of these vertices is set from their "IDinCollection" attribute $i$ to $(i,i,i)$, collapsing the whole mesh onto the Point Cloud created at step 4. Only one vertex per original geometry in the collection "Instances" is kept using a Merge by Distance
node. (NB: The Set Position
node can be removed if the "Scale" is set to (0,0,0) in the Instance on Points
node).
7. To query the lookup table, firstly a Sample Nearest
node set in Point domain is used to recover the Index of the lookup table vertex the closest to the sought index stored in the "RNGType" attribute.
8. Then the value of the stored attribute "myValue" is recovered from the lookup table using a Sample Index
node set in Point domain.
Additional results about the lookup table
The Spreadsheet Editor shows the lookup table under construction after step 4. It is a Point Cloud where each point is coding one row of the table. The main feature is the Position that is used afterwards to query such a row based on its index with a Sample Nearest
node, independently of Blender internal indexing of vertices.
The Spreadsheet Editor shows the lookup table under construction after step 5. It is a Mesh collecting all the vertices of every instanced geometry. These vertices are carrying the attributes attached both to the Points (i.e. "IDinCollection" here) and the Instance (i.e. "myValue" here) they are spawned from. It is to notice that the Instance on Points
node is transferring the attributes attached to the Points, while the Realize Instances
node is transferring the attributes attached to the Instance. Both nodes are required to complete the transfer.
The Spreadsheet Editor shows the lookup table under construction during step 6, before applying Merge by Distance
. Vertices are moved to the position defined by the index of the instance they are spawned from (i.e. "IDinCollection" here).
The Spreadsheet Editor shows the final lookup table after step 6. It has the same structure as after step 4, notwithstanding that it is a Mesh instead of a Point Cloud. The main addition is the column storing the user-defined attribute "myValue".
NB: A Point Cloud could be set from this Mesh where Blender internal indexing of points were matching the "IDinCollection" attribute, using the same process involving the Sample Nearest
node. This way, the Sample Index
node at step 8 could be linked directly to the Named Attribute
node returning the "RNGType" value. The underlying logic is the same, but the performance could be better for large collections.