diff options
-rw-r--r-- | source/blender/blenkernel/intern/DerivedMesh.cc | 99 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/pointcloud.cc | 32 | ||||
-rw-r--r-- | source/blender/depsgraph/intern/depsgraph_query_iter.cc | 22 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_object_types.h | 11 |
4 files changed, 143 insertions, 21 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 78d4ad6fe19..b8219dcf7ac 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -50,6 +50,7 @@ #include "BKE_colorband.h" #include "BKE_deform.h" #include "BKE_editmesh.h" +#include "BKE_geometry_set.hh" #include "BKE_key.h" #include "BKE_layer.h" #include "BKE_lib_id.h" @@ -881,6 +882,56 @@ void BKE_mesh_wrapper_deferred_finalize(Mesh *me_eval, BLI_assert(me_eval->runtime.wrapper_type_finalize == 0); } +/** + * Modifies the given mesh and geometry set. The geometry set is expect to have NO mesh component. + * After this function ends, the geometry set will still have NO mesh component. Instead, an input + * mesh is passed separately and is returned separately. + * + * The purpose of the geometry set is to store all non-mesh geometry components that are generated + * by modifiers. + */ +static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md, + const ModifierEvalContext &mectx, + Object *ob, + Mesh *input_mesh, + GeometrySet &geometry_set) +{ + Mesh *mesh_output = nullptr; + const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type); + if (mti->modifyGeometrySet == nullptr) { + mesh_output = BKE_modifier_modify_mesh(md, &mectx, input_mesh); + } + else { + /* For performance reasons, this should be called by the modifier and/or nodes themselves at + * some point. */ + BKE_mesh_wrapper_ensure_mdata(input_mesh); + + /* Adds a new mesh component to the geometry set based on the #input_mesh. */ + BLI_assert(!geometry_set.has<MeshComponent>()); + MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); + mesh_component.replace(input_mesh, GeometryOwnershipType::Editable); + mesh_component.copy_vertex_group_names_from_object(*ob); + + /* Let the modifier change the geometry set. */ + mti->modifyGeometrySet(md, &mectx, &geometry_set); + + /* Release the mesh from the geometry set again. */ + if (geometry_set.has<MeshComponent>()) { + MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); + mesh_output = mesh_component.release(); + geometry_set.remove<MeshComponent>(); + } + + /* Return an empty mesh instead of null. */ + if (mesh_output == nullptr) { + mesh_output = BKE_mesh_new_nomain(0, 0, 0, 0, 0); + BKE_mesh_copy_settings(mesh_output, input_mesh); + } + } + + return mesh_output; +} + static void mesh_calc_modifiers(struct Depsgraph *depsgraph, Scene *scene, Object *ob, @@ -892,7 +943,8 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, const bool allow_shared_mesh, /* return args */ Mesh **r_deform, - Mesh **r_final) + Mesh **r_final, + GeometrySet **r_geometry_set) { /* Input and final mesh. Final mesh is only created the moment the first * constructive modifier is executed, or a deform modifier needs normals @@ -900,6 +952,8 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, Mesh *mesh_input = (Mesh *)ob->data; Mesh *mesh_final = nullptr; Mesh *mesh_deform = nullptr; + /* This geometry set contains the non-mesh data that might be generated by modifiers. */ + GeometrySet geometry_set_final; BLI_assert((mesh_input->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0); /* Deformed vertex locations array. Deform only modifier need this type of @@ -1197,7 +1251,8 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, } } - Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final); + Mesh *mesh_next = modifier_modify_mesh_and_geometry_set( + md, mectx, ob, mesh_final, geometry_set_final); ASSERT_IS_VALID_MESH(mesh_next); if (mesh_next) { @@ -1375,6 +1430,9 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, if (r_deform) { *r_deform = mesh_deform; } + if (r_geometry_set) { + *r_geometry_set = new GeometrySet(std::move(geometry_set_final)); + } } float (*editbmesh_vert_coords_alloc(BMEditMesh *em, int *r_vert_len))[3] @@ -1483,7 +1541,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, const CustomData_MeshMasks *dataMask, /* return args */ Mesh **r_cage, - Mesh **r_final) + Mesh **r_final, + GeometrySet **r_geometry_set) { /* Input and final mesh. Final mesh is only created the moment the first * constructive modifier is executed, or a deform modifier needs normals @@ -1491,6 +1550,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, Mesh *mesh_input = (Mesh *)ob->data; Mesh *mesh_final = nullptr; Mesh *mesh_cage = nullptr; + /* This geometry set contains the non-mesh data that might be generated by modifiers. */ + GeometrySet geometry_set_final; /* Deformed vertex locations array. Deform only modifier need this type of * float array rather than MVert*. Tracked along with mesh_final as an @@ -1655,7 +1716,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, } } - Mesh *mesh_next = BKE_modifier_modify_mesh(md, &mectx, mesh_final); + Mesh *mesh_next = modifier_modify_mesh_and_geometry_set( + md, mectx, ob, mesh_final, geometry_set_final); ASSERT_IS_VALID_MESH(mesh_next); if (mesh_next) { @@ -1757,6 +1819,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (r_cage) { *r_cage = mesh_cage; } + if (r_geometry_set) { + *r_geometry_set = new GeometrySet(std::move(geometry_set_final)); + } } static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob, Mesh *mesh_eval) @@ -1803,6 +1868,7 @@ static void mesh_build_data(struct Depsgraph *depsgraph, #endif Mesh *mesh_eval = nullptr, *mesh_deform_eval = nullptr; + GeometrySet *geometry_set_eval = nullptr; mesh_calc_modifiers(depsgraph, scene, ob, @@ -1813,7 +1879,8 @@ static void mesh_build_data(struct Depsgraph *depsgraph, true, true, &mesh_deform_eval, - &mesh_eval); + &mesh_eval, + &geometry_set_eval); /* The modifier stack evaluation is storing result in mesh->runtime.mesh_eval, but this result * is not guaranteed to be owned by object. @@ -1825,6 +1892,12 @@ static void mesh_build_data(struct Depsgraph *depsgraph, const bool is_mesh_eval_owned = (mesh_eval != mesh->runtime.mesh_eval); BKE_object_eval_assign_data(ob, &mesh_eval->id, is_mesh_eval_owned); + /* Add the final mesh as read-only non-owning component to the geometry set. */ + BLI_assert(!geometry_set_eval->has<MeshComponent>()); + MeshComponent &mesh_component = geometry_set_eval->get_component_for_write<MeshComponent>(); + mesh_component.replace(mesh_eval, GeometryOwnershipType::ReadOnly); + ob->runtime.geometry_set_eval = geometry_set_eval; + ob->runtime.mesh_deform_eval = mesh_deform_eval; ob->runtime.last_data_mask = *dataMask; ob->runtime.last_need_mapping = need_mapping; @@ -1864,11 +1937,14 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph, Mesh *me_cage; Mesh *me_final; + GeometrySet *non_mesh_components; - editbmesh_calc_modifiers(depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final); + editbmesh_calc_modifiers( + depsgraph, scene, obedit, em, dataMask, &me_cage, &me_final, &non_mesh_components); em->mesh_eval_final = me_final; em->mesh_eval_cage = me_cage; + obedit->runtime.geometry_set_eval = non_mesh_components; BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final); @@ -2020,7 +2096,8 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph, { Mesh *final; - mesh_calc_modifiers(depsgraph, scene, ob, 1, false, dataMask, -1, false, false, nullptr, &final); + mesh_calc_modifiers( + depsgraph, scene, ob, 1, false, dataMask, -1, false, false, nullptr, &final, nullptr); return final; } @@ -2034,7 +2111,7 @@ Mesh *mesh_create_eval_final_index_render(Depsgraph *depsgraph, Mesh *final; mesh_calc_modifiers( - depsgraph, scene, ob, 1, false, dataMask, index, false, false, nullptr, &final); + depsgraph, scene, ob, 1, false, dataMask, index, false, false, nullptr, &final, nullptr); return final; } @@ -2046,7 +2123,8 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph, { Mesh *final; - mesh_calc_modifiers(depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final); + mesh_calc_modifiers( + depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final, nullptr); return final; } @@ -2058,7 +2136,8 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph, { Mesh *final; - mesh_calc_modifiers(depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final); + mesh_calc_modifiers( + depsgraph, scene, ob, 0, false, dataMask, -1, false, false, nullptr, &final, nullptr); return final; } diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index b4a9ad73048..7bd14e80333 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -371,6 +371,25 @@ static void pointcloud_evaluate_modifiers(struct Depsgraph *depsgraph, } } +static PointCloud *take_pointcloud_ownership_from_geometry_set(GeometrySet &geometry_set) +{ + if (!geometry_set.has<PointCloudComponent>()) { + return nullptr; + } + PointCloudComponent &pointcloud_component = + geometry_set.get_component_for_write<PointCloudComponent>(); + PointCloud *pointcloud = pointcloud_component.release(); + if (pointcloud != nullptr) { + /* Add back, but as read-only non-owning component. */ + pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly); + } + else { + /* The component was empty, we can also remove it. */ + geometry_set.remove<PointCloudComponent>(); + } + return pointcloud; +} + void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object) { /* Free any evaluated data and restore original data. */ @@ -382,10 +401,17 @@ void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, struct Scene *scene GeometryOwnershipType::ReadOnly); pointcloud_evaluate_modifiers(depsgraph, scene, object, geometry_set); + PointCloud *pointcloud_eval = take_pointcloud_ownership_from_geometry_set(geometry_set); + + /* If the geometry set did not contain a point cloud, we still create an empty one. */ + if (pointcloud_eval == nullptr) { + pointcloud_eval = BKE_pointcloud_new_nomain(0); + } + /* Assign evaluated object. */ - PointCloud *dummy_pointcloud = BKE_pointcloud_new_nomain(0); - BKE_object_eval_assign_data(object, &dummy_pointcloud->id, true); - object->runtime.geometry_set_eval = new GeometrySet(geometry_set); + const bool eval_is_owned = pointcloud_eval != pointcloud; + BKE_object_eval_assign_data(object, &pointcloud_eval->id, eval_is_owned); + object->runtime.geometry_set_eval = new GeometrySet(std::move(geometry_set)); } /* Draw Cache */ diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index b92bf475f49..e472d82f2ee 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -136,8 +136,8 @@ bool deg_iterator_components_step(BLI_Iterator *iter) return false; } - if (data->geometry_component_owner->type != OB_POINTCLOUD) { - /* Only point clouds support multiple geometry components currently. */ + 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; @@ -149,10 +149,16 @@ bool deg_iterator_components_step(BLI_Iterator *iter) return false; } + /* The mesh component. */ if (data->geometry_component_id == 0) { data->geometry_component_id++; - /* The mesh component. */ + /* 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; @@ -164,10 +170,17 @@ bool deg_iterator_components_step(BLI_Iterator *iter) return true; } } + + /* The pointcloud component. */ if (data->geometry_component_id == 1) { data->geometry_component_id++; - /* The pointcloud component. */ + /* 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; @@ -179,6 +192,7 @@ bool deg_iterator_components_step(BLI_Iterator *iter) return true; } } + data->geometry_component_owner = nullptr; return false; } diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 71f67d8a3b4..0a3a2cd0b64 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -150,14 +150,17 @@ typedef struct Object_Runtime { */ struct ID *data_orig; /** - * Object data structure created during object evaluation. - * It has all modifiers applied. + * Object data structure created during object evaluation. It has all modifiers applied. + * The type is determined by the type of the original object. For example, for mesh and curve + * objects, this is a mesh. For a volume object, this is a volume. */ struct ID *data_eval; /** - * Some objects support evaluating to a geometry set instead of a single ID. In those cases the - * evaluated geometry will be stored here instead of in #data_eval. + * Objects can evaluate to a geometry set instead of a single ID. In those cases, the evaluated + * geometry set will be stored here. An ID of the correct type is still stored in #data_eval. + * #geometry_set_eval might reference the ID pointed to by #data_eval as well, but does not own + * the data. */ struct GeometrySet *geometry_set_eval; |