Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/object_dupli.cc
| Show All 18 Lines | |||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_math_vec_types.hh" | #include "BLI_math_vec_types.hh" | ||||
| #include "BLI_rand.h" | #include "BLI_rand.h" | ||||
| #include "BLI_span.hh" | #include "BLI_span.hh" | ||||
| #include "BLI_vector.hh" | #include "BLI_vector.hh" | ||||
| #include "DNA_anim_types.h" | #include "DNA_anim_types.h" | ||||
| #include "DNA_collection_types.h" | #include "DNA_collection_types.h" | ||||
| #include "DNA_curves_types.h" | |||||
| #include "DNA_mesh_types.h" | #include "DNA_mesh_types.h" | ||||
| #include "DNA_meshdata_types.h" | #include "DNA_meshdata_types.h" | ||||
| #include "DNA_modifier_types.h" | |||||
| #include "DNA_pointcloud_types.h" | #include "DNA_pointcloud_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_vfont_types.h" | #include "DNA_vfont_types.h" | ||||
| #include "DNA_volume_types.h" | #include "DNA_volume_types.h" | ||||
| #include "BKE_collection.h" | #include "BKE_collection.h" | ||||
| #include "BKE_duplilist.h" | #include "BKE_duplilist.h" | ||||
| #include "BKE_editmesh.h" | #include "BKE_editmesh.h" | ||||
| #include "BKE_editmesh_cache.h" | #include "BKE_editmesh_cache.h" | ||||
| #include "BKE_geometry_set.h" | #include "BKE_geometry_set.h" | ||||
| #include "BKE_geometry_set.hh" | #include "BKE_geometry_set.hh" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_idprop.h" | #include "BKE_idprop.h" | ||||
| #include "BKE_lattice.h" | #include "BKE_lattice.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_mesh_iterators.h" | #include "BKE_mesh_iterators.h" | ||||
| #include "BKE_mesh_runtime.h" | #include "BKE_mesh_runtime.h" | ||||
| #include "BKE_modifier.h" | |||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "BKE_particle.h" | #include "BKE_particle.h" | ||||
| #include "BKE_scene.h" | #include "BKE_scene.h" | ||||
| #include "BKE_vfont.h" | #include "BKE_vfont.h" | ||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| #include "BLI_hash.h" | #include "BLI_hash.h" | ||||
| #include "BLI_strict_flags.h" | |||||
| #include "NOD_geometry_nodes_log.hh" | |||||
| using blender::Array; | using blender::Array; | ||||
| using blender::float3; | using blender::float3; | ||||
| using blender::float4x4; | using blender::float4x4; | ||||
| using blender::Span; | using blender::Span; | ||||
| using blender::Vector; | using blender::Vector; | ||||
| namespace geo_log = blender::nodes::geo_eval_log; | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Internal Duplicate Context | /** \name Internal Duplicate Context | ||||
| * \{ */ | * \{ */ | ||||
| struct DupliContext { | struct DupliContext { | ||||
| Depsgraph *depsgraph; | Depsgraph *depsgraph; | ||||
| /** XXX child objects are selected from this group if set, could be nicer. */ | /** XXX child objects are selected from this group if set, could be nicer. */ | ||||
| Collection *collection; | Collection *collection; | ||||
| /** Only to check if the object is in edit-mode. */ | /** Only to check if the object is in edit-mode. */ | ||||
| Object *obedit; | Object *obedit; | ||||
| Scene *scene; | Scene *scene; | ||||
| Object *object; | Object *object; | ||||
| float space_mat[4][4]; | float space_mat[4][4]; | ||||
| /** | |||||
| * Index of the top-level instance that contains this context or -1 when unused. | |||||
| * This is an index into the instances component of #preview_base_geometry. | |||||
| */ | |||||
| int preview_instance_index; | |||||
| /** | |||||
| * Top level geometry set that is previewed. | |||||
| */ | |||||
| const GeometrySet *preview_base_geometry; | |||||
| /** | /** | ||||
| * A stack that contains all the "parent" objects of a particular instance when recursive | * A stack that contains all the "parent" objects of a particular instance when recursive | ||||
| * instancing is used. This is used to prevent objects from instancing themselves accidentally. | * instancing is used. This is used to prevent objects from instancing themselves accidentally. | ||||
| * Use a vector instead of a stack because we want to use the #contains method. | * Use a vector instead of a stack because we want to use the #contains method. | ||||
| */ | */ | ||||
| Vector<Object *> *instance_stack; | Vector<Object *> *instance_stack; | ||||
| Show All 36 Lines | static void init_context(DupliContext *r_ctx, | ||||
| else { | else { | ||||
| unit_m4(r_ctx->space_mat); | unit_m4(r_ctx->space_mat); | ||||
| } | } | ||||
| r_ctx->level = 0; | r_ctx->level = 0; | ||||
| r_ctx->gen = get_dupli_generator(r_ctx); | r_ctx->gen = get_dupli_generator(r_ctx); | ||||
| r_ctx->duplilist = nullptr; | r_ctx->duplilist = nullptr; | ||||
| r_ctx->preview_instance_index = -1; | |||||
| r_ctx->preview_base_geometry = nullptr; | |||||
| } | } | ||||
| /** | /** | ||||
| * Create sub-context for recursive duplis. | * Create sub-context for recursive duplis. | ||||
| */ | */ | ||||
| static bool copy_dupli_context( | static bool copy_dupli_context( | ||||
| DupliContext *r_ctx, const DupliContext *ctx, Object *ob, const float mat[4][4], int index) | DupliContext *r_ctx, const DupliContext *ctx, Object *ob, const float mat[4][4], int index) | ||||
| { | { | ||||
| *r_ctx = *ctx; | *r_ctx = *ctx; | ||||
| /* XXX annoying, previously was done by passing an ID* argument, | /* XXX annoying, previously was done by passing an ID* argument, | ||||
| * this at least is more explicit. */ | * this at least is more explicit. */ | ||||
| if (ctx->gen->type == OB_DUPLICOLLECTION) { | if (ctx->gen && ctx->gen->type == OB_DUPLICOLLECTION) { | ||||
| r_ctx->collection = ctx->object->instance_collection; | r_ctx->collection = ctx->object->instance_collection; | ||||
| } | } | ||||
| r_ctx->object = ob; | r_ctx->object = ob; | ||||
| r_ctx->instance_stack = ctx->instance_stack; | r_ctx->instance_stack = ctx->instance_stack; | ||||
| if (mat) { | if (mat) { | ||||
| mul_m4_m4m4(r_ctx->space_mat, (float(*)[4])ctx->space_mat, mat); | mul_m4_m4m4(r_ctx->space_mat, (float(*)[4])ctx->space_mat, mat); | ||||
| } | } | ||||
| Show All 27 Lines | static DupliObject *make_dupli( | ||||
| } | } | ||||
| else { | else { | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| dob->ob = ob; | dob->ob = ob; | ||||
| dob->ob_data = const_cast<ID *>(object_data); | dob->ob_data = const_cast<ID *>(object_data); | ||||
| mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat); | mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat); | ||||
| dob->type = ctx->gen->type; | dob->type = ctx->gen == nullptr ? 0 : ctx->gen->type; | ||||
| dob->preview_base_geometry = ctx->preview_base_geometry; | |||||
| dob->preview_instance_index = ctx->preview_instance_index; | |||||
| /* Set persistent id, which is an array with a persistent index for each level | /* Set persistent id, which is an array with a persistent index for each level | ||||
| * (particle number, vertex number, ..). by comparing this we can find the same | * (particle number, vertex number, ..). by comparing this we can find the same | ||||
| * dupli-object between frames, which is needed for motion blur. | * dupli-object between frames, which is needed for motion blur. | ||||
| * The last level is ordered first in the array. */ | * The last level is ordered first in the array. */ | ||||
| dob->persistent_id[0] = index; | dob->persistent_id[0] = index; | ||||
| for (i = 1; i < ctx->level + 1; i++) { | for (i = 1; i < ctx->level + 1; i++) { | ||||
| dob->persistent_id[i] = ctx->persistent_id[ctx->level - i]; | dob->persistent_id[i] = ctx->persistent_id[ctx->level - i]; | ||||
| ▲ Show 20 Lines • Show All 580 Lines • ▼ Show 20 Lines | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Instances Geometry Component Implementation | /** \name Instances Geometry Component Implementation | ||||
| * \{ */ | * \{ */ | ||||
| static void make_duplis_geometry_set_impl(const DupliContext *ctx, | static void make_duplis_geometry_set_impl(const DupliContext *ctx, | ||||
| const GeometrySet &geometry_set, | const GeometrySet &geometry_set, | ||||
| const float parent_transform[4][4], | const float parent_transform[4][4], | ||||
| bool geometry_set_is_instance) | bool geometry_set_is_instance, | ||||
| bool use_new_curves_type) | |||||
| { | { | ||||
| int component_index = 0; | int component_index = 0; | ||||
| if (ctx->object->type != OB_MESH || geometry_set_is_instance) { | if (ctx->object->type != OB_MESH || geometry_set_is_instance) { | ||||
| if (const Mesh *mesh = geometry_set.get_mesh_for_read()) { | if (const Mesh *mesh = geometry_set.get_mesh_for_read()) { | ||||
| make_dupli(ctx, ctx->object, &mesh->id, parent_transform, component_index++); | make_dupli(ctx, ctx->object, &mesh->id, parent_transform, component_index++); | ||||
| } | } | ||||
| } | } | ||||
| if (ctx->object->type != OB_VOLUME || geometry_set_is_instance) { | if (ctx->object->type != OB_VOLUME || geometry_set_is_instance) { | ||||
| if (const Volume *volume = geometry_set.get_volume_for_read()) { | if (const Volume *volume = geometry_set.get_volume_for_read()) { | ||||
| make_dupli(ctx, ctx->object, &volume->id, parent_transform, component_index++); | make_dupli(ctx, ctx->object, &volume->id, parent_transform, component_index++); | ||||
| } | } | ||||
| } | } | ||||
| if (!ELEM(ctx->object->type, OB_CURVES_LEGACY, OB_FONT, OB_CURVES) || geometry_set_is_instance) { | if (!ELEM(ctx->object->type, OB_CURVES_LEGACY, OB_FONT, OB_CURVES) || geometry_set_is_instance) { | ||||
| if (const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>()) { | if (const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>()) { | ||||
| if (use_new_curves_type) { | |||||
| if (const Curves *curves = component->get_for_read()) { | |||||
| make_dupli(ctx, ctx->object, &curves->id, parent_transform, component_index++); | |||||
| } | |||||
| } | |||||
| else { | |||||
| if (const Curve *curve = component->get_curve_for_render()) { | if (const Curve *curve = component->get_curve_for_render()) { | ||||
| make_dupli(ctx, ctx->object, &curve->id, parent_transform, component_index++); | make_dupli(ctx, ctx->object, &curve->id, parent_transform, component_index++); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| if (ctx->object->type != OB_POINTCLOUD || geometry_set_is_instance) { | if (ctx->object->type != OB_POINTCLOUD || geometry_set_is_instance) { | ||||
| if (const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read()) { | if (const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read()) { | ||||
| make_dupli(ctx, ctx->object, &pointcloud->id, parent_transform, component_index++); | make_dupli(ctx, ctx->object, &pointcloud->id, parent_transform, component_index++); | ||||
| } | } | ||||
| } | } | ||||
| const bool creates_duplis_for_components = component_index >= 1; | const bool creates_duplis_for_components = component_index >= 1; | ||||
| const InstancesComponent *component = geometry_set.get_component_for_read<InstancesComponent>(); | const InstancesComponent *component = geometry_set.get_component_for_read<InstancesComponent>(); | ||||
| Show All 16 Lines | static void make_duplis_geometry_set_impl(const DupliContext *ctx, | ||||
| Span<int> instance_reference_handles = component->instance_reference_handles(); | Span<int> instance_reference_handles = component->instance_reference_handles(); | ||||
| Span<int> almost_unique_ids = component->almost_unique_ids(); | Span<int> almost_unique_ids = component->almost_unique_ids(); | ||||
| Span<InstanceReference> references = component->references(); | Span<InstanceReference> references = component->references(); | ||||
| for (int64_t i : instance_offset_matrices.index_range()) { | for (int64_t i : instance_offset_matrices.index_range()) { | ||||
| const InstanceReference &reference = references[instance_reference_handles[i]]; | const InstanceReference &reference = references[instance_reference_handles[i]]; | ||||
| const int id = almost_unique_ids[i]; | const int id = almost_unique_ids[i]; | ||||
| const DupliContext *ctx_for_instance = instances_ctx; | |||||
| /* Set the #preview_instance_index when necessary. */ | |||||
| DupliContext tmp_ctx_for_instance; | |||||
| if (instances_ctx->preview_base_geometry == &geometry_set) { | |||||
| tmp_ctx_for_instance = *instances_ctx; | |||||
| tmp_ctx_for_instance.preview_instance_index = i; | |||||
| ctx_for_instance = &tmp_ctx_for_instance; | |||||
| } | |||||
| switch (reference.type()) { | switch (reference.type()) { | ||||
| case InstanceReference::Type::Object: { | case InstanceReference::Type::Object: { | ||||
| Object &object = reference.object(); | Object &object = reference.object(); | ||||
| float matrix[4][4]; | float matrix[4][4]; | ||||
| mul_m4_m4m4(matrix, parent_transform, instance_offset_matrices[i].values); | mul_m4_m4m4(matrix, parent_transform, instance_offset_matrices[i].values); | ||||
| make_dupli(instances_ctx, &object, matrix, id); | make_dupli(ctx_for_instance, &object, matrix, id); | ||||
| float space_matrix[4][4]; | float space_matrix[4][4]; | ||||
| mul_m4_m4m4(space_matrix, instance_offset_matrices[i].values, object.imat); | mul_m4_m4m4(space_matrix, instance_offset_matrices[i].values, object.imat); | ||||
| mul_m4_m4_pre(space_matrix, parent_transform); | mul_m4_m4_pre(space_matrix, parent_transform); | ||||
| make_recursive_duplis(instances_ctx, &object, space_matrix, id); | make_recursive_duplis(ctx_for_instance, &object, space_matrix, id); | ||||
| break; | break; | ||||
| } | } | ||||
| case InstanceReference::Type::Collection: { | case InstanceReference::Type::Collection: { | ||||
| Collection &collection = reference.collection(); | Collection &collection = reference.collection(); | ||||
| float collection_matrix[4][4]; | float collection_matrix[4][4]; | ||||
| unit_m4(collection_matrix); | unit_m4(collection_matrix); | ||||
| sub_v3_v3(collection_matrix[3], collection.instance_offset); | sub_v3_v3(collection_matrix[3], collection.instance_offset); | ||||
| mul_m4_m4_pre(collection_matrix, instance_offset_matrices[i].values); | mul_m4_m4_pre(collection_matrix, instance_offset_matrices[i].values); | ||||
| mul_m4_m4_pre(collection_matrix, parent_transform); | mul_m4_m4_pre(collection_matrix, parent_transform); | ||||
| DupliContext sub_ctx; | DupliContext sub_ctx; | ||||
| if (!copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) { | if (!copy_dupli_context( | ||||
| &sub_ctx, ctx_for_instance, ctx_for_instance->object, nullptr, id)) { | |||||
| break; | break; | ||||
| } | } | ||||
| eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph); | eEvaluationMode mode = DEG_get_mode(ctx_for_instance->depsgraph); | ||||
| int object_id = 0; | int object_id = 0; | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (&collection, object, mode) { | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (&collection, object, mode) { | ||||
| if (object == instances_ctx->object) { | if (object == ctx_for_instance->object) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| float instance_matrix[4][4]; | float instance_matrix[4][4]; | ||||
| mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat); | mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat); | ||||
| make_dupli(&sub_ctx, object, instance_matrix, object_id++); | make_dupli(&sub_ctx, object, instance_matrix, object_id++); | ||||
| make_recursive_duplis(&sub_ctx, object, collection_matrix, object_id++); | make_recursive_duplis(&sub_ctx, object, collection_matrix, object_id++); | ||||
| } | } | ||||
| FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; | ||||
| break; | break; | ||||
| } | } | ||||
| case InstanceReference::Type::GeometrySet: { | case InstanceReference::Type::GeometrySet: { | ||||
| float new_transform[4][4]; | float new_transform[4][4]; | ||||
| mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values); | mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values); | ||||
| DupliContext sub_ctx; | DupliContext sub_ctx; | ||||
| if (copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) { | if (copy_dupli_context( | ||||
| make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true); | &sub_ctx, ctx_for_instance, ctx_for_instance->object, nullptr, id)) { | ||||
| make_duplis_geometry_set_impl( | |||||
| &sub_ctx, reference.geometry_set(), new_transform, true, false); | |||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case InstanceReference::Type::None: { | case InstanceReference::Type::None: { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void make_duplis_geometry_set(const DupliContext *ctx) | static void make_duplis_geometry_set(const DupliContext *ctx) | ||||
| { | { | ||||
| const GeometrySet *geometry_set = ctx->object->runtime.geometry_set_eval; | const GeometrySet *geometry_set = ctx->object->runtime.geometry_set_eval; | ||||
| make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false); | make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false, false); | ||||
| } | } | ||||
| static const DupliGenerator gen_dupli_geometry_set = { | static const DupliGenerator gen_dupli_geometry_set = { | ||||
| 0, | 0, | ||||
| make_duplis_geometry_set, | make_duplis_geometry_set, | ||||
| }; | }; | ||||
| /** \} */ | /** \} */ | ||||
| ▲ Show 20 Lines • Show All 721 Lines • ▼ Show 20 Lines | ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob) | ||||
| if (ctx.gen) { | if (ctx.gen) { | ||||
| ctx.duplilist = duplilist; | ctx.duplilist = duplilist; | ||||
| ctx.gen->make_duplis(&ctx); | ctx.gen->make_duplis(&ctx); | ||||
| } | } | ||||
| return duplilist; | return duplilist; | ||||
| } | } | ||||
| ListBase *object_duplilist_preview(Depsgraph *depsgraph, | |||||
| Scene *sce, | |||||
| Object *ob_eval, | |||||
| const ViewerPath *viewer_path) | |||||
| { | |||||
| ListBase *duplilist = MEM_cnew<ListBase>("duplilist"); | |||||
| DupliContext ctx; | |||||
| Vector<Object *> instance_stack; | |||||
| instance_stack.append(ob_eval); | |||||
| init_context(&ctx, depsgraph, sce, ob_eval, nullptr, instance_stack); | |||||
| ctx.duplilist = duplilist; | |||||
| Object *ob_orig = DEG_get_original_object(ob_eval); | |||||
| LISTBASE_FOREACH (ModifierData *, md_orig, &ob_orig->modifiers) { | |||||
| if (md_orig->type != eModifierType_Nodes) { | |||||
| continue; | |||||
| } | |||||
| NodesModifierData *nmd_orig = reinterpret_cast<NodesModifierData *>(md_orig); | |||||
| if (nmd_orig->runtime_eval_log == nullptr) { | |||||
| continue; | |||||
| } | |||||
| geo_log::GeoModifierLog *log = static_cast<geo_log::GeoModifierLog *>( | |||||
| nmd_orig->runtime_eval_log); | |||||
| if (const geo_log::ViewerNodeLog *viewer_log = log->find_viewer_node_log_for_path( | |||||
| *viewer_path)) { | |||||
| ctx.preview_base_geometry = &viewer_log->geometry; | |||||
| make_duplis_geometry_set_impl( | |||||
| &ctx, viewer_log->geometry, ob_eval->obmat, true, ob_eval->type == OB_CURVES); | |||||
| } | |||||
| } | |||||
| return duplilist; | |||||
| } | |||||
| void free_object_duplilist(ListBase *lb) | void free_object_duplilist(ListBase *lb) | ||||
| { | { | ||||
| BLI_freelistN(lb); | BLI_freelistN(lb); | ||||
| MEM_freeN(lb); | MEM_freeN(lb); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||