diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_duplilist.h | 11 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object_dupli.cc | 114 |
2 files changed, 111 insertions, 14 deletions
diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h index 79f37d2edde..8a37348377a 100644 --- a/source/blender/blenkernel/BKE_duplilist.h +++ b/source/blender/blenkernel/BKE_duplilist.h @@ -60,6 +60,17 @@ 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. + * + * Only non-null entries are stored, ordered from innermost to outermost. + * To save memory, these arrays are allocated smaller than persistent_id, + * assuming that not every entry will be associated with a GeometrySet; any + * size between 1 and MAX_DUPLI_RECUR can be used without issues. + */ + 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 b4ccef56ee3..1b315d29923 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" @@ -101,6 +102,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; @@ -151,8 +154,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 *geometry = nullptr, + int64_t instance_index = 0) { *r_ctx = *ctx; @@ -168,6 +176,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] = instance_index; + r_ctx->instance_data[r_ctx->level] = geometry; ++r_ctx->level; if (r_ctx->level == MAX_DUPLI_RECUR - 1) { @@ -184,8 +194,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 *geometry = nullptr, + int64_t instance_index = 0) { DupliObject *dob; int i; @@ -219,6 +234,23 @@ static DupliObject *make_dupli( dob->persistent_id[i] = INT_MAX; } + /* Store geometry set data for attribute lookup in innermost to outermost + * order, copying only non-null entries to save space. */ + const int max_instance = sizeof(dob->instance_data) / sizeof(void *); + int next_instance = 0; + if (geometry != nullptr) { + dob->instance_idx[next_instance] = int(instance_index); + dob->instance_data[next_instance] = geometry; + next_instance++; + } + for (i = ctx->level - 1; i >= 0 && next_instance < max_instance; i--) { + if (ctx->instance_data[i] != nullptr) { + dob->instance_idx[next_instance] = int(ctx->instance_idx[i]); + dob->instance_data[next_instance] = ctx->instance_data[i]; + next_instance++; + } + } + /* 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. */ @@ -249,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 *geometry = nullptr, + int64_t instance_index = 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, geometry, instance_index); } /** @@ -262,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 *geometry = nullptr, + int64_t instance_index = 0) { if (ctx->instance_stack->contains(ob)) { /* Avoid recursive instances. */ @@ -272,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, geometry, instance_index)) { return; } if (rctx.gen) { @@ -875,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: { @@ -892,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; } @@ -918,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); } @@ -1719,6 +1765,41 @@ 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; + + /* Loop over layers from innermost to outermost. */ + for (const int i : IndexRange(sizeof(dupli->instance_data) / sizeof(void *))) { + /* 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]) { @@ -1809,6 +1890,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; |