From f5dc34ec9c05cc8f1163313baafe634f4798c29b Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Fri, 11 Dec 2020 18:00:37 +0100 Subject: Geometry Nodes: support instancing collections The Point Instance node can instance entire collections now. Before, only individual collections were supported. Randomly selecting objects from the collection on a per point basis is not support, yet. Last part of D9739. Ref T82372. --- source/blender/blenkernel/BKE_geometry_set.h | 16 ++++++- source/blender/blenkernel/BKE_geometry_set.hh | 15 +++++-- source/blender/blenkernel/intern/geometry_set.cc | 46 +++++++++++++++----- source/blender/blenkernel/intern/object_dupli.c | 53 ++++++++++++++++++------ 4 files changed, 103 insertions(+), 27 deletions(-) (limited to 'source/blender/blenkernel') diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h index 026f4d39d51..87bb96be145 100644 --- a/source/blender/blenkernel/BKE_geometry_set.h +++ b/source/blender/blenkernel/BKE_geometry_set.h @@ -26,16 +26,30 @@ extern "C" { struct Object; struct GeometrySet; +struct Collection; void BKE_geometry_set_free(struct GeometrySet *geometry_set); bool BKE_geometry_set_has_instances(const struct GeometrySet *geometry_set); +typedef enum InstancedDataType { + INSTANCE_DATA_TYPE_OBJECT = 0, + INSTANCE_DATA_TYPE_COLLECTION = 1, +} InstancedDataType; + +typedef struct InstancedData { + InstancedDataType type; + union { + struct Object *object; + struct Collection *collection; + } data; +} InstancedData; + int BKE_geometry_set_instances(const struct GeometrySet *geometry_set, float (**r_positions)[3], float (**r_rotations)[3], float (**r_scales)[3], - struct Object ***r_objects); + struct InstancedData **r_instanced_data); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index b7cb9320086..617e0c45ae4 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -35,6 +35,7 @@ struct Mesh; struct PointCloud; struct Object; +struct Collection; /* Each geometry component has a specific type. The type determines what kind of data the component * stores. Functions modifying a geometry will usually just modify a subset of the component types. @@ -358,7 +359,7 @@ class InstancesComponent : public GeometryComponent { blender::Vector positions_; blender::Vector rotations_; blender::Vector scales_; - blender::Vector objects_; + blender::Vector instanced_data_; public: InstancesComponent(); @@ -366,12 +367,20 @@ class InstancesComponent : public GeometryComponent { GeometryComponent *copy() const override; void clear(); - void add_instance(const Object *object, + void add_instance(Object *object, blender::float3 position, blender::float3 rotation = {0, 0, 0}, blender::float3 scale = {1, 1, 1}); + void add_instance(Collection *collection, + blender::float3 position, + blender::float3 rotation = {0, 0, 0}, + blender::float3 scale = {1, 1, 1}); + void add_instance(InstancedData data, + blender::float3 position, + blender::float3 rotation, + blender::float3 scale); - blender::Span objects() const; + blender::Span instanced_data() const; blender::Span positions() const; blender::Span rotations() const; blender::Span scales() const; diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 28695d769d3..e6a67b191f8 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -460,31 +460,54 @@ GeometryComponent *InstancesComponent::copy() const new_component->positions_ = positions_; new_component->rotations_ = rotations_; new_component->scales_ = scales_; - new_component->objects_ = objects_; + new_component->instanced_data_ = instanced_data_; return new_component; } void InstancesComponent::clear() { - objects_.clear(); + instanced_data_.clear(); positions_.clear(); rotations_.clear(); scales_.clear(); } -void InstancesComponent::add_instance(const Object *object, + +void InstancesComponent::add_instance(Object *object, + blender::float3 position, + blender::float3 rotation, + blender::float3 scale) +{ + InstancedData data; + data.type = INSTANCE_DATA_TYPE_OBJECT; + data.data.object = object; + this->add_instance(data, position, rotation, scale); +} + +void InstancesComponent::add_instance(Collection *collection, + blender::float3 position, + blender::float3 rotation, + blender::float3 scale) +{ + InstancedData data; + data.type = INSTANCE_DATA_TYPE_COLLECTION; + data.data.collection = collection; + this->add_instance(data, position, rotation, scale); +} + +void InstancesComponent::add_instance(InstancedData data, blender::float3 position, blender::float3 rotation, blender::float3 scale) { - objects_.append(object); + instanced_data_.append(data); positions_.append(position); rotations_.append(rotation); scales_.append(scale); } -Span InstancesComponent::objects() const +Span InstancesComponent::instanced_data() const { - return objects_; + return instanced_data_; } Span InstancesComponent::positions() const @@ -509,8 +532,11 @@ MutableSpan InstancesComponent::positions() int InstancesComponent::instances_amount() const { - BLI_assert(positions_.size() == objects_.size()); - return objects_.size(); + const int size = instanced_data_.size(); + BLI_assert(positions_.size() == size); + BLI_assert(rotations_.size() == size); + BLI_assert(scales_.size() == size); + return size; } bool InstancesComponent::is_empty() const @@ -538,7 +564,7 @@ int BKE_geometry_set_instances(const GeometrySet *geometry_set, float (**r_positions)[3], float (**r_rotations)[3], float (**r_scales)[3], - Object ***r_objects) + InstancedData **r_instanced_data) { const InstancesComponent *component = geometry_set->get_component_for_read(); if (component == nullptr) { @@ -547,7 +573,7 @@ int BKE_geometry_set_instances(const GeometrySet *geometry_set, *r_positions = (float(*)[3])component->positions().data(); *r_rotations = (float(*)[3])component->rotations().data(); *r_scales = (float(*)[3])component->scales().data(); - *r_objects = (Object **)component->objects().data(); + *r_instanced_data = (InstancedData *)component->instanced_data().data(); return component->instances_amount(); } diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index d5434710e23..8fa708f31cb 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -816,15 +816,13 @@ static void make_duplis_instances_component(const DupliContext *ctx) float(*positions)[3]; float(*rotations)[3]; float(*scales)[3]; - Object **objects; + InstancedData *instanced_data; const int amount = BKE_geometry_set_instances( - ctx->object->runtime.geometry_set_eval, &positions, &rotations, &scales, &objects); + ctx->object->runtime.geometry_set_eval, &positions, &rotations, &scales, &instanced_data); for (int i = 0; i < amount; i++) { - Object *object = objects[i]; - if (object == NULL) { - continue; - } + InstancedData *data = &instanced_data[i]; + float scale_matrix[4][4]; size_to_mat4(scale_matrix, scales[i]); float rotation_matrix[4][4]; @@ -833,14 +831,43 @@ static void make_duplis_instances_component(const DupliContext *ctx) mul_m4_m4m4(instance_offset_matrix, rotation_matrix, scale_matrix); copy_v3_v3(instance_offset_matrix[3], positions[i]); - float matrix[4][4]; - mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrix); - make_dupli(ctx, object, matrix, i); + if (data->type == INSTANCE_DATA_TYPE_OBJECT) { + Object *object = data->data.object; + if (object != NULL) { + float matrix[4][4]; + mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrix); + make_dupli(ctx, object, matrix, i); + + float space_matrix[4][4]; + mul_m4_m4m4(space_matrix, instance_offset_matrix, object->imat); + mul_m4_m4_pre(space_matrix, ctx->object->obmat); + make_recursive_duplis(ctx, object, space_matrix, i); + } + } + else if (data->type == INSTANCE_DATA_TYPE_COLLECTION) { + Collection *collection = data->data.collection; + if (collection != NULL) { + float collection_matrix[4][4]; + unit_m4(collection_matrix); + sub_v3_v3(collection_matrix[3], collection->instance_offset); + mul_m4_m4_pre(collection_matrix, instance_offset_matrix); + mul_m4_m4_pre(collection_matrix, ctx->object->obmat); + + eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, object, mode) { + if (object == ctx->object) { + continue; + } + + float instance_matrix[4][4]; + mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat); - float space_matrix[4][4]; - mul_m4_m4m4(space_matrix, instance_offset_matrix, object->imat); - mul_m4_m4_pre(space_matrix, ctx->object->obmat); - make_recursive_duplis(ctx, object, space_matrix, i); + make_dupli(ctx, object, instance_matrix, i); + make_recursive_duplis(ctx, object, collection_matrix, i); + } + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; + } + } } } -- cgit v1.2.3