[Bf-blender-cvs] [099d707ede4] temp-angavrilov: Attribute Node: access geometry node instance attributes.

Alexander Gavrilov noreply at git.blender.org
Sat Oct 1 15:18:41 CEST 2022


Commit: 099d707ede456aca29b593b84fdffc4afa1040cf
Author: Alexander Gavrilov
Date:   Fri Sep 30 21:00:27 2022 +0300
Branches: temp-angavrilov
https://developer.blender.org/rB099d707ede456aca29b593b84fdffc4afa1040cf

Attribute Node: access geometry node instance attributes.

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.

Differential Revision: https://developer.blender.org/D16114

===================================================================

M	source/blender/blenkernel/BKE_duplilist.h
M	source/blender/blenkernel/intern/object_dupli.cc

===================================================================

diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h
index 70351279467..f1e7b619819 100644
--- a/source/blender/blenkernel/BKE_duplilist.h
+++ b/source/blender/blenkernel/BKE_duplilist.h
@@ -61,6 +61,11 @@ typedef struct DupliObject {
   /* Particle this dupli was generated from. */
   struct ParticleSystem *particle_system;
 
+  /* Geometry set stack for instance attributes; for each level lists the
+   * geometry set and instance index within it. Some pointers may be null. */
+  int instance_idx[4];
+  const struct GeometrySet *instance_data[4];
+
   /* Random ID for shading */
   unsigned int random_id;
 } DupliObject;
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index 03491363726..d4e18438343 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -50,6 +50,7 @@
 #include "BKE_object.h"
 #include "BKE_particle.h"
 #include "BKE_scene.h"
+#include "BKE_type_conversions.hh"
 #include "BKE_vfont.h"
 
 #include "DEG_depsgraph.h"
@@ -103,6 +104,8 @@ struct DupliContext {
   Vector<Object *> *instance_stack;
 
   int persistent_id[MAX_DUPLI_RECUR];
+  int64_t instance_idx[MAX_DUPLI_RECUR];
+  const GeometrySet *instance_data[MAX_DUPLI_RECUR];
   int level;
 
   const struct DupliGenerator *gen;
@@ -153,8 +156,13 @@ static void init_context(DupliContext *r_ctx,
 /**
  * Create sub-context for recursive duplis.
  */
-static bool copy_dupli_context(
-    DupliContext *r_ctx, const DupliContext *ctx, Object *ob, const float mat[4][4], int index)
+static bool copy_dupli_context(DupliContext *r_ctx,
+                               const DupliContext *ctx,
+                               Object *ob,
+                               const float mat[4][4],
+                               int index,
+                               const GeometrySet *gset = nullptr,
+                               int64_t gset_idx = 0)
 {
   *r_ctx = *ctx;
 
@@ -170,6 +178,8 @@ static bool copy_dupli_context(
     mul_m4_m4m4(r_ctx->space_mat, (float(*)[4])ctx->space_mat, mat);
   }
   r_ctx->persistent_id[r_ctx->level] = index;
+  r_ctx->instance_idx[r_ctx->level] = gset_idx;
+  r_ctx->instance_data[r_ctx->level] = gset;
   ++r_ctx->level;
 
   if (r_ctx->level == MAX_DUPLI_RECUR - 1) {
@@ -186,8 +196,13 @@ static bool copy_dupli_context(
  *
  * \param mat: is transform of the object relative to current context (including #Object.obmat).
  */
-static DupliObject *make_dupli(
-    const DupliContext *ctx, Object *ob, const ID *object_data, const float mat[4][4], int index)
+static DupliObject *make_dupli(const DupliContext *ctx,
+                               Object *ob,
+                               const ID *object_data,
+                               const float mat[4][4],
+                               int index,
+                               const GeometrySet *gset = nullptr,
+                               int64_t gset_idx = 0)
 {
   DupliObject *dob;
   int i;
@@ -221,6 +236,21 @@ static DupliObject *make_dupli(
     dob->persistent_id[i] = INT_MAX;
   }
 
+  /* Store geometry set data for attribute lookup, using only non-null entries to save space. */
+  const int max_gset = sizeof(dob->instance_data) / sizeof(void *);
+  int next_gset = 0;
+  if (gset != nullptr) {
+    dob->instance_idx[next_gset] = (int)gset_idx;
+    dob->instance_data[next_gset++] = gset;
+  }
+  for (i = 1; i < ctx->level + 1 && next_gset < max_gset; i++) {
+    const GeometrySet *data = ctx->instance_data[ctx->level - i];
+    if (data != nullptr) {
+      dob->instance_idx[next_gset] = (int)ctx->instance_idx[ctx->level - i];
+      dob->instance_data[next_gset++] = data;
+    }
+  }
+
   /* Meta-balls never draw in duplis, they are instead merged into one by the basis
    * meta-ball outside of the group. this does mean that if that meta-ball is not in the
    * scene, they will not show up at all, limitation that should be solved once. */
@@ -251,9 +281,11 @@ static DupliObject *make_dupli(
 static DupliObject *make_dupli(const DupliContext *ctx,
                                Object *ob,
                                const float mat[4][4],
-                               int index)
+                               int index,
+                               const GeometrySet *gset = nullptr,
+                               int64_t gset_idx = 0)
 {
-  return make_dupli(ctx, ob, static_cast<ID *>(ob->data), mat, index);
+  return make_dupli(ctx, ob, static_cast<ID *>(ob->data), mat, index, gset, gset_idx);
 }
 
 /**
@@ -264,7 +296,9 @@ static DupliObject *make_dupli(const DupliContext *ctx,
 static void make_recursive_duplis(const DupliContext *ctx,
                                   Object *ob,
                                   const float space_mat[4][4],
-                                  int index)
+                                  int index,
+                                  const GeometrySet *gset = nullptr,
+                                  int64_t gset_idx = 0)
 {
   if (ctx->instance_stack->contains(ob)) {
     /* Avoid recursive instances. */
@@ -274,7 +308,7 @@ static void make_recursive_duplis(const DupliContext *ctx,
   /* Simple preventing of too deep nested collections with #MAX_DUPLI_RECUR. */
   if (ctx->level < MAX_DUPLI_RECUR) {
     DupliContext rctx;
-    if (!copy_dupli_context(&rctx, ctx, ob, space_mat, index)) {
+    if (!copy_dupli_context(&rctx, ctx, ob, space_mat, index, gset, gset_idx)) {
       return;
     }
     if (rctx.gen) {
@@ -877,12 +911,12 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
         Object &object = reference.object();
         float matrix[4][4];
         mul_m4_m4m4(matrix, parent_transform, instance_offset_matrices[i].values);
-        make_dupli(ctx_for_instance, &object, matrix, id);
+        make_dupli(ctx_for_instance, &object, matrix, id, &geometry_set, i);
 
         float space_matrix[4][4];
         mul_m4_m4m4(space_matrix, instance_offset_matrices[i].values, object.imat);
         mul_m4_m4_pre(space_matrix, parent_transform);
-        make_recursive_duplis(ctx_for_instance, &object, space_matrix, id);
+        make_recursive_duplis(ctx_for_instance, &object, space_matrix, id, &geometry_set, i);
         break;
       }
       case InstanceReference::Type::Collection: {
@@ -894,8 +928,13 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
         mul_m4_m4_pre(collection_matrix, parent_transform);
 
         DupliContext sub_ctx;
-        if (!copy_dupli_context(
-                &sub_ctx, ctx_for_instance, ctx_for_instance->object, nullptr, id)) {
+        if (!copy_dupli_context(&sub_ctx,
+                                ctx_for_instance,
+                                ctx_for_instance->object,
+                                nullptr,
+                                id,
+                                &geometry_set,
+                                i)) {
           break;
         }
 
@@ -920,8 +959,13 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx,
         mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values);
 
         DupliContext sub_ctx;
-        if (copy_dupli_context(
-                &sub_ctx, ctx_for_instance, ctx_for_instance->object, nullptr, id)) {
+        if (copy_dupli_context(&sub_ctx,
+                               ctx_for_instance,
+                               ctx_for_instance->object,
+                               nullptr,
+                               id,
+                               &geometry_set,
+                               i)) {
           make_duplis_geometry_set_impl(
               &sub_ctx, reference.geometry_set(), new_transform, true, false);
         }
@@ -1721,6 +1765,40 @@ void free_object_duplilist(ListBase *lb)
 /** \name Uniform attribute lookup
  * \{ */
 
+/** Lookup instance attributes assigned via geometry nodes. */
+static bool find_geonode_attribute_rgba(const DupliObject *dupli,
+                                        const char *name,
+                                        float r_value[4])
+{
+  using namespace blender;
+
+  for (int i = 0; i < sizeof(dupli->instance_data) / sizeof(void *); i++) {
+    /* Skip non-geonode layers. */
+    if (dupli->instance_data[i] == nullptr) {
+      continue;
+    }
+
+    const InstancesComponent *component =
+        dupli->instance_data[i]->get_component_for_read<InstancesComponent>();
+
+    if (component == nullptr) {
+      continue;
+    }
+
+    /* Attempt to look up the attribute. */
+    std::optional<bke::AttributeAccessor> attributes = component->attributes();
+    const VArray data = attributes->lookup<ColorGeometry4f>(name);
+
+    /* If the attribute was found and converted to float RGBA successfully, output it. */
+    if (data) {
+      copy_v4_v4(r_value, data[dupli->instance_idx[i]]);
+      return true;
+    }
+  }
+
+  return false;
+}
+
 /** Lookup an arbitrary RNA property and convert it to RGBA if possible. */
 static bool find_rna_property_rgba(PointerRNA *id_ptr, const char *name, float r_data[4])
 {
@@ -1811,6 +1889,11 @@ bool BKE_object_dupli_find_rgba_attribute(
     }
   }
 
+  /* Check geometry node dupli instance attributes. */
+  if (dupli && find_geonode_attribute_rgba(dupli, name, r_value)) {
+    return true;
+  }
+
   /* Check the dupli parent object. */
   if (dupli_parent && find_rna_property_rgba(&dupli_parent->id, name, r_value)) {
     return true;



More information about the Bf-blender-cvs mailing list