diff options
30 files changed, 501 insertions, 314 deletions
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 85d886fd850..6fe5ea41fff 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -526,8 +526,13 @@ bool BlenderSync::object_has_particle_hair(BL::Object b_ob) /* Old particle hair. */ void BlenderSync::sync_particle_hair( - Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step) + Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step) { + if (!b_ob_info.is_real_object_data()) { + return; + } + BL::Object b_ob = b_ob_info.real_object; + /* obtain general settings */ if (b_ob.mode() == b_ob.mode_PARTICLE_EDIT || b_ob.mode() == b_ob.mode_EDIT) { return; @@ -788,10 +793,10 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st } /* Hair object. */ -void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step) +void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step) { /* Convert Blender hair to Cycles curves. */ - BL::Hair b_hair(b_ob.data()); + BL::Hair b_hair(b_ob_info.object_data); if (motion) { export_hair_curves_motion(hair, b_hair, motion_step); } @@ -800,16 +805,16 @@ void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motio } } #else -void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step) +void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step) { (void)hair; - (void)b_ob; + (void)b_ob_info; (void)motion; (void)motion_step; } #endif -void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair) +void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair) { /* make a copy of the shaders as the caller in the main thread still need them for syncing the * attributes */ @@ -819,19 +824,19 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *ha new_hair.set_used_shaders(used_shaders); if (view_layer.use_hair) { - if (b_ob.type() == BL::Object::type_HAIR) { + if (b_ob_info.object_data.is_a(&RNA_Hair)) { /* Hair object. */ - sync_hair(&new_hair, b_ob, false); + sync_hair(&new_hair, b_ob_info, false); } else { /* Particle hair. */ bool need_undeformed = new_hair.need_attribute(scene, ATTR_STD_GENERATED); BL::Mesh b_mesh = object_to_mesh( - b_data, b_ob, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE); + b_data, b_ob_info, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE); if (b_mesh) { - sync_particle_hair(&new_hair, b_mesh, b_ob, false); - free_object_to_mesh(b_data, b_ob, b_mesh); + sync_particle_hair(&new_hair, b_mesh, b_ob_info, false); + free_object_to_mesh(b_data, b_ob_info, b_mesh); } } } @@ -859,7 +864,7 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *ha } void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph, - BL::Object b_ob, + BObjectInfo &b_ob_info, Hair *hair, int motion_step) { @@ -869,18 +874,19 @@ void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph, } /* Export deformed coordinates. */ - if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { - if (b_ob.type() == BL::Object::type_HAIR) { + if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) { + if (b_ob_info.object_data.is_a(&RNA_Hair)) { /* Hair object. */ - sync_hair(hair, b_ob, true, motion_step); + sync_hair(hair, b_ob_info, true, motion_step); return; } else { /* Particle hair. */ - BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE); + BL::Mesh b_mesh = object_to_mesh( + b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE); if (b_mesh) { - sync_particle_hair(hair, b_mesh, b_ob, true, motion_step); - free_object_to_mesh(b_data, b_ob, b_mesh); + sync_particle_hair(hair, b_mesh, b_ob_info, true, motion_step); + free_object_to_mesh(b_data, b_ob_info, b_mesh); return; } } diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp index a009018f357..acc089a286c 100644 --- a/intern/cycles/blender/blender_geometry.cpp +++ b/intern/cycles/blender/blender_geometry.cpp @@ -29,13 +29,15 @@ CCL_NAMESPACE_BEGIN -static Geometry::Type determine_geom_type(BL::Object &b_ob, bool use_particle_hair) +static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair) { - if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) { + if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) { return Geometry::HAIR; } - if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) { + if (b_ob_info.object_data.is_a(&RNA_Volume) || + (b_ob_info.object_data == b_ob_info.real_object.data() && + object_fluid_gas_domain_find(b_ob_info.real_object))) { return Geometry::VOLUME; } @@ -71,20 +73,17 @@ array<Node *> BlenderSync::find_used_shaders(BL::Object &b_ob) } Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, - BL::Object &b_ob, - BL::Object &b_ob_instance, + BObjectInfo &b_ob_info, bool object_updated, bool use_particle_hair, TaskPool *task_pool) { /* Test if we can instance or if the object is modified. */ - BL::ID b_ob_data = b_ob.data(); - BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data; - Geometry::Type geom_type = determine_geom_type(b_ob, use_particle_hair); - GeometryKey key(b_key_id.ptr.data, geom_type); + Geometry::Type geom_type = determine_geom_type(b_ob_info, use_particle_hair); + GeometryKey key(b_ob_info.object_data, geom_type); /* Find shader indices. */ - array<Node *> used_shaders = find_used_shaders(b_ob); + array<Node *> used_shaders = find_used_shaders(b_ob_info.iter_object); /* Ensure we only sync instanced geometry once. */ Geometry *geom = geometry_map.find(key); @@ -111,7 +110,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, } else { /* Test if we need to update existing geometry. */ - sync = geometry_map.update(geom, b_key_id); + sync = geometry_map.update(geom, b_ob_info.object_data); } if (!sync) { @@ -144,7 +143,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, geometry_synced.insert(geom); - geom->name = ustring(b_ob_data.name().c_str()); + geom->name = ustring(b_ob_info.object_data.name().c_str()); /* Store the shaders immediately for the object attribute code. */ geom->set_used_shaders(used_shaders); @@ -153,19 +152,19 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, if (progress.get_cancel()) return; - progress.set_sync_status("Synchronizing object", b_ob.name()); + progress.set_sync_status("Synchronizing object", b_ob_info.real_object.name()); if (geom_type == Geometry::HAIR) { Hair *hair = static_cast<Hair *>(geom); - sync_hair(b_depsgraph, b_ob, hair); + sync_hair(b_depsgraph, b_ob_info, hair); } else if (geom_type == Geometry::VOLUME) { Volume *volume = static_cast<Volume *>(geom); - sync_volume(b_ob, volume); + sync_volume(b_ob_info, volume); } else { Mesh *mesh = static_cast<Mesh *>(geom); - sync_mesh(b_depsgraph, b_ob, mesh); + sync_mesh(b_depsgraph, b_ob_info, mesh); } }; @@ -181,7 +180,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, } void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph, - BL::Object &b_ob, + BObjectInfo &b_ob_info, Object *object, float motion_time, bool use_particle_hair, @@ -210,16 +209,17 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph, if (progress.get_cancel()) return; - if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) { + if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) { Hair *hair = static_cast<Hair *>(geom); - sync_hair_motion(b_depsgraph, b_ob, hair, motion_step); + sync_hair_motion(b_depsgraph, b_ob_info, hair, motion_step); } - else if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) { + else if (b_ob_info.object_data.is_a(&RNA_Volume) || + object_fluid_gas_domain_find(b_ob_info.real_object)) { /* No volume motion blur support yet. */ } else { Mesh *mesh = static_cast<Mesh *>(geom); - sync_mesh_motion(b_depsgraph, b_ob, mesh, motion_step); + sync_mesh_motion(b_depsgraph, b_ob_info, mesh, motion_step); } }; diff --git a/intern/cycles/blender/blender_light.cpp b/intern/cycles/blender/blender_light.cpp index 50cd9e3db5c..542028f4b2f 100644 --- a/intern/cycles/blender/blender_light.cpp +++ b/intern/cycles/blender/blender_light.cpp @@ -27,15 +27,14 @@ CCL_NAMESPACE_BEGIN void BlenderSync::sync_light(BL::Object &b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], - BL::Object &b_ob, - BL::Object &b_ob_instance, + BObjectInfo &b_ob_info, int random_id, Transform &tfm, bool *use_portal) { /* test if we need to sync */ - ObjectKey key(b_parent, persistent_id, b_ob_instance, false); - BL::Light b_light(b_ob.data()); + ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, false); + BL::Light b_light(b_ob_info.object_data); Light *light = light_map.find(key); @@ -44,7 +43,7 @@ void BlenderSync::sync_light(BL::Object &b_parent, const bool tfm_updated = (light && light->get_tfm() != tfm); /* Update if either object or light data changed. */ - if (!light_map.add_or_update(&light, b_ob, b_parent, key) && !tfm_updated) { + if (!light_map.add_or_update(&light, b_ob_info.real_object, b_parent, key) && !tfm_updated) { Shader *shader; if (!shader_map.add_or_update(&shader, b_light)) { if (light->get_is_portal()) @@ -139,11 +138,11 @@ void BlenderSync::sync_light(BL::Object &b_parent, light->set_max_bounces(get_int(clight, "max_bounces")); - if (b_ob != b_ob_instance) { + if (b_ob_info.real_object != b_ob_info.iter_object) { light->set_random_id(random_id); } else { - light->set_random_id(hash_uint2(hash_string(b_ob.name().c_str()), 0)); + light->set_random_id(hash_uint2(hash_string(b_ob_info.real_object.name().c_str()), 0)); } if (light->get_light_type() == LIGHT_AREA) @@ -155,7 +154,7 @@ void BlenderSync::sync_light(BL::Object &b_parent, *use_portal = true; /* visibility */ - uint visibility = object_ray_visibility(b_ob); + uint visibility = object_ray_visibility(b_ob_info.real_object); light->set_use_diffuse((visibility & PATH_RAY_DIFFUSE) != 0); light->set_use_glossy((visibility & PATH_RAY_GLOSSY) != 0); light->set_use_transmission((visibility & PATH_RAY_TRANSMIT) != 0); diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index ebba6981502..9bb3447f56b 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -999,12 +999,14 @@ static void create_mesh(Scene *scene, static void create_subd_mesh(Scene *scene, Mesh *mesh, - BL::Object &b_ob, + BObjectInfo &b_ob_info, BL::Mesh &b_mesh, const array<Node *> &used_shaders, float dicing_rate, int max_subdivisions) { + BL::Object b_ob = b_ob_info.real_object; + BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]); bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE; @@ -1043,7 +1045,7 @@ static void create_subd_mesh(Scene *scene, * * NOTE: This code is run prior to object motion blur initialization. so can not access properties * set by `sync_object_motion_init()`. */ -static bool mesh_need_motion_attribute(BL::Object &b_ob, Scene *scene) +static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene) { const Scene::MotionType need_motion = scene->need_motion(); if (need_motion == Scene::MOTION_NONE) { @@ -1060,7 +1062,7 @@ static bool mesh_need_motion_attribute(BL::Object &b_ob, Scene *scene) * - Motion attribute expects non-zero time steps. * * Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */ - PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles"); const bool use_motion = get_boolean(cobject, "use_motion_blur"); if (!use_motion) { return false; @@ -1072,12 +1074,13 @@ static bool mesh_need_motion_attribute(BL::Object &b_ob, Scene *scene) return true; } -static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *mesh) +static void sync_mesh_cached_velocities(BObjectInfo &b_ob_info, Scene *scene, Mesh *mesh) { - if (!mesh_need_motion_attribute(b_ob, scene)) { + if (!mesh_need_motion_attribute(b_ob_info, scene)) { return; } + BL::Object b_ob = b_ob_info.real_object; BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob, true, nullptr); if (!b_mesh_cache) { @@ -1118,12 +1121,16 @@ static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *me } } -static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh) +static void sync_mesh_fluid_motion(BObjectInfo &b_ob_info, Scene *scene, Mesh *mesh) { - if (!mesh_need_motion_attribute(b_ob, scene)) { + if (!b_ob_info.is_real_object_data()) { + return; + } + if (!mesh_need_motion_attribute(b_ob_info, scene)) { return; } + BL::Object b_ob = b_ob_info.real_object; BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob); if (!b_fluid_domain) @@ -1157,7 +1164,7 @@ static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh) } } -void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh) +void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh) { /* make a copy of the shaders as the caller in the main thread still need them for syncing the * attributes */ @@ -1170,20 +1177,21 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me /* Adaptive subdivision setup. Not for baking since that requires * exact mapping to the Blender mesh. */ if (!scene->bake_manager->get_baking()) { - new_mesh.set_subdivision_type(object_subdivision_type(b_ob, preview, experimental)); + new_mesh.set_subdivision_type( + object_subdivision_type(b_ob_info.real_object, preview, experimental)); } /* For some reason, meshes do not need this... */ bool need_undeformed = new_mesh.need_attribute(scene, ATTR_STD_GENERATED); BL::Mesh b_mesh = object_to_mesh( - b_data, b_ob, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type()); + b_data, b_ob_info, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type()); if (b_mesh) { /* Sync mesh itself. */ if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE) create_subd_mesh(scene, &new_mesh, - b_ob, + b_ob_info, b_mesh, new_mesh.get_used_shaders(), dicing_rate, @@ -1191,15 +1199,15 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me else create_mesh(scene, &new_mesh, b_mesh, new_mesh.get_used_shaders(), false); - free_object_to_mesh(b_data, b_ob, b_mesh); + free_object_to_mesh(b_data, b_ob_info, b_mesh); } } /* cached velocities (e.g. from alembic archive) */ - sync_mesh_cached_velocities(b_ob, scene, &new_mesh); + sync_mesh_cached_velocities(b_ob_info, scene, &new_mesh); /* mesh fluid motion mantaflow */ - sync_mesh_fluid_motion(b_ob, scene, &new_mesh); + sync_mesh_fluid_motion(b_ob_info, scene, &new_mesh); /* update original sockets */ @@ -1230,18 +1238,19 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *me } void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph, - BL::Object b_ob, + BObjectInfo &b_ob_info, Mesh *mesh, int motion_step) { /* Fluid motion blur already exported. */ - BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob); + BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob_info.real_object); if (b_fluid_domain) { return; } /* Cached motion blur already exported. */ - BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob, true, nullptr); + BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find( + b_ob_info.real_object, true, nullptr); if (mesh_cache) { return; } @@ -1255,11 +1264,13 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph, /* Skip objects without deforming modifiers. this is not totally reliable, * would need a more extensive check to see which objects are animated. */ BL::Mesh b_mesh(PointerRNA_NULL); - if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { + if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) { /* get derived mesh */ - b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE); + b_mesh = object_to_mesh(b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE); } + const std::string ob_name = b_ob_info.real_object.name(); + /* TODO(sergey): Perform preliminary check for number of vertices. */ if (b_mesh) { /* Export deformed coordinates. */ @@ -1295,17 +1306,17 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph, memcmp(mP, &mesh->get_verts()[0], sizeof(float3) * numverts) == 0) { /* no motion, remove attributes again */ if (b_mesh.vertices.length() != numverts) { - VLOG(1) << "Topology differs, disabling motion blur for object " << b_ob.name(); + VLOG(1) << "Topology differs, disabling motion blur for object " << ob_name; } else { - VLOG(1) << "No actual deformation motion for object " << b_ob.name(); + VLOG(1) << "No actual deformation motion for object " << ob_name; } mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); if (attr_mN) mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL); } else if (motion_step > 0) { - VLOG(1) << "Filling deformation motion for object " << b_ob.name(); + VLOG(1) << "Filling deformation motion for object " << ob_name; /* motion, fill up previous steps that we might have skipped because * they had no motion, but we need them anyway now */ float3 *P = &mesh->get_verts()[0]; @@ -1319,8 +1330,8 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph, } else { if (b_mesh.vertices.length() != numverts) { - VLOG(1) << "Topology differs, discarding motion blur for object " << b_ob.name() - << " at time " << motion_step; + VLOG(1) << "Topology differs, discarding motion blur for object " << ob_name << " at time " + << motion_step; memcpy(mP, &mesh->get_verts()[0], sizeof(float3) * numverts); if (mN != NULL) { memcpy(mN, attr_N->data_float3(), sizeof(float3) * numverts); @@ -1328,7 +1339,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph, } } - free_object_to_mesh(b_data, b_ob, b_mesh); + free_object_to_mesh(b_data, b_ob_info, b_mesh); return; } diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 5d98b61b409..2243baca0b2 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -154,7 +154,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, const bool is_instance = b_instance.is_instance(); BL::Object b_ob = b_instance.object(); BL::Object b_parent = is_instance ? b_instance.parent() : b_instance.object(); - BL::Object b_ob_instance = is_instance ? b_instance.instance_object() : b_ob; + BObjectInfo b_ob_info{b_ob, is_instance ? b_instance.instance_object() : b_ob, b_ob.data()}; const bool motion = motion_time != 0.0f; /*const*/ Transform tfm = get_transform(b_ob.matrix_world()); int *persistent_id = NULL; @@ -178,8 +178,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, { sync_light(b_parent, persistent_id, - b_ob, - b_ob_instance, + b_ob_info, is_instance ? b_instance.random_id() : 0, tfm, use_portal); @@ -231,7 +230,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, TaskPool *object_geom_task_pool = (is_instance) ? NULL : geom_task_pool; /* key to lookup object */ - ObjectKey key(b_parent, persistent_id, b_ob_instance, use_particle_hair); + ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, use_particle_hair); Object *object; /* motion vector case */ @@ -249,12 +248,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, /* mesh deformation */ if (object->get_geometry()) - sync_geometry_motion(b_depsgraph, - b_ob_instance, - object, - motion_time, - use_particle_hair, - object_geom_task_pool); + sync_geometry_motion( + b_depsgraph, b_ob_info, object, motion_time, use_particle_hair, object_geom_task_pool); } return object; @@ -265,15 +260,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, (tfm != object->get_tfm()); /* mesh sync */ - /* b_ob is owned by the iterator and will go out of scope at the end of the block. - * b_ob_instance is the original object and will remain valid for deferred geometry - * sync. */ - Geometry *geometry = sync_geometry(b_depsgraph, - b_ob_instance, - b_ob_instance, - object_updated, - use_particle_hair, - object_geom_task_pool); + Geometry *geometry = sync_geometry( + b_depsgraph, b_ob_info, object_updated, use_particle_hair, object_geom_task_pool); object->set_geometry(geometry); /* special case not tracked by object update flags */ diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 44322dda6b9..76e8f23864c 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -23,6 +23,7 @@ #include "RNA_types.h" #include "blender/blender_id_map.h" +#include "blender/blender_util.h" #include "blender/blender_viewport.h" #include "render/scene.h" @@ -158,18 +159,24 @@ class BlenderSync { bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object); /* Volume */ - void sync_volume(BL::Object &b_ob, Volume *volume); + void sync_volume(BObjectInfo &b_ob_info, Volume *volume); /* Mesh */ - void sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh); - void sync_mesh_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh, int motion_step); + void sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh); + void sync_mesh_motion(BL::Depsgraph b_depsgraph, + BObjectInfo &b_ob_info, + Mesh *mesh, + int motion_step); /* Hair */ - void sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair); - void sync_hair_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair, int motion_step); - void sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step = 0); + void sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair); + void sync_hair_motion(BL::Depsgraph b_depsgraph, + BObjectInfo &b_ob_info, + Hair *hair, + int motion_step); + void sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step = 0); void sync_particle_hair( - Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0); + Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step = 0); bool object_has_particle_hair(BL::Object b_ob); /* Camera */ @@ -178,14 +185,13 @@ class BlenderSync { /* Geometry */ Geometry *sync_geometry(BL::Depsgraph &b_depsgrpah, - BL::Object &b_ob, - BL::Object &b_ob_instance, + BObjectInfo &b_ob_info, bool object_updated, bool use_particle_hair, TaskPool *task_pool); void sync_geometry_motion(BL::Depsgraph &b_depsgraph, - BL::Object &b_ob, + BObjectInfo &b_ob_info, Object *object, float motion_time, bool use_particle_hair, @@ -194,8 +200,7 @@ class BlenderSync { /* Light */ void sync_light(BL::Object &b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], - BL::Object &b_ob, - BL::Object &b_ob_instance, + BObjectInfo &b_ob_info, int random_id, Transform &tfm, bool *use_portal); diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index f6824f31b7b..e69531ea707 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -40,6 +40,28 @@ float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile); CCL_NAMESPACE_BEGIN +struct BObjectInfo { + /* Object directly provided by the depsgraph iterator. This object is only valid during one + * iteration and must not be accessed afterwards. Transforms and visibility should be checked on + * this object. */ + BL::Object iter_object; + + /* This object remains alive even after the object iterator is done. It corresponds to one + * original object. It is the object that owns the object data below. */ + BL::Object real_object; + + /* The object-data referenced by the iter object. This is still valid after the depsgraph + * iterator is done. It might have a different type compared to real_object.data(). */ + BL::ID object_data; + + /* True when the current geometry is the data of the referenced object. False when it is a + * geometry instance that does not have a 1-to-1 relationship with an object. */ + bool is_real_object_data() const + { + return const_cast<BL::Object &>(real_object).data() == object_data; + } +}; + typedef BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType; BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name); @@ -47,7 +69,7 @@ void python_thread_state_save(void **python_thread_state); void python_thread_state_restore(void **python_thread_state); static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/, - BL::Object &object, + BObjectInfo &b_ob_info, BL::Depsgraph & /*depsgraph*/, bool /*calc_undeformed*/, Mesh::SubdivisionType subdivision_type) @@ -69,9 +91,9 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/, #endif BL::Mesh mesh(PointerRNA_NULL); - if (object.type() == BL::Object::type_MESH) { + if (b_ob_info.object_data.is_a(&RNA_Mesh)) { /* TODO: calc_undeformed is not used. */ - mesh = BL::Mesh(object.data()); + mesh = BL::Mesh(b_ob_info.object_data); /* Make a copy to split faces if we use autosmooth, otherwise not needed. * Also in edit mode do we need to make a copy, to ensure data layers like @@ -79,12 +101,15 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/, if (mesh.is_editmode() || (mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) { BL::Depsgraph depsgraph(PointerRNA_NULL); - mesh = object.to_mesh(false, depsgraph); + assert(b_ob_info.is_real_object_data()); + mesh = b_ob_info.real_object.to_mesh(false, depsgraph); } } else { BL::Depsgraph depsgraph(PointerRNA_NULL); - mesh = object.to_mesh(false, depsgraph); + if (b_ob_info.is_real_object_data()) { + mesh = b_ob_info.real_object.to_mesh(false, depsgraph); + } } #if 0 @@ -108,10 +133,14 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/, } static inline void free_object_to_mesh(BL::BlendData & /*data*/, - BL::Object &object, + BObjectInfo &b_ob_info, BL::Mesh &mesh) { + if (!b_ob_info.is_real_object_data()) { + return; + } /* Free mesh if we didn't just use the existing one. */ + BL::Object object = b_ob_info.real_object; if (object.data().ptr.data != mesh.ptr.data) { object.to_mesh_clear(); } @@ -219,9 +248,13 @@ static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bo return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false; } -static inline bool BKE_object_is_deform_modified(BL::Object &self, BL::Scene &scene, bool preview) +static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview) { - return self.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false; + if (!self.is_real_object_data()) { + return false; + } + return self.real_object.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : + false; } static inline int render_resolution_x(BL::RenderSettings &b_render) diff --git a/intern/cycles/blender/blender_volume.cpp b/intern/cycles/blender/blender_volume.cpp index 772ab9f5c8a..0a5b19d7d4c 100644 --- a/intern/cycles/blender/blender_volume.cpp +++ b/intern/cycles/blender/blender_volume.cpp @@ -181,9 +181,12 @@ class BlenderSmokeLoader : public ImageLoader { AttributeStandard attribute; }; -static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Volume *volume, float frame) +static void sync_smoke_volume(Scene *scene, BObjectInfo &b_ob_info, Volume *volume, float frame) { - BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob); + if (!b_ob_info.is_real_object_data()) { + return; + } + BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob_info.real_object); if (!b_domain) { return; } @@ -206,7 +209,7 @@ static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Volume *volume, fl Attribute *attr = volume->attributes.add(std); - ImageLoader *loader = new BlenderSmokeLoader(b_ob, std); + ImageLoader *loader = new BlenderSmokeLoader(b_ob_info.real_object, std); ImageParams params; params.frame = frame; @@ -244,11 +247,11 @@ class BlenderVolumeLoader : public VDBImageLoader { }; static void sync_volume_object(BL::BlendData &b_data, - BL::Object &b_ob, + BObjectInfo &b_ob_info, Scene *scene, Volume *volume) { - BL::Volume b_volume(b_ob.data()); + BL::Volume b_volume(b_ob_info.object_data); b_volume.grids.load(b_data.ptr.data); BL::VolumeRender b_render(b_volume.render()); @@ -296,19 +299,19 @@ static void sync_volume_object(BL::BlendData &b_data, } } -void BlenderSync::sync_volume(BL::Object &b_ob, Volume *volume) +void BlenderSync::sync_volume(BObjectInfo &b_ob_info, Volume *volume) { volume->clear(true); if (view_layer.use_volumes) { - if (b_ob.type() == BL::Object::type_VOLUME) { + if (b_ob_info.object_data.is_a(&RNA_Volume)) { /* Volume object. Create only attributes, bounding mesh will then * be automatically generated later. */ - sync_volume_object(b_data, b_ob, scene, volume); + sync_volume_object(b_data, b_ob_info, scene, volume); } else { /* Smoke domain. */ - sync_smoke_volume(scene, b_ob, volume, b_scene.frame_current()); + sync_smoke_volume(scene, b_ob_info, volume, b_scene.frame_current()); } } diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h index c142d5338d1..989b68f4ccb 100644 --- a/source/blender/blenkernel/BKE_duplilist.h +++ b/source/blender/blenkernel/BKE_duplilist.h @@ -31,6 +31,7 @@ struct ListBase; struct Object; struct ParticleSystem; struct Scene; +struct ID; /* ---------------------------------------------------- */ /* Dupli-Geometry */ @@ -42,7 +43,10 @@ void free_object_duplilist(struct ListBase *lb); typedef struct DupliObject { struct DupliObject *next, *prev; + /* Object whose geometry is instanced. */ struct Object *ob; + /* Data owned by the object above that is instanced. This might not be the same as `ob->data`. */ + struct ID *ob_data; float mat[4][4]; float orco[3], uv[2]; diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h index 5f6a9ec7b91..17cdb9d6a42 100644 --- a/source/blender/blenkernel/BKE_geometry_set.h +++ b/source/blender/blenkernel/BKE_geometry_set.h @@ -41,7 +41,7 @@ typedef enum GeometryComponentType { void BKE_geometry_set_free(struct GeometrySet *geometry_set); -bool BKE_geometry_set_has_instances(const struct GeometrySet *geometry_set); +bool BKE_object_has_geometry_set_instances(const struct Object *ob); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 42e9ce82278..08b6cb951a8 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -283,6 +283,7 @@ struct GeometrySet { void clear(); + bool owns_direct_data() const; void ensure_owns_direct_data(); /* Utility methods for creation. */ @@ -447,12 +448,14 @@ class InstanceReference { None, Object, Collection, + GeometrySet, }; private: Type type_ = Type::None; /** Depending on the type this is either null, an Object or Collection pointer. */ void *data_ = nullptr; + std::unique_ptr<GeometrySet> geometry_set_; public: InstanceReference() = default; @@ -465,6 +468,19 @@ class InstanceReference { { } + InstanceReference(GeometrySet geometry_set) + : type_(Type::GeometrySet), + geometry_set_(std::make_unique<GeometrySet>(std::move(geometry_set))) + { + } + + InstanceReference(const InstanceReference &src) : type_(src.type_), data_(src.data_) + { + if (src.type_ == Type::GeometrySet) { + geometry_set_ = std::make_unique<GeometrySet>(*src.geometry_set_); + } + } + Type type() const { return type_; @@ -482,14 +498,37 @@ class InstanceReference { return *(Collection *)data_; } + const GeometrySet &geometry_set() const + { + BLI_assert(type_ == Type::GeometrySet); + return *geometry_set_; + } + + bool owns_direct_data() const + { + if (type_ != Type::GeometrySet) { + /* The object and collection instances are not direct data. */ + return true; + } + return geometry_set_->owns_direct_data(); + } + + void ensure_owns_direct_data() + { + if (type_ != Type::GeometrySet) { + return; + } + geometry_set_->ensure_owns_direct_data(); + } + uint64_t hash() const { - return blender::get_default_hash(data_); + return blender::get_default_hash_2(data_, geometry_set_.get()); } friend bool operator==(const InstanceReference &a, const InstanceReference &b) { - return a.data_ == b.data_; + return a.data_ == b.data_ && a.geometry_set_.get() == b.geometry_set_.get(); } }; @@ -529,7 +568,7 @@ class InstancesComponent : public GeometryComponent { void reserve(int min_capacity); void resize(int capacity); - int add_reference(InstanceReference reference); + int add_reference(const InstanceReference &reference); void add_instance(int instance_handle, const blender::float4x4 &transform, const int id = -1); blender::Span<InstanceReference> references() const; diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index a823602e341..31b3cd66cbb 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -458,6 +458,8 @@ void BKE_object_modifiers_lib_link_common(void *userData, struct ID **idpoin, int cb_flag); +void BKE_object_replace_data_on_shallow_copy(struct Object *ob, struct ID *new_data); + struct PartEff; struct PartEff *BKE_object_do_version_give_parteff_245(struct Object *ob); diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 3b1b7456162..26ef827d36d 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -122,7 +122,7 @@ blender::Span<int> InstancesComponent::instance_ids() const * If the reference exists already, the handle of the existing reference is returned. * Otherwise a new handle is added. */ -int InstancesComponent::add_reference(InstanceReference reference) +int InstancesComponent::add_reference(const InstanceReference &reference) { return references_.index_of_or_add_as(reference); } @@ -144,14 +144,23 @@ bool InstancesComponent::is_empty() const bool InstancesComponent::owns_direct_data() const { - /* The object and collection instances are not direct data. Instance transforms are direct data - * and are always owned. Therefore, instance components always own all their direct data. */ + for (const InstanceReference &reference : references_) { + if (!reference.owns_direct_data()) { + return false; + } + } return true; } void InstancesComponent::ensure_owns_direct_data() { BLI_assert(this->is_mutable()); + for (const InstanceReference &const_reference : references_) { + /* Const cast is fine because we are not changing anything that would change the hash of the + * reference. */ + InstanceReference &reference = const_cast<InstanceReference &>(const_reference); + reference.ensure_owns_direct_data(); + } } static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids) diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 07b4e715ea9..dafebef1812 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -218,6 +218,16 @@ void GeometrySet::ensure_owns_direct_data() } } +bool GeometrySet::owns_direct_data() const +{ + for (const GeometryComponentPtr &component : components_.values()) { + if (!component->owns_direct_data()) { + return false; + } + } + return true; +} + /* Returns a read-only mesh or null. */ const Mesh *GeometrySet::get_mesh_for_read() const { @@ -376,9 +386,32 @@ void BKE_geometry_set_free(GeometrySet *geometry_set) delete geometry_set; } -bool BKE_geometry_set_has_instances(const GeometrySet *geometry_set) +bool BKE_object_has_geometry_set_instances(const Object *ob) { - return geometry_set->get_component_for_read<InstancesComponent>() != nullptr; + const GeometrySet *geometry_set = ob->runtime.geometry_set_eval; + if (geometry_set == nullptr) { + return false; + } + if (geometry_set->has_instances()) { + return true; + } + const bool has_mesh = geometry_set->has_mesh(); + const bool has_pointcloud = geometry_set->has_pointcloud(); + const bool has_volume = geometry_set->has_volume(); + const bool has_curve = geometry_set->has_curve(); + if (ob->type == OB_MESH) { + return has_pointcloud || has_volume || has_curve; + } + if (ob->type == OB_POINTCLOUD) { + return has_mesh || has_volume || has_curve; + } + if (ob->type == OB_VOLUME) { + return has_mesh || has_pointcloud || has_curve; + } + if (ob->type == OB_CURVE) { + return has_mesh || has_pointcloud || has_volume; + } + return false; } /** \} */ diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 32a65ab47bf..376792b9b96 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -168,6 +168,11 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set, collection, instance_transform, r_sets); break; } + case InstanceReference::Type::GeometrySet: { + const GeometrySet &geometry_set = reference.geometry_set(); + geometry_set_collect_recursive(geometry_set, instance_transform, r_sets); + break; + } case InstanceReference::Type::None: { break; } @@ -290,6 +295,13 @@ static bool instances_attribute_foreach_recursive(const GeometrySet &geometry_se } break; } + case InstanceReference::Type::GeometrySet: { + const GeometrySet &geometry_set = reference.geometry_set(); + if (!instances_attribute_foreach_recursive(geometry_set, callback, limit, count)) { + return false; + } + break; + } case InstanceReference::Type::None: { break; } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 062264c5729..bca1afbf101 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1979,8 +1979,7 @@ int BKE_object_visibility(const Object *ob, const int dag_eval_mode) visibility |= OB_VISIBLE_INSTANCES; } - if (ob->runtime.geometry_set_eval != NULL && - BKE_geometry_set_has_instances(ob->runtime.geometry_set_eval)) { + if (BKE_object_has_geometry_set_instances(ob)) { visibility |= OB_VISIBLE_INSTANCES; } @@ -5737,3 +5736,13 @@ void BKE_object_modifiers_lib_link_common(void *userData, id_us_plus_no_lib(*idpoin); } } + +void BKE_object_replace_data_on_shallow_copy(Object *ob, ID *new_data) +{ + ob->type = BKE_object_obdata_to_type(new_data); + ob->data = new_data; + ob->runtime.geometry_set_eval = NULL; + ob->runtime.data_eval = NULL; + ob->runtime.bb->flag |= BOUNDBOX_DIRTY; + ob->id.py_instance = NULL; +} diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index a46ac4b1175..47d4d03d1e1 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -194,6 +194,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, } dob->ob = ob; + dob->ob_data = (ID *)ob->data; mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat); dob->type = ctx->gen->type; @@ -834,14 +835,59 @@ static const DupliGenerator gen_dupli_verts_pointcloud = { /** \name Instances Geometry Component Implementation * \{ */ -static void make_duplis_instances_component(const DupliContext *ctx) +static void make_duplis_geometry_set_impl(const DupliContext *ctx, + const GeometrySet &geometry_set, + const float parent_transform[4][4], + bool geometry_set_is_instance) { - const InstancesComponent *component = - ctx->object->runtime.geometry_set_eval->get_component_for_read<InstancesComponent>(); + int component_index = 0; + if (ctx->object->type != OB_MESH || geometry_set_is_instance) { + const Mesh *mesh = geometry_set.get_mesh_for_read(); + if (mesh != nullptr) { + DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); + dupli->ob_data = (ID *)mesh; + } + } + if (ctx->object->type != OB_VOLUME || geometry_set_is_instance) { + const Volume *volume = geometry_set.get_volume_for_read(); + if (volume != nullptr) { + DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); + dupli->ob_data = (ID *)volume; + } + } + if (ctx->object->type != OB_CURVE || geometry_set_is_instance) { + const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>(); + if (curve_component != nullptr) { + const Curve *curve = curve_component->get_curve_for_render(); + if (curve != nullptr) { + DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); + dupli->ob_data = (ID *)curve; + } + } + } + if (ctx->object->type != OB_POINTCLOUD || geometry_set_is_instance) { + const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read(); + if (pointcloud != nullptr) { + DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); + dupli->ob_data = (ID *)pointcloud; + } + } + const bool creates_duplis_for_components = component_index >= 1; + + const InstancesComponent *component = geometry_set.get_component_for_read<InstancesComponent>(); if (component == nullptr) { return; } + const DupliContext *instances_ctx = ctx; + /* Create a sub-context if some duplis were created above. This is to avoid dupli id collisions + * between the instances component below and the other components above. */ + DupliContext new_instances_ctx; + if (creates_duplis_for_components) { + copy_dupli_context(&new_instances_ctx, ctx, ctx->object, nullptr, component_index); + instances_ctx = &new_instances_ctx; + } + Span<float4x4> instance_offset_matrices = component->instance_transforms(); Span<int> instance_reference_handles = component->instance_reference_handles(); Span<int> almost_unique_ids = component->almost_unique_ids(); @@ -855,13 +901,13 @@ static void make_duplis_instances_component(const DupliContext *ctx) case InstanceReference::Type::Object: { Object &object = reference.object(); float matrix[4][4]; - mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrices[i].values); - make_dupli(ctx, &object, matrix, id); + mul_m4_m4m4(matrix, parent_transform, instance_offset_matrices[i].values); + make_dupli(instances_ctx, &object, matrix, id); float space_matrix[4][4]; mul_m4_m4m4(space_matrix, instance_offset_matrices[i].values, object.imat); - mul_m4_m4_pre(space_matrix, ctx->object->obmat); - make_recursive_duplis(ctx, &object, space_matrix, id); + mul_m4_m4_pre(space_matrix, parent_transform); + make_recursive_duplis(instances_ctx, &object, space_matrix, id); break; } case InstanceReference::Type::Collection: { @@ -870,23 +916,36 @@ static void make_duplis_instances_component(const DupliContext *ctx) unit_m4(collection_matrix); 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, ctx->object->obmat); + mul_m4_m4_pre(collection_matrix, parent_transform); + + DupliContext sub_ctx; + copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id); - eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); + eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph); + int object_id = 0; FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (&collection, object, mode) { - if (object == ctx->object) { + if (object == instances_ctx->object) { continue; } float instance_matrix[4][4]; mul_m4_m4m4(instance_matrix, collection_matrix, object->obmat); - make_dupli(ctx, object, instance_matrix, id); - make_recursive_duplis(ctx, object, collection_matrix, id); + make_dupli(&sub_ctx, object, instance_matrix, object_id++); + make_recursive_duplis(&sub_ctx, object, collection_matrix, object_id++); } FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; break; } + case InstanceReference::Type::GeometrySet: { + float new_transform[4][4]; + mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values); + + DupliContext sub_ctx; + copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id); + make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true); + break; + } case InstanceReference::Type::None: { break; } @@ -894,9 +953,15 @@ static void make_duplis_instances_component(const DupliContext *ctx) } } -static const DupliGenerator gen_dupli_instances_component = { +static void make_duplis_geometry_set(const DupliContext *ctx) +{ + const GeometrySet *geometry_set = ctx->object->runtime.geometry_set_eval; + make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false); +} + +static const DupliGenerator gen_dupli_geometry_set = { 0, - make_duplis_instances_component, + make_duplis_geometry_set, }; /** \} */ @@ -1567,8 +1632,8 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) } if (ctx->object->runtime.geometry_set_eval != nullptr) { - if (BKE_geometry_set_has_instances(ctx->object->runtime.geometry_set_eval)) { - return &gen_dupli_instances_component; + if (BKE_object_has_geometry_set_instances(ctx->object)) { + return &gen_dupli_geometry_set; } } diff --git a/source/blender/blenlib/BLI_user_counter.hh b/source/blender/blenlib/BLI_user_counter.hh index 3e6d5af4c3f..8cebadeac4c 100644 --- a/source/blender/blenlib/BLI_user_counter.hh +++ b/source/blender/blenlib/BLI_user_counter.hh @@ -84,12 +84,24 @@ template<typename T> class UserCounter { return data_; } + const T *operator->() const + { + BLI_assert(data_ != nullptr); + return data_; + } + T &operator*() { BLI_assert(data_ != nullptr); return *data_; } + const T &operator*() const + { + BLI_assert(data_ != nullptr); + return *data_; + } + operator bool() const { return data_ != nullptr; diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index 17f5ca0db79..e9195a1eb26 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -145,15 +145,7 @@ typedef struct DEGObjectIterData { eEvaluationMode eval_mode; - /* **** Iteration over geometry components **** */ - - /* The object whose components we currently iterate over. - * This might point to #temp_dupli_object. */ - struct Object *geometry_component_owner; - /* Some identifier that is used to determine which geometry component should be returned next. */ - int geometry_component_id; - /* Temporary storage for an object that is created from a component. */ - struct Object temp_geometry_component_object; + struct Object *next_object; /* **** Iteration over dupli-list. *** */ diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 770d9775dd3..7af3d03d478 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -120,130 +120,6 @@ bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, DupliObject return false; } -void deg_iterator_components_init(DEGObjectIterData *data, Object *object) -{ - data->geometry_component_owner = object; - data->geometry_component_id = 0; -} - -/* Returns false when iterator is exhausted. */ -bool deg_iterator_components_step(BLI_Iterator *iter) -{ - DEGObjectIterData *data = (DEGObjectIterData *)iter->data; - if (data->geometry_component_owner == nullptr) { - return false; - } - - if (data->geometry_component_owner->runtime.geometry_set_eval == nullptr) { - /* Return the object itself, if it does not have a geometry set yet. */ - iter->current = data->geometry_component_owner; - data->geometry_component_owner = nullptr; - return true; - } - - GeometrySet *geometry_set = data->geometry_component_owner->runtime.geometry_set_eval; - if (geometry_set == nullptr) { - data->geometry_component_owner = nullptr; - return false; - } - - /* The mesh component. */ - if (data->geometry_component_id == 0) { - data->geometry_component_id++; - - /* Don't use a temporary object for this component, when the owner is a mesh object. */ - if (data->geometry_component_owner->type == OB_MESH) { - iter->current = data->geometry_component_owner; - return true; - } - - const Mesh *mesh = geometry_set->get_mesh_for_read(); - if (mesh != nullptr) { - Object *temp_object = &data->temp_geometry_component_object; - *temp_object = *data->geometry_component_owner; - temp_object->type = OB_MESH; - temp_object->data = (void *)mesh; - temp_object->runtime.select_id = data->geometry_component_owner->runtime.select_id; - iter->current = temp_object; - return true; - } - } - - /* The pointcloud component. */ - if (data->geometry_component_id == 1) { - data->geometry_component_id++; - - /* Don't use a temporary object for this component, when the owner is a point cloud object. */ - if (data->geometry_component_owner->type == OB_POINTCLOUD) { - iter->current = data->geometry_component_owner; - return true; - } - - const PointCloud *pointcloud = geometry_set->get_pointcloud_for_read(); - if (pointcloud != nullptr) { - Object *temp_object = &data->temp_geometry_component_object; - *temp_object = *data->geometry_component_owner; - temp_object->type = OB_POINTCLOUD; - temp_object->data = (void *)pointcloud; - temp_object->runtime.select_id = data->geometry_component_owner->runtime.select_id; - iter->current = temp_object; - return true; - } - } - - /* The volume component. */ - if (data->geometry_component_id == 2) { - data->geometry_component_id++; - - /* Don't use a temporary object for this component, when the owner is a volume object. */ - if (data->geometry_component_owner->type == OB_VOLUME) { - iter->current = data->geometry_component_owner; - return true; - } - - const VolumeComponent *component = geometry_set->get_component_for_read<VolumeComponent>(); - if (component != nullptr) { - const Volume *volume = component->get_for_read(); - - if (volume != nullptr) { - Object *temp_object = &data->temp_geometry_component_object; - *temp_object = *data->geometry_component_owner; - temp_object->type = OB_VOLUME; - temp_object->data = (void *)volume; - temp_object->runtime.select_id = data->geometry_component_owner->runtime.select_id; - iter->current = temp_object; - return true; - } - } - } - - /* The curve component. */ - if (data->geometry_component_id == 3) { - data->geometry_component_id++; - - const CurveComponent *component = geometry_set->get_component_for_read<CurveComponent>(); - if (component != nullptr) { - const Curve *curve = component->get_curve_for_render(); - - if (curve != nullptr) { - Object *temp_object = &data->temp_geometry_component_object; - *temp_object = *data->geometry_component_owner; - temp_object->type = OB_CURVE; - temp_object->data = (void *)curve; - /* Assign data_eval here too, because curve rendering code tries - * to use a mesh if it can find one in this pointer. */ - temp_object->runtime.data_eval = (ID *)curve; - temp_object->runtime.select_id = data->geometry_component_owner->runtime.select_id; - iter->current = temp_object; - return true; - } - } - } - - data->geometry_component_owner = nullptr; - return false; -} - void deg_iterator_duplis_init(DEGObjectIterData *data, Object *object) { if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && @@ -292,6 +168,9 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data) temp_dupli_object->dt = MIN2(temp_dupli_object->dt, dupli_parent->dt); copy_v4_v4(temp_dupli_object->color, dupli_parent->color); temp_dupli_object->runtime.select_id = dupli_parent->runtime.select_id; + if (dob->ob->data != dob->ob_data) { + BKE_object_replace_data_on_shallow_copy(temp_dupli_object, dob->ob_data); + } /* Duplicated elements shouldn't care whether their original collection is visible or not. */ temp_dupli_object->base_flag |= BASE_VISIBLE_DEPSGRAPH; @@ -308,7 +187,7 @@ bool deg_iterator_duplis_step(DEGObjectIterData *data) copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); invert_m4_m4(data->temp_dupli_object.imat, data->temp_dupli_object.obmat); - deg_iterator_components_init(data, &data->temp_dupli_object); + data->next_object = &data->temp_dupli_object; BLI_assert(deg::deg_validate_copy_on_write_datablock(&data->temp_dupli_object.id)); return true; } @@ -377,7 +256,7 @@ bool deg_iterator_objects_step(DEGObjectIterData *data) } if (ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) { - deg_iterator_components_init(data, object); + data->next_object = object; } data->id_node_index++; return true; @@ -400,6 +279,7 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data) return; } + data->next_object = nullptr; data->dupli_parent = nullptr; data->dupli_list = nullptr; data->dupli_object_next = nullptr; @@ -408,8 +288,6 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data) data->id_node_index = 0; data->num_id_nodes = num_id_nodes; data->eval_mode = DEG_get_mode(depsgraph); - data->geometry_component_id = 0; - data->geometry_component_owner = nullptr; deg_invalidate_iterator_work_data(data); DEG_iterator_objects_next(iter); @@ -419,7 +297,9 @@ void DEG_iterator_objects_next(BLI_Iterator *iter) { DEGObjectIterData *data = (DEGObjectIterData *)iter->data; while (true) { - if (deg_iterator_components_step(iter)) { + if (data->next_object != nullptr) { + iter->current = data->next_object; + data->next_object = nullptr; return; } if (deg_iterator_duplis_step(data)) { diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 7f850435a64..9590a4aa7ee 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -632,14 +632,29 @@ void DRW_viewport_request_redraw(void) /** \name Duplis * \{ */ -static void drw_duplidata_load(DupliObject *dupli) +static uint dupli_key_hash(const void *key) { + const DupliKey *dupli_key = (const DupliKey *)key; + return BLI_ghashutil_ptrhash(dupli_key->ob) ^ BLI_ghashutil_ptrhash(dupli_key->ob_data); +} + +static bool dupli_key_cmp(const void *key1, const void *key2) +{ + const DupliKey *dupli_key1 = (const DupliKey *)key1; + const DupliKey *dupli_key2 = (const DupliKey *)key2; + return dupli_key1->ob != dupli_key2->ob || dupli_key1->ob_data != dupli_key2->ob_data; +} + +static void drw_duplidata_load(Object *ob) +{ + DupliObject *dupli = DST.dupli_source; if (dupli == NULL) { return; } - if (DST.dupli_origin != dupli->ob) { + if (DST.dupli_origin != dupli->ob || (DST.dupli_origin_data != dupli->ob_data)) { DST.dupli_origin = dupli->ob; + DST.dupli_origin_data = dupli->ob_data; } else { /* Same data as previous iter. No need to poll ghash for this. */ @@ -647,16 +662,23 @@ static void drw_duplidata_load(DupliObject *dupli) } if (DST.dupli_ghash == NULL) { - DST.dupli_ghash = BLI_ghash_ptr_new(__func__); + DST.dupli_ghash = BLI_ghash_new(dupli_key_hash, dupli_key_cmp, __func__); } + DupliKey *key = MEM_callocN(sizeof(DupliKey), __func__); + key->ob = dupli->ob; + key->ob_data = dupli->ob_data; + void **value; - if (!BLI_ghash_ensure_p(DST.dupli_ghash, DST.dupli_origin, &value)) { + if (!BLI_ghash_ensure_p(DST.dupli_ghash, key, &value)) { *value = MEM_callocN(sizeof(void *) * DST.enabled_engine_count, __func__); /* TODO: Meh a bit out of place but this is nice as it is - * only done once per "original" object. */ - drw_batch_cache_validate(DST.dupli_origin); + * only done once per instance type. */ + drw_batch_cache_validate(ob); + } + else { + MEM_freeN(key); } DST.dupli_datas = *(void ***)value; } @@ -670,12 +692,24 @@ static void duplidata_value_free(void *val) MEM_freeN(val); } +static void duplidata_key_free(void *key) +{ + DupliKey *dupli_key = (DupliKey *)key; + if (dupli_key->ob_data == NULL) { + drw_batch_cache_generate_requested(dupli_key->ob); + } + else { + Object temp_object = *dupli_key->ob; + BKE_object_replace_data_on_shallow_copy(&temp_object, dupli_key->ob_data); + drw_batch_cache_generate_requested(&temp_object); + } + MEM_freeN(key); +} + static void drw_duplidata_free(void) { if (DST.dupli_ghash != NULL) { - BLI_ghash_free(DST.dupli_ghash, - (void (*)(void *key))drw_batch_cache_generate_requested, - duplidata_value_free); + BLI_ghash_free(DST.dupli_ghash, duplidata_key_free, duplidata_value_free); DST.dupli_ghash = NULL; } } @@ -1523,6 +1557,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, /* Only iterate over objects for internal engines or when overlays are enabled */ if (do_populate_loop) { DST.dupli_origin = NULL; + DST.dupli_origin_data = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; @@ -1532,7 +1567,7 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, } DST.dupli_parent = data_.dupli_parent; DST.dupli_source = data_.dupli_object_current; - drw_duplidata_load(DST.dupli_source); + drw_duplidata_load(ob); drw_engines_cache_populate(ob); } DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; @@ -1881,12 +1916,13 @@ void DRW_render_object_iter( draw_ctx->v3d->object_type_exclude_viewport : 0; DST.dupli_origin = NULL; + DST.dupli_origin_data = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) == 0) { DST.dupli_parent = data_.dupli_parent; DST.dupli_source = data_.dupli_object_current; DST.ob_handle = 0; - drw_duplidata_load(DST.dupli_source); + drw_duplidata_load(ob); if (!DST.dupli_source) { drw_batch_cache_validate(ob); @@ -2330,6 +2366,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, v3d->object_type_exclude_select); bool filter_exclude = false; DST.dupli_origin = NULL; + DST.dupli_origin_data = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (depsgraph, ob) { if (!BKE_object_is_visible_in_viewport(v3d, ob)) { continue; @@ -2362,7 +2399,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, DRW_select_load_id(ob->runtime.select_id); DST.dupli_parent = data_.dupli_parent; DST.dupli_source = data_.dupli_object_current; - drw_duplidata_load(DST.dupli_source); + drw_duplidata_load(ob); drw_engines_cache_populate(ob); } } @@ -2475,6 +2512,7 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph, const int object_type_exclude_viewport = v3d->object_type_exclude_viewport; DST.dupli_origin = NULL; + DST.dupli_origin_data = NULL; DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN (DST.draw_ctx.depsgraph, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; @@ -2484,7 +2522,7 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph, } DST.dupli_parent = data_.dupli_parent; DST.dupli_source = data_.dupli_object_current; - drw_duplidata_load(DST.dupli_source); + drw_duplidata_load(ob); drw_engines_cache_populate(ob); } DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index 33e1a57198c..1747ca752c7 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -497,6 +497,11 @@ typedef struct DRWDebugSphere { /* ------------- DRAW MANAGER ------------ */ +typedef struct DupliKey { + struct Object *ob; + struct ID *ob_data; +} DupliKey; + #define DST_MAX_SLOTS 64 /* Cannot be changed without modifying RST.bound_tex_slots */ #define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */ #define STENCIL_UNDEFINED 256 @@ -515,15 +520,19 @@ typedef struct DRWManager { /** Handle of next DRWPass to be allocated. */ DRWResourceHandle pass_handle; - /** Dupli state. NULL if not dupli. */ + /** Dupli object that corresponds to the current object. */ struct DupliObject *dupli_source; + /** Object that created the dupli-list the current object is part of. */ struct Object *dupli_parent; + /** Object referenced by the current dupli object. */ struct Object *dupli_origin; - /** Ghash containing original objects. */ + /** Object-data referenced by the current dupli object. */ + struct ID *dupli_origin_data; + /** Ghash: #DupliKey -> void pointer for each enabled engine. */ struct GHash *dupli_ghash; /** TODO(fclem): try to remove usage of this. */ DRWInstanceData *object_instance_data[MAX_INSTANCE_DATA_SIZE]; - /* Array of dupli_data (one for each enabled engine) to handle duplis. */ + /* Dupli data for the current dupli for each enabled engine. */ void **dupli_datas; /* Rendering state */ diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 2e34284f46e..f95e3f3b236 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2246,13 +2246,6 @@ static bool dupliobject_instancer_cmp(const void *a_, const void *b_) return false; } -static bool object_has_geometry_set_instances(const Object *object_eval) -{ - struct GeometrySet *geometry_set = object_eval->runtime.geometry_set_eval; - - return (geometry_set != NULL) && BKE_geometry_set_has_instances(geometry_set); -} - static void make_object_duplilist_real(bContext *C, Depsgraph *depsgraph, Scene *scene, @@ -2266,7 +2259,8 @@ static void make_object_duplilist_real(bContext *C, Object *object_eval = DEG_get_evaluated_object(depsgraph, base->object); - if (!(base->object->transflag & OB_DUPLI) && !object_has_geometry_set_instances(object_eval)) { + if (!(base->object->transflag & OB_DUPLI) && + !BKE_object_has_geometry_set_instances(object_eval)) { return; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh index 680da9b6794..97170693cb3 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh @@ -35,6 +35,10 @@ struct CollectionCellValue { const Collection *collection; }; +struct GeometrySetCellValue { + const GeometrySet *geometry_set; +}; + /** * This is a type that can hold the value of a cell in a spreadsheet. This type allows us to * decouple the drawing of individual cells from the code that generates the data to be displayed. @@ -53,6 +57,7 @@ class CellValue { std::optional<ColorGeometry4f> value_color; std::optional<ObjectCellValue> value_object; std::optional<CollectionCellValue> value_collection; + std::optional<GeometrySetCellValue> value_geometry_set; }; } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index e38c70afd0f..12815c2c7e9 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -332,6 +332,11 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values( r_cell_value.value_collection = CollectionCellValue{&collection}; break; } + case InstanceReference::Type::GeometrySet: { + const GeometrySet &geometry_set = reference.geometry_set(); + r_cell_value.value_geometry_set = GeometrySetCellValue{&geometry_set}; + break; + } case InstanceReference::Type::None: { break; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc index 8079763a339..1a5eac53306 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc @@ -209,6 +209,23 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { 0, nullptr); } + else if (cell_value.value_geometry_set.has_value()) { + uiDefIconTextBut(params.block, + UI_BTYPE_LABEL, + 0, + ICON_MESH_DATA, + "Geometry", + params.xmin, + params.ymin, + params.width, + params.height, + nullptr, + 0, + 0, + 0, + 0, + nullptr); + } } void draw_float_vector(const CellDrawParams ¶ms, const Span<float> values) const diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index bb04f557074..811f30c96e5 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -501,9 +501,7 @@ static void iter_snap_objects(SnapObjectContext *sctx, } Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object); - if (obj_eval->transflag & OB_DUPLI || - (obj_eval->runtime.geometry_set_eval != NULL && - BKE_geometry_set_has_instances(obj_eval->runtime.geometry_set_eval))) { + if (obj_eval->transflag & OB_DUPLI || BKE_object_has_geometry_set_instances(obj_eval)) { ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval); for (DupliObject *dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { BLI_assert(DEG_is_evaluated_object(dupli_ob->ob)); diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 43dd4b4270e..fd67150811d 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1889,6 +1889,7 @@ typedef enum GeometryNodeTriangulateQuads { typedef enum GeometryNodePointInstanceType { GEO_NODE_POINT_INSTANCE_TYPE_OBJECT = 0, GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION = 1, + GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY = 2, } GeometryNodePointInstanceType; typedef enum GeometryNodePointInstanceFlag { diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 9e24a36915e..a7c0372f309 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -9295,6 +9295,11 @@ static void def_geo_point_instance(StructRNA *srna) ICON_NONE, "Collection", "Instance an entire collection on all points"}, + {GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY, + "GEOMETRY", + ICON_NONE, + "Geometry", + "Copy geometry to all points"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc index 36017307739..9f67638de7e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc @@ -31,13 +31,14 @@ static void geo_node_point_instance_declare(NodeDeclarationBuilder &b) b.add_input<decl::Geometry>("Geometry"); b.add_input<decl::Object>("Object").hide_label(true); b.add_input<decl::Collection>("Collection").hide_label(true); + b.add_input<decl::Geometry>("Instance Geometry"); b.add_input<decl::Int>("Seed").min(-10000).max(10000); b.add_output<decl::Geometry>("Geometry"); } static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "instance_type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); + uiItemR(layout, ptr, "instance_type", 0, nullptr, ICON_NONE); if (RNA_enum_get(ptr, "instance_type") == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION) { uiItemR(layout, ptr, "use_whole_collection", 0, nullptr, ICON_NONE); } @@ -56,7 +57,8 @@ static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node) { bNodeSocket *object_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1); bNodeSocket *collection_socket = object_socket->next; - bNodeSocket *seed_socket = collection_socket->next; + bNodeSocket *instance_geometry_socket = collection_socket->next; + bNodeSocket *seed_socket = instance_geometry_socket->next; NodeGeometryPointInstance *node_storage = (NodeGeometryPointInstance *)node->storage; GeometryNodePointInstanceType type = (GeometryNodePointInstanceType)node_storage->instance_type; @@ -65,6 +67,8 @@ static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node) nodeSetSocketAvailability(object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT); nodeSetSocketAvailability(collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION); + nodeSetSocketAvailability(instance_geometry_socket, + type == GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY); nodeSetSocketAvailability( seed_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION && !use_whole_collection); } @@ -114,6 +118,12 @@ static Vector<InstanceReference> get_instance_references__collection(GeoNodeExec return references; } +static Vector<InstanceReference> get_instance_references__geometry(GeoNodeExecParams ¶ms) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Instance Geometry"); + return {std::move(geometry_set)}; +} + static Vector<InstanceReference> get_instance_references(GeoNodeExecParams ¶ms) { const bNode &node = params.node(); @@ -128,6 +138,9 @@ static Vector<InstanceReference> get_instance_references(GeoNodeExecParams ¶ case GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION: { return get_instance_references__collection(params); } + case GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY: { + return get_instance_references__geometry(params); + } } return {}; } |