WIP: Mesh: Improve and simplify modifier evaluation logic #119968
|
@ -168,6 +168,13 @@ struct GeometrySet {
|
||||||
return static_cast<Component &>(this->get_component_for_write(Component::static_type));
|
return static_cast<Component &>(this->get_component_for_write(Component::static_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GeometryComponentPtr get_component_ptr(GeometryComponent::Type component_type) const;
|
||||||
|
template<typename Component> ImplicitSharingPtr<Component> get_component_ptr() const
|
||||||
|
{
|
||||||
|
BLI_STATIC_ASSERT(is_geometry_component_v<Component>, "");
|
||||||
|
return static_cast<ImplicitSharingPtr<Component>>(components_(Component::static_type));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the component of the given type. Might return null if the component does not exist yet.
|
* Get the component of the given type. Might return null if the component does not exist yet.
|
||||||
*/
|
*/
|
||||||
|
@ -428,11 +435,11 @@ struct GeometrySet {
|
||||||
* Retrieve the pointer to a component without creating it if it does not exist,
|
* Retrieve the pointer to a component without creating it if it does not exist,
|
||||||
* unlike #get_component_for_write.
|
* unlike #get_component_for_write.
|
||||||
*/
|
*/
|
||||||
GeometryComponent *get_component_ptr(GeometryComponent::Type type);
|
GeometryComponent *get_component_for_write_ptr(GeometryComponent::Type type);
|
||||||
template<typename Component> Component *get_component_ptr()
|
template<typename Component> Component *get_component_for_write_ptr()
|
||||||
{
|
{
|
||||||
BLI_STATIC_ASSERT(is_geometry_component_v<Component>, "");
|
BLI_STATIC_ASSERT(is_geometry_component_v<Component>, "");
|
||||||
return static_cast<Component *>(get_component_ptr(Component::static_type));
|
return static_cast<Component *>(get_component_for_write_ptr(Component::static_type));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -675,6 +682,25 @@ class VolumeComponent : public GeometryComponent {
|
||||||
static constexpr inline GeometryComponent::Type static_type = Type::Volume;
|
static constexpr inline GeometryComponent::Type static_type = Type::Volume;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MeshEditHints {
|
||||||
|
/**
|
||||||
|
* Mesh created by object evaluation. It only has leading deformation modifiers applied.
|
||||||
|
*
|
||||||
|
* \todo This should use a similar system to #CurvesEditHints storing just an array for the
|
||||||
|
* deformed positions, but for historical reasons we copy the whole mesh.
|
||||||
|
*/
|
||||||
|
ImplicitSharingPtr<MeshComponent> mesh_deform;
|
||||||
|
/**
|
||||||
|
* Evaluated mesh cage in edit mode.
|
||||||
|
*
|
||||||
|
* \note When the mesh's `runtime->deformed_only` is true, its vertex positions and other
|
||||||
|
* geometry arrays will be aligned the edit-mesh. Otherwise the #CD_ORIGINDEX custom-data should
|
||||||
|
* be used to map the cage geometry back to the original indices, see
|
||||||
|
* #eModifierTypeFlag_SupportsMapping.
|
||||||
|
*/
|
||||||
|
ImplicitSharingPtr<MeshComponent> mesh_cage;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the original data is in some edit mode, we want to propagate some additional information
|
* When the original data is in some edit mode, we want to propagate some additional information
|
||||||
* through object evaluation. This information can be used by edit modes to support working on
|
* through object evaluation. This information can be used by edit modes to support working on
|
||||||
|
@ -696,6 +722,8 @@ class GeometryComponentEditData final : public GeometryComponent {
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<GreasePencilEditHints> grease_pencil_edit_hints_;
|
std::unique_ptr<GreasePencilEditHints> grease_pencil_edit_hints_;
|
||||||
|
|
||||||
|
std::unique_ptr<MeshEditHints> mesh_edit_hints_;
|
||||||
|
|
||||||
GeometryComponentEditData();
|
GeometryComponentEditData();
|
||||||
|
|
||||||
GeometryComponentPtr copy() const final;
|
GeometryComponentPtr copy() const final;
|
||||||
|
|
|
@ -84,22 +84,6 @@ struct ObjectRuntime {
|
||||||
*/
|
*/
|
||||||
GeometrySet *geometry_set_eval = nullptr;
|
GeometrySet *geometry_set_eval = nullptr;
|
||||||
|
|
||||||
/**
|
|
||||||
* Mesh structure created during object evaluation.
|
|
||||||
* It has deformation only modifiers applied on it.
|
|
||||||
*/
|
|
||||||
Mesh *mesh_deform_eval = nullptr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluated mesh cage in edit mode.
|
|
||||||
*
|
|
||||||
* \note When the mesh's `runtime->deformed_only` is true, the meshes vertex positions
|
|
||||||
* and other geometry arrays will be aligned the edit-mesh. Otherwise the #CD_ORIGINDEX
|
|
||||||
* custom-data should be used to map the cage geometry back to the original indices, see
|
|
||||||
* #eModifierTypeFlag_SupportsMapping.
|
|
||||||
*/
|
|
||||||
Mesh *editmesh_eval_cage = nullptr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Original grease pencil bGPdata pointer, before object->data was changed to point
|
* Original grease pencil bGPdata pointer, before object->data was changed to point
|
||||||
* to gpd_eval.
|
* to gpd_eval.
|
||||||
|
|
|
@ -133,7 +133,7 @@ GeometryComponent &GeometrySet::get_component_for_write(GeometryComponent::Type
|
||||||
return const_cast<GeometryComponent &>(*component_ptr);
|
return const_cast<GeometryComponent &>(*component_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
GeometryComponent *GeometrySet::get_component_ptr(GeometryComponent::Type type)
|
GeometryComponent *GeometrySet::get_component_for_write_ptr(GeometryComponent::Type type)
|
||||||
{
|
{
|
||||||
if (this->has(type)) {
|
if (this->has(type)) {
|
||||||
return &this->get_component_for_write(type);
|
return &this->get_component_for_write(type);
|
||||||
|
@ -529,31 +529,31 @@ void GeometrySet::replace_grease_pencil(GreasePencil *grease_pencil,
|
||||||
|
|
||||||
Mesh *GeometrySet::get_mesh_for_write()
|
Mesh *GeometrySet::get_mesh_for_write()
|
||||||
{
|
{
|
||||||
MeshComponent *component = this->get_component_ptr<MeshComponent>();
|
MeshComponent *component = this->get_component_for_write_ptr<MeshComponent>();
|
||||||
return component == nullptr ? nullptr : component->get_for_write();
|
return component == nullptr ? nullptr : component->get_for_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
PointCloud *GeometrySet::get_pointcloud_for_write()
|
PointCloud *GeometrySet::get_pointcloud_for_write()
|
||||||
{
|
{
|
||||||
PointCloudComponent *component = this->get_component_ptr<PointCloudComponent>();
|
PointCloudComponent *component = this->get_component_for_write_ptr<PointCloudComponent>();
|
||||||
return component == nullptr ? nullptr : component->get_for_write();
|
return component == nullptr ? nullptr : component->get_for_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
Volume *GeometrySet::get_volume_for_write()
|
Volume *GeometrySet::get_volume_for_write()
|
||||||
{
|
{
|
||||||
VolumeComponent *component = this->get_component_ptr<VolumeComponent>();
|
VolumeComponent *component = this->get_component_for_write_ptr<VolumeComponent>();
|
||||||
return component == nullptr ? nullptr : component->get_for_write();
|
return component == nullptr ? nullptr : component->get_for_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
Curves *GeometrySet::get_curves_for_write()
|
Curves *GeometrySet::get_curves_for_write()
|
||||||
{
|
{
|
||||||
CurveComponent *component = this->get_component_ptr<CurveComponent>();
|
CurveComponent *component = this->get_component_for_write_ptr<CurveComponent>();
|
||||||
return component == nullptr ? nullptr : component->get_for_write();
|
return component == nullptr ? nullptr : component->get_for_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
Instances *GeometrySet::get_instances_for_write()
|
Instances *GeometrySet::get_instances_for_write()
|
||||||
{
|
{
|
||||||
InstancesComponent *component = this->get_component_ptr<InstancesComponent>();
|
InstancesComponent *component = this->get_component_for_write_ptr<InstancesComponent>();
|
||||||
return component == nullptr ? nullptr : component->get_for_write();
|
return component == nullptr ? nullptr : component->get_for_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,7 +569,7 @@ CurvesEditHints *GeometrySet::get_curve_edit_hints_for_write()
|
||||||
|
|
||||||
GreasePencil *GeometrySet::get_grease_pencil_for_write()
|
GreasePencil *GeometrySet::get_grease_pencil_for_write()
|
||||||
{
|
{
|
||||||
GreasePencilComponent *component = this->get_component_ptr<GreasePencilComponent>();
|
GreasePencilComponent *component = this->get_component_for_write_ptr<GreasePencilComponent>();
|
||||||
return component == nullptr ? nullptr : component->get_for_write();
|
return component == nullptr ? nullptr : component->get_for_write();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,50 +240,26 @@ static void mesh_calc_finalize(const Mesh &mesh_input, Mesh &mesh_eval)
|
||||||
* The purpose of the geometry set is to store all geometry components that are generated
|
* The purpose of the geometry set is to store all geometry components that are generated
|
||||||
* by modifiers to allow outputting non-mesh data from modifiers.
|
* by modifiers to allow outputting non-mesh data from modifiers.
|
||||||
*/
|
*/
|
||||||
static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
|
static void modifier_modify_mesh_and_geometry_set(ModifierData *md,
|
||||||
const ModifierEvalContext &mectx,
|
const ModifierEvalContext &mectx,
|
||||||
Mesh *input_mesh,
|
GeometrySet &geometry_set)
|
||||||
GeometrySet &geometry_set)
|
|
||||||
{
|
{
|
||||||
Mesh *mesh_output = nullptr;
|
|
||||||
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
|
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
|
||||||
if (mti->modify_geometry_set == nullptr) {
|
if (mti->modify_geometry_set) {
|
||||||
mesh_output = BKE_modifier_modify_mesh(md, &mectx, input_mesh);
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||||
|
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||||
|
}
|
||||||
|
mti->modify_geometry_set(md, &mectx, &geometry_set);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* For performance reasons, this should be called by the modifier and/or nodes themselves at
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||||
* some point. */
|
geometry_set.replace_mesh(BKE_modifier_modify_mesh(md, &mectx, mesh));
|
||||||
BKE_mesh_wrapper_ensure_mdata(input_mesh);
|
|
||||||
|
|
||||||
/* Replace only the mesh rather than the whole component, because the entire #MeshComponent
|
|
||||||
* might have been replaced by data from a different object in the node tree, which means the
|
|
||||||
* component contains vertex group name data for that object that should not be removed. */
|
|
||||||
geometry_set.replace_mesh(input_mesh, GeometryOwnershipType::Editable);
|
|
||||||
|
|
||||||
/* Let the modifier change the geometry set. */
|
|
||||||
mti->modify_geometry_set(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>();
|
|
||||||
if (mesh_component.get() != input_mesh) {
|
|
||||||
/* Make sure the mesh component actually owns the mesh before taking over ownership. */
|
|
||||||
mesh_component.ensure_owns_direct_data();
|
|
||||||
}
|
|
||||||
mesh_output = mesh_component.release();
|
|
||||||
}
|
|
||||||
/* Need to ensure that non-mesh data is also owned by the geometry set. Otherwise it might be
|
|
||||||
* freed while there is still a reference to it in the geometry. */
|
|
||||||
geometry_set.ensure_owns_direct_data();
|
|
||||||
|
|
||||||
/* Return an empty mesh instead of null. */
|
|
||||||
if (mesh_output == nullptr) {
|
|
||||||
mesh_output = BKE_mesh_new_nomain(0, 0, 0, 0);
|
|
||||||
BKE_mesh_copy_parameters_for_eval(mesh_output, input_mesh);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mesh_output;
|
if (!geometry_set.has_mesh()) {
|
||||||
|
geometry_set.replace_mesh(BKE_mesh_new_nomain(0, 0, 0, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_rest_position(Mesh &mesh)
|
static void set_rest_position(Mesh &mesh)
|
||||||
|
@ -305,30 +281,36 @@ static void set_rest_position(Mesh &mesh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mesh_calc_modifiers(Depsgraph &depsgraph,
|
static MeshEditHints &geometry_mesh_edit_hints_ensure(GeometrySet &geometry)
|
||||||
const Scene &scene,
|
|
||||||
Object &ob,
|
|
||||||
const bool use_deform,
|
|
||||||
const bool need_mapping,
|
|
||||||
const CustomData_MeshMasks &dataMask,
|
|
||||||
const bool use_cache,
|
|
||||||
const bool allow_shared_mesh,
|
|
||||||
/* return args */
|
|
||||||
Mesh **r_deform,
|
|
||||||
Mesh **r_final,
|
|
||||||
GeometrySet **r_geometry_set)
|
|
||||||
{
|
{
|
||||||
/* Input mesh shouldn't be modified. */
|
auto &edit_data = geometry.get_component_for_write<GeometryComponentEditData>();
|
||||||
Mesh &mesh_input = *static_cast<Mesh *>(ob.data);
|
if (!edit_data.mesh_edit_hints_) {
|
||||||
/* The final mesh is the result of calculating all enabled modifiers. */
|
edit_data.mesh_edit_hints_ = std::make_unique<MeshEditHints>();
|
||||||
Mesh *mesh = nullptr;
|
}
|
||||||
/* The result of calculating all leading deform modifiers. */
|
return *edit_data.mesh_edit_hints_;
|
||||||
Mesh *mesh_deform = nullptr;
|
}
|
||||||
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
|
|
||||||
GeometrySet geometry_set_final;
|
static void save_deform_mesh(GeometrySet &geometry)
|
||||||
|
{
|
||||||
|
MeshEditHints &edit_data = geometry_mesh_edit_hints_ensure(geometry);
|
||||||
|
edit_data.mesh_deform = geometry.get_component_ptr<MeshComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static GeometrySet mesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
|
const Scene &scene,
|
||||||
|
Object &ob,
|
||||||
|
const bool use_deform,
|
||||||
|
const bool need_mapping,
|
||||||
|
const CustomData_MeshMasks &dataMask,
|
||||||
|
const bool use_cache)
|
||||||
|
{
|
||||||
|
const Mesh &mesh_input = *static_cast<const Mesh *>(ob.data);
|
||||||
|
|
||||||
BLI_assert((mesh_input.id.tag & LIB_TAG_COPIED_ON_EVAL_FINAL_RESULT) == 0);
|
BLI_assert((mesh_input.id.tag & LIB_TAG_COPIED_ON_EVAL_FINAL_RESULT) == 0);
|
||||||
|
|
||||||
|
GeometrySet geometry_set = GeometrySet::from_mesh(const_cast<Mesh *>(&mesh_input),
|
||||||
|
GeometryOwnershipType::ReadOnly);
|
||||||
|
|
||||||
/* Mesh with constructive modifiers but no deformation applied. Tracked
|
/* Mesh with constructive modifiers but no deformation applied. Tracked
|
||||||
* along with final mesh if undeformed / orco coordinates are requested
|
* along with final mesh if undeformed / orco coordinates are requested
|
||||||
* for texturing. */
|
* for texturing. */
|
||||||
|
@ -371,11 +353,9 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
BKE_modifiers_clear_errors(&ob);
|
BKE_modifiers_clear_errors(&ob);
|
||||||
|
|
||||||
if (ob.modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
|
if (ob.modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
|
||||||
if (mesh == nullptr) {
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||||
mesh = BKE_mesh_copy_for_eval(mesh_input);
|
set_rest_position(*mesh);
|
||||||
ASSERT_IS_VALID_MESH(mesh);
|
|
||||||
}
|
}
|
||||||
set_rest_position(*mesh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply all leading deform modifiers. */
|
/* Apply all leading deform modifiers. */
|
||||||
|
@ -389,20 +369,17 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
|
|
||||||
if (mti->type == ModifierTypeType::OnlyDeform && !sculpt_dyntopo) {
|
if (mti->type == ModifierTypeType::OnlyDeform && !sculpt_dyntopo) {
|
||||||
ScopedModifierTimer modifier_timer{*md};
|
ScopedModifierTimer modifier_timer{*md};
|
||||||
if (!mesh) {
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||||
mesh = BKE_mesh_copy_for_eval(mesh_input);
|
if (mti->required_data_mask) {
|
||||||
ASSERT_IS_VALID_MESH(mesh);
|
CustomData_MeshMasks mask{};
|
||||||
}
|
mti->required_data_mask(md, &mask);
|
||||||
|
if (mask.vmask & CD_MASK_ORCO) {
|
||||||
if (mti->required_data_mask) {
|
add_orco_mesh(ob, nullptr, *mesh, nullptr, CD_ORCO);
|
||||||
CustomData_MeshMasks mask{};
|
}
|
||||||
mti->required_data_mask(md, &mask);
|
|
||||||
if (mask.vmask & CD_MASK_ORCO) {
|
|
||||||
add_orco_mesh(ob, nullptr, *mesh, nullptr, CD_ORCO);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
BKE_modifier_deform_verts(md, &mectx, mesh, mesh->vert_positions_for_write());
|
BKE_modifier_deform_verts(md, &mectx, mesh, mesh->vert_positions_for_write());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
|
@ -412,9 +389,7 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
/* Result of all leading deforming modifiers is cached for
|
/* Result of all leading deforming modifiers is cached for
|
||||||
* places that wish to use the original mesh but with deformed
|
* places that wish to use the original mesh but with deformed
|
||||||
* coordinates (like vertex paint). */
|
* coordinates (like vertex paint). */
|
||||||
if (r_deform) {
|
save_deform_mesh(geometry_set);
|
||||||
mesh_deform = BKE_mesh_copy_for_eval(mesh ? *mesh : mesh_input);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply all remaining constructive and deforming modifiers. */
|
/* Apply all remaining constructive and deforming modifiers. */
|
||||||
|
@ -475,42 +450,28 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
ScopedModifierTimer modifier_timer{*md};
|
ScopedModifierTimer modifier_timer{*md};
|
||||||
|
|
||||||
/* Add orco mesh as layer if needed by this modifier. */
|
/* Add orco mesh as layer if needed by this modifier. */
|
||||||
if (mesh && mesh_orco && mti->required_data_mask) {
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||||
CustomData_MeshMasks mask = {0};
|
if (mesh_orco && mti->required_data_mask) {
|
||||||
mti->required_data_mask(md, &mask);
|
CustomData_MeshMasks mask = {0};
|
||||||
if (mask.vmask & CD_MASK_ORCO) {
|
mti->required_data_mask(md, &mask);
|
||||||
add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_ORCO);
|
if (mask.vmask & CD_MASK_ORCO) {
|
||||||
|
add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_ORCO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mti->type == ModifierTypeType::OnlyDeform) {
|
if (mti->type == ModifierTypeType::OnlyDeform) {
|
||||||
if (!mesh) {
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||||
mesh = BKE_mesh_copy_for_eval(mesh_input);
|
BKE_modifier_deform_verts(md, &mectx, mesh, mesh->vert_positions_for_write());
|
||||||
ASSERT_IS_VALID_MESH(mesh);
|
|
||||||
}
|
}
|
||||||
BKE_modifier_deform_verts(md, &mectx, mesh, mesh->vert_positions_for_write());
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bool check_for_needs_mapping = false;
|
|
||||||
if (mesh != nullptr) {
|
|
||||||
if (have_non_onlydeform_modifiers_applied == false) {
|
|
||||||
/* If we only deformed, we won't have initialized #CD_ORIGINDEX.
|
|
||||||
* as this is the only part of the function that initializes mapping. */
|
|
||||||
check_for_needs_mapping = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mesh = BKE_mesh_copy_for_eval(mesh_input);
|
|
||||||
ASSERT_IS_VALID_MESH(mesh);
|
|
||||||
check_for_needs_mapping = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
have_non_onlydeform_modifiers_applied = true;
|
have_non_onlydeform_modifiers_applied = true;
|
||||||
|
|
||||||
/* determine which data layers are needed by following modifiers */
|
/* determine which data layers are needed by following modifiers */
|
||||||
CustomData_MeshMasks nextmask = md_datamask->next ? md_datamask->next->mask : final_datamask;
|
CustomData_MeshMasks nextmask = md_datamask->next ? md_datamask->next->mask : final_datamask;
|
||||||
|
|
||||||
if (check_for_needs_mapping) {
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||||
/* Initialize original indices the first time we evaluate a
|
/* Initialize original indices the first time we evaluate a
|
||||||
* constructive modifier. Modifiers will then do mapping mostly
|
* constructive modifier. Modifiers will then do mapping mostly
|
||||||
* automatic by copying them through CustomData_copy_data along
|
* automatic by copying them through CustomData_copy_data along
|
||||||
|
@ -541,45 +502,35 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
mesh->faces_num,
|
mesh->faces_num,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* set the Mesh to only copy needed data */
|
/* set the Mesh to only copy needed data */
|
||||||
CustomData_MeshMasks mask = md_datamask->mask;
|
CustomData_MeshMasks mask = md_datamask->mask;
|
||||||
/* needMapping check here fixes bug #28112, otherwise it's
|
/* needMapping check here fixes bug #28112, otherwise it's
|
||||||
* possible that it won't be copied */
|
* possible that it won't be copied */
|
||||||
CustomData_MeshMasks_update(&mask, &append_mask);
|
CustomData_MeshMasks_update(&mask, &append_mask);
|
||||||
if (need_mapping) {
|
if (need_mapping) {
|
||||||
mask.vmask |= CD_MASK_ORIGINDEX;
|
mask.vmask |= CD_MASK_ORIGINDEX;
|
||||||
mask.emask |= CD_MASK_ORIGINDEX;
|
mask.emask |= CD_MASK_ORIGINDEX;
|
||||||
mask.pmask |= CD_MASK_ORIGINDEX;
|
mask.pmask |= CD_MASK_ORIGINDEX;
|
||||||
}
|
}
|
||||||
mesh_set_only_copy(mesh, &mask);
|
mesh_set_only_copy(mesh, &mask);
|
||||||
|
|
||||||
/* add cloth rest shape key if needed */
|
/* add cloth rest shape key if needed */
|
||||||
if (mask.vmask & CD_MASK_CLOTH_ORCO) {
|
if (mask.vmask & CD_MASK_CLOTH_ORCO) {
|
||||||
add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_CLOTH_ORCO);
|
add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_CLOTH_ORCO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add an origspace layer if needed */
|
/* add an origspace layer if needed */
|
||||||
if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) {
|
if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) {
|
||||||
if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) {
|
if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) {
|
||||||
CustomData_add_layer(
|
CustomData_add_layer(
|
||||||
&mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num);
|
&mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num);
|
||||||
mesh_init_origspace(*mesh);
|
mesh_init_origspace(*mesh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(md, mectx, mesh, geometry_set_final);
|
modifier_modify_mesh_and_geometry_set(md, mectx, geometry_set);
|
||||||
ASSERT_IS_VALID_MESH(mesh_next);
|
|
||||||
|
|
||||||
if (mesh_next) {
|
|
||||||
/* if the modifier returned a new mesh, release the old one */
|
|
||||||
if (mesh != mesh_next) {
|
|
||||||
BLI_assert(mesh != &mesh_input);
|
|
||||||
BKE_id_free(nullptr, mesh);
|
|
||||||
}
|
|
||||||
mesh = mesh_next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create an orco mesh in parallel */
|
/* create an orco mesh in parallel */
|
||||||
if (nextmask.vmask & CD_MASK_ORCO) {
|
if (nextmask.vmask & CD_MASK_ORCO) {
|
||||||
|
@ -600,17 +551,14 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask);
|
CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask);
|
||||||
mesh_set_only_copy(mesh_orco, &temp_cddata_masks);
|
mesh_set_only_copy(mesh_orco, &temp_cddata_masks);
|
||||||
|
|
||||||
mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco);
|
Mesh *mesh_orco_new = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco);
|
||||||
ASSERT_IS_VALID_MESH(mesh_next);
|
ASSERT_IS_VALID_MESH(mesh_orco_new);
|
||||||
|
if (mesh_orco_new) {
|
||||||
if (mesh_next) {
|
if (mesh_orco != mesh_orco_new) {
|
||||||
/* if the modifier returned a new mesh, release the old one */
|
BLI_assert(mesh_orco != mesh_input);
|
||||||
if (mesh_orco != mesh_next) {
|
|
||||||
BLI_assert(mesh_orco != &mesh_input);
|
|
||||||
BKE_id_free(nullptr, mesh_orco);
|
BKE_id_free(nullptr, mesh_orco);
|
||||||
}
|
}
|
||||||
|
mesh_orco = mesh_orco_new;
|
||||||
mesh_orco = mesh_next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -626,21 +574,23 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
nextmask.pmask |= CD_MASK_ORIGINDEX;
|
nextmask.pmask |= CD_MASK_ORIGINDEX;
|
||||||
mesh_set_only_copy(mesh_orco_cloth, &nextmask);
|
mesh_set_only_copy(mesh_orco_cloth, &nextmask);
|
||||||
|
|
||||||
mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth);
|
Mesh *mesh_orco_cloth_new = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth);
|
||||||
ASSERT_IS_VALID_MESH(mesh_next);
|
ASSERT_IS_VALID_MESH(mesh_orco_cloth_new);
|
||||||
|
if (mesh_orco_cloth_new) {
|
||||||
if (mesh_next) {
|
if (mesh_orco_cloth != mesh_orco_cloth_new) {
|
||||||
/* if the modifier returned a new mesh, release the old one */
|
BLI_assert(mesh_orco != mesh_input);
|
||||||
if (mesh_orco_cloth != mesh_next) {
|
|
||||||
BLI_assert(mesh_orco != &mesh_input);
|
|
||||||
BKE_id_free(nullptr, mesh_orco_cloth);
|
BKE_id_free(nullptr, mesh_orco_cloth);
|
||||||
}
|
}
|
||||||
|
mesh_orco_cloth = mesh_orco_cloth_new;
|
||||||
mesh_orco_cloth = mesh_next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->runtime->deformed_only = false;
|
if (const Mesh *mesh = geometry_set.get_mesh()) {
|
||||||
|
if (mesh->runtime->deformed_only) {
|
||||||
|
Mesh *mesh_mut = geometry_set.get_mesh_for_write();
|
||||||
|
mesh_mut->runtime->deformed_only = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sculpt_mode && md->type == eModifierType_Multires) {
|
if (sculpt_mode && md->type == eModifierType_Multires) {
|
||||||
|
@ -654,32 +604,6 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
BKE_modifier_free_temporary_data(md);
|
BKE_modifier_free_temporary_data(md);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh == nullptr) {
|
|
||||||
if (allow_shared_mesh) {
|
|
||||||
mesh = &mesh_input;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mesh = BKE_mesh_copy_for_eval(mesh_input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Denotes whether the object which the modifier stack came from owns the mesh or whether the
|
|
||||||
* mesh is shared across multiple objects since there are no effective modifiers. */
|
|
||||||
const bool is_own_mesh = (mesh != &mesh_input);
|
|
||||||
|
|
||||||
/* Add orco coordinates to final and deformed mesh if requested. */
|
|
||||||
if (final_datamask.vmask & CD_MASK_ORCO) {
|
|
||||||
/* No need in ORCO layer if the mesh was not deformed or modified: undeformed mesh in this case
|
|
||||||
* matches input mesh. */
|
|
||||||
if (is_own_mesh) {
|
|
||||||
add_orco_mesh(ob, nullptr, *mesh, mesh_orco, CD_ORCO);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mesh_deform) {
|
|
||||||
add_orco_mesh(ob, nullptr, *mesh_deform, nullptr, CD_ORCO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mesh_orco) {
|
if (mesh_orco) {
|
||||||
BKE_id_free(nullptr, mesh_orco);
|
BKE_id_free(nullptr, mesh_orco);
|
||||||
}
|
}
|
||||||
|
@ -689,44 +613,14 @@ static void mesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
|
|
||||||
/* Remove temporary data layer only needed for modifier evaluation.
|
/* Remove temporary data layer only needed for modifier evaluation.
|
||||||
* Save some memory, and ensure GPU subdivision does not need to deal with this. */
|
* Save some memory, and ensure GPU subdivision does not need to deal with this. */
|
||||||
CustomData_free_layers(&mesh->vert_data, CD_CLOTH_ORCO, mesh->verts_num);
|
if (const Mesh *mesh = geometry_set.get_mesh()) {
|
||||||
|
if (CustomData_has_layer(&mesh->vert_data, CD_CLOTH_ORCO)) {
|
||||||
/* Compute normals. */
|
Mesh *mesh_mut = geometry_set.get_mesh_for_write();
|
||||||
if (is_own_mesh) {
|
CustomData_free_layers(&mesh_mut->vert_data, CD_CLOTH_ORCO, mesh_mut->verts_num);
|
||||||
mesh_calc_finalize(mesh_input, *mesh);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
MeshRuntime *runtime = mesh_input.runtime;
|
|
||||||
if (runtime->mesh_eval == nullptr) {
|
|
||||||
std::lock_guard lock{mesh_input.runtime->eval_mutex};
|
|
||||||
if (runtime->mesh_eval == nullptr) {
|
|
||||||
/* Not yet finalized by any instance, do it now
|
|
||||||
* Isolate since computing normals is multithreaded and we are holding a lock. */
|
|
||||||
threading::isolate_task([&] {
|
|
||||||
mesh = BKE_mesh_copy_for_eval(mesh_input);
|
|
||||||
mesh_calc_finalize(mesh_input, *mesh);
|
|
||||||
runtime->mesh_eval = mesh;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Already finalized by another instance, reuse. */
|
|
||||||
mesh = runtime->mesh_eval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Already finalized by another instance, reuse. */
|
|
||||||
mesh = runtime->mesh_eval;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return final mesh */
|
return geometry_set;
|
||||||
*r_final = mesh;
|
|
||||||
if (r_deform) {
|
|
||||||
*r_deform = mesh_deform;
|
|
||||||
}
|
|
||||||
if (r_geometry_set) {
|
|
||||||
*r_geometry_set = new GeometrySet(std::move(geometry_set_final));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool editbmesh_modifier_is_enabled(const Scene *scene,
|
bool editbmesh_modifier_is_enabled(const Scene *scene,
|
||||||
|
@ -766,21 +660,19 @@ static MutableSpan<float3> mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
|
static void save_cage_mesh(GeometrySet &geometry)
|
||||||
const Scene &scene,
|
|
||||||
Object &ob,
|
|
||||||
const CustomData_MeshMasks &dataMask,
|
|
||||||
/* return args */
|
|
||||||
Mesh **r_cage,
|
|
||||||
Mesh **r_final,
|
|
||||||
GeometrySet **r_geometry_set)
|
|
||||||
{
|
{
|
||||||
Mesh &mesh_input = *static_cast<Mesh *>(ob.data);
|
MeshEditHints &edit_data = geometry_mesh_edit_hints_ensure(geometry);
|
||||||
BMEditMesh &em_input = *mesh_input.runtime->edit_mesh;
|
edit_data.mesh_cage = geometry.get_component_ptr<MeshComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
Mesh *mesh_cage = nullptr;
|
static GeometrySet editbmesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
|
const Scene &scene,
|
||||||
GeometrySet geometry_set_final;
|
Object &ob,
|
||||||
|
const CustomData_MeshMasks &dataMask)
|
||||||
|
{
|
||||||
|
const Mesh &mesh_input = *static_cast<const Mesh *>(ob.data);
|
||||||
|
const BMEditMesh &em_input = *mesh_input.runtime->edit_mesh;
|
||||||
|
|
||||||
/* Mesh with constructive modifiers but no deformation applied. Tracked
|
/* Mesh with constructive modifiers but no deformation applied. Tracked
|
||||||
* along with final mesh if undeformed / orco coordinates are requested
|
* along with final mesh if undeformed / orco coordinates are requested
|
||||||
|
@ -810,12 +702,12 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
CDMaskLink *md_datamask = datamasks;
|
CDMaskLink *md_datamask = datamasks;
|
||||||
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH;
|
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH;
|
||||||
|
|
||||||
Mesh *mesh = BKE_mesh_wrapper_from_editmesh(
|
GeometrySet geometry_set = GeometrySet::from_mesh(
|
||||||
mesh_input.runtime->edit_mesh, &final_datamask, &mesh_input);
|
BKE_mesh_wrapper_from_editmesh(mesh_input.runtime->edit_mesh, &final_datamask, &mesh_input));
|
||||||
|
|
||||||
int cageIndex = BKE_modifiers_get_cage_index(&scene, &ob, nullptr, true);
|
int cageIndex = BKE_modifiers_get_cage_index(&scene, &ob, nullptr, true);
|
||||||
if (r_cage && cageIndex == -1) {
|
if (cageIndex == -1) {
|
||||||
mesh_cage = mesh;
|
save_cage_mesh(geometry_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The mesh from edit mode should not have any original index layers already, since those
|
/* The mesh from edit mode should not have any original index layers already, since those
|
||||||
|
@ -828,8 +720,10 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
BKE_modifiers_clear_errors(&ob);
|
BKE_modifiers_clear_errors(&ob);
|
||||||
|
|
||||||
if (ob.modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
|
if (ob.modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
|
||||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||||
set_rest_position(*mesh);
|
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||||
|
set_rest_position(*mesh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool non_deform_modifier_applied = false;
|
bool non_deform_modifier_applied = false;
|
||||||
|
@ -840,6 +734,7 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedModifierTimer modifier_timer{*md};
|
ScopedModifierTimer modifier_timer{*md};
|
||||||
|
Mesh *mesh = geometry_set.get_mesh_for_write();
|
||||||
|
|
||||||
/* Add an orco mesh as layer if needed by this modifier. */
|
/* Add an orco mesh as layer if needed by this modifier. */
|
||||||
if (mesh_orco && mti->required_data_mask) {
|
if (mesh_orco && mti->required_data_mask) {
|
||||||
|
@ -850,21 +745,6 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh == mesh_cage) {
|
|
||||||
/* If the cage mesh has already been assigned, we have passed the cage index in the modifier
|
|
||||||
* list. If the cage and final meshes are still the same, duplicate the final mesh so the
|
|
||||||
* cage mesh isn't modified anymore. */
|
|
||||||
mesh = BKE_mesh_copy_for_eval(*mesh);
|
|
||||||
if (mesh_cage->runtime->edit_mesh) {
|
|
||||||
mesh->runtime->edit_mesh = mesh_cage->runtime->edit_mesh;
|
|
||||||
mesh->runtime->is_original_bmesh = true;
|
|
||||||
if (mesh_cage->runtime->edit_data) {
|
|
||||||
mesh->runtime->edit_data = std::make_unique<EditMeshData>(
|
|
||||||
*mesh_cage->runtime->edit_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mti->type == ModifierTypeType::OnlyDeform) {
|
if (mti->type == ModifierTypeType::OnlyDeform) {
|
||||||
if (mti->deform_verts_EM) {
|
if (mti->deform_verts_EM) {
|
||||||
BKE_modifier_deform_vertsEM(
|
BKE_modifier_deform_vertsEM(
|
||||||
|
@ -914,30 +794,25 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
mask.emask |= CD_MASK_ORIGINDEX;
|
mask.emask |= CD_MASK_ORIGINDEX;
|
||||||
mask.pmask |= CD_MASK_ORIGINDEX;
|
mask.pmask |= CD_MASK_ORIGINDEX;
|
||||||
|
|
||||||
mesh_set_only_copy(mesh, &mask);
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||||
|
mesh_set_only_copy(mesh, &mask);
|
||||||
|
|
||||||
if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) {
|
if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) {
|
||||||
if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) {
|
if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) {
|
||||||
CustomData_add_layer(
|
CustomData_add_layer(
|
||||||
&mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num);
|
&mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num);
|
||||||
mesh_init_origspace(*mesh);
|
mesh_init_origspace(*mesh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mesh->runtime->deformed_only = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(md, mectx, mesh, geometry_set_final);
|
modifier_modify_mesh_and_geometry_set(md, mectx, geometry_set);
|
||||||
ASSERT_IS_VALID_MESH(mesh_next);
|
|
||||||
|
|
||||||
if (mesh_next) {
|
|
||||||
if (mesh != mesh_next) {
|
|
||||||
BKE_id_free(nullptr, mesh);
|
|
||||||
}
|
|
||||||
mesh = mesh_next;
|
|
||||||
}
|
|
||||||
mesh->runtime->deformed_only = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r_cage && i == cageIndex) {
|
if (i == cageIndex) {
|
||||||
mesh_cage = mesh;
|
blender::bke::save_cage_mesh(geometry_set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -945,24 +820,18 @@ static void editbmesh_calc_modifiers(Depsgraph &depsgraph,
|
||||||
|
|
||||||
/* Add orco coordinates to final and deformed mesh if requested. */
|
/* Add orco coordinates to final and deformed mesh if requested. */
|
||||||
if (final_datamask.vmask & CD_MASK_ORCO) {
|
if (final_datamask.vmask & CD_MASK_ORCO) {
|
||||||
/* FIXME(@ideasman42): avoid the need to convert to mesh data just to add an orco layer. */
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
/* FIXME(@ideasman42): avoid the need to convert to mesh data just to add an orco layer. */
|
||||||
|
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||||
add_orco_mesh(ob, &em_input, *mesh, mesh_orco, CD_ORCO);
|
add_orco_mesh(ob, &em_input, *mesh, mesh_orco, CD_ORCO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh_orco) {
|
if (mesh_orco) {
|
||||||
BKE_id_free(nullptr, mesh_orco);
|
BKE_id_free(nullptr, mesh_orco);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return final mesh. */
|
return geometry_set;
|
||||||
*r_final = mesh;
|
|
||||||
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(const Depsgraph &depsgraph,
|
static void mesh_build_extra_data(const Depsgraph &depsgraph,
|
||||||
|
@ -982,53 +851,26 @@ static void mesh_build_data(Depsgraph &depsgraph,
|
||||||
const CustomData_MeshMasks &dataMask,
|
const CustomData_MeshMasks &dataMask,
|
||||||
const bool need_mapping)
|
const bool need_mapping)
|
||||||
{
|
{
|
||||||
#if 0 /* XXX This is already taken care of in #mesh_calc_modifiers... */
|
const Mesh &mesh_input = *static_cast<const Mesh *>(ob.data);
|
||||||
if (need_mapping) {
|
GeometrySet geometry_set = mesh_calc_modifiers(
|
||||||
/* Also add the flag so that it is recorded in lastDataMask. */
|
depsgraph, scene, ob, true, need_mapping, dataMask, true);
|
||||||
dataMask->vmask |= CD_MASK_ORIGINDEX;
|
const Mesh *mesh_eval = geometry_set.get_mesh();
|
||||||
dataMask->emask |= CD_MASK_ORIGINDEX;
|
|
||||||
dataMask->pmask |= CD_MASK_ORIGINDEX;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Mesh *mesh_eval = nullptr, *mesh_deform_eval = nullptr;
|
BKE_object_eval_assign_data(&ob, &const_cast<ID &>(mesh_eval->id), false);
|
||||||
GeometrySet *geometry_set_eval = nullptr;
|
ob.runtime->geometry_set_eval = new GeometrySet(std::move(geometry_set));
|
||||||
mesh_calc_modifiers(depsgraph,
|
|
||||||
scene,
|
|
||||||
ob,
|
|
||||||
true,
|
|
||||||
need_mapping,
|
|
||||||
dataMask,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
&mesh_deform_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.
|
|
||||||
*
|
|
||||||
* Check ownership now, since later on we can not go to a mesh owned by someone else via
|
|
||||||
* object's runtime: this could cause access freed data on depsgraph destruction (mesh who owns
|
|
||||||
* the final result might be freed prior to object). */
|
|
||||||
Mesh *mesh = (Mesh *)ob.data;
|
|
||||||
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 a non-owning component to the geometry set. */
|
|
||||||
MeshComponent &mesh_component = geometry_set_eval->get_component_for_write<MeshComponent>();
|
|
||||||
mesh_component.replace(mesh_eval, GeometryOwnershipType::Editable);
|
|
||||||
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_data_mask = dataMask;
|
||||||
ob.runtime->last_need_mapping = need_mapping;
|
ob.runtime->last_need_mapping = need_mapping;
|
||||||
|
|
||||||
/* Make sure that drivers can target shapekey properties.
|
/* Make sure that drivers can target shapekey properties.
|
||||||
* Note that this causes a potential inconsistency, as the shapekey may have a
|
* Note that this causes a potential inconsistency, as the shapekey may have a
|
||||||
* different topology than the evaluated mesh. */
|
* different topology than the evaluated mesh. */
|
||||||
BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id));
|
if (mesh_input.key) {
|
||||||
mesh_eval->key = mesh->key;
|
BLI_assert(DEG_is_evaluated_id(&mesh_input->key->id));
|
||||||
|
if (mesh_eval != &mesh_input) {
|
||||||
|
const_cast<Mesh *>(mesh_eval)->key = mesh_input.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((ob.mode & OB_MODE_ALL_SCULPT) && ob.sculpt) {
|
if ((ob.mode & OB_MODE_ALL_SCULPT) && ob.sculpt) {
|
||||||
if (DEG_is_active(&depsgraph)) {
|
if (DEG_is_active(&depsgraph)) {
|
||||||
|
@ -1044,43 +886,50 @@ static void editbmesh_build_data(Depsgraph &depsgraph,
|
||||||
Object &obedit,
|
Object &obedit,
|
||||||
CustomData_MeshMasks &dataMask)
|
CustomData_MeshMasks &dataMask)
|
||||||
{
|
{
|
||||||
Mesh *mesh = static_cast<Mesh *>(obedit.data);
|
const Mesh &mesh_input = *static_cast<const Mesh *>(obedit.data);
|
||||||
Mesh *me_cage;
|
|
||||||
Mesh *me_final;
|
|
||||||
GeometrySet *non_mesh_components;
|
|
||||||
|
|
||||||
editbmesh_calc_modifiers(
|
GeometrySet geometry_set = editbmesh_calc_modifiers(depsgraph, scene, obedit, dataMask);
|
||||||
depsgraph, scene, obedit, dataMask, &me_cage, &me_final, &non_mesh_components);
|
|
||||||
|
|
||||||
/* The modifier stack result is expected to share edit mesh pointer with the input.
|
|
||||||
* This is similar `mesh_calc_finalize()`. */
|
|
||||||
BKE_mesh_free_editmesh(me_final);
|
|
||||||
BKE_mesh_free_editmesh(me_cage);
|
|
||||||
me_final->runtime->edit_mesh = me_cage->runtime->edit_mesh = mesh->runtime->edit_mesh;
|
|
||||||
|
|
||||||
/* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object
|
/* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object
|
||||||
* with is in edit mode).
|
* with is in edit mode).
|
||||||
* Convert edit mesh to mesh until the draw manager can draw mesh wrapper which is not in the
|
* Convert edit mesh to mesh until the draw manager can draw mesh wrapper which is not in the
|
||||||
* edit mode. */
|
* edit mode. */
|
||||||
if (!(obedit.mode & OB_MODE_EDIT)) {
|
if (!(obedit.mode & OB_MODE_EDIT)) {
|
||||||
BKE_mesh_wrapper_ensure_mdata(me_final);
|
MeshEditHints &edit_hints =
|
||||||
if (me_final != me_cage) {
|
*geometry_set.get_component_for_write<GeometryComponentEditData>().mesh_edit_hints_;
|
||||||
BKE_mesh_wrapper_ensure_mdata(me_cage);
|
const bool cage_mesh_shared = edit_hints.mesh_cage->get() == geometry_set.get_mesh();
|
||||||
|
Mesh *mesh = geometry_set.get_mesh_for_write();
|
||||||
|
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||||
|
if (cage_mesh_shared) {
|
||||||
|
save_cage_mesh(geometry_set);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (edit_hints.mesh_cage->is_mutable()) {
|
||||||
|
edit_hints.mesh_cage->tag_ensured_mutable();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Mesh *mesh_copy = BKE_mesh_copy_for_eval(*edit_hints.mesh_cage->get());
|
||||||
|
MeshComponent *copy = new MeshComponent(mesh_copy);
|
||||||
|
edit_hints.mesh_cage = ImplicitSharingPtr<MeshComponent>(copy);
|
||||||
|
}
|
||||||
|
Mesh *mesh_cage = const_cast<MeshComponent &>(*edit_hints.mesh_cage).get_for_write();
|
||||||
|
BKE_mesh_wrapper_ensure_mdata(mesh_cage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool is_mesh_eval_owned = (me_final != mesh->runtime->mesh_eval);
|
Mesh *mesh_final = const_cast<Mesh *>(geometry_set.get_mesh());
|
||||||
BKE_object_eval_assign_data(&obedit, &me_final->id, is_mesh_eval_owned);
|
|
||||||
|
BKE_object_eval_assign_data(&obedit, &mesh_final->id, false);
|
||||||
|
|
||||||
/* Make sure that drivers can target shapekey properties.
|
/* Make sure that drivers can target shapekey properties.
|
||||||
* Note that this causes a potential inconsistency, as the shapekey may have a
|
* Note that this causes a potential inconsistency, as the shapekey may have a
|
||||||
* different topology than the evaluated mesh. */
|
* different topology than the evaluated mesh. */
|
||||||
BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id));
|
BLI_assert(mesh_input.key == nullptr || DEG_is_evaluated_id(&mesh_input.key->id));
|
||||||
me_final->key = mesh->key;
|
if (mesh_input.key && !mesh_final->key) {
|
||||||
|
mesh_final->key = mesh_input.key;
|
||||||
|
}
|
||||||
|
|
||||||
obedit.runtime->editmesh_eval_cage = me_cage;
|
obedit.runtime->geometry_set_eval = new GeometrySet(std::move(geometry_set));
|
||||||
|
|
||||||
obedit.runtime->geometry_set_eval = non_mesh_components;
|
|
||||||
|
|
||||||
obedit.runtime->last_data_mask = dataMask;
|
obedit.runtime->last_data_mask = dataMask;
|
||||||
}
|
}
|
||||||
|
@ -1202,7 +1051,7 @@ Mesh *mesh_get_eval_deform(Depsgraph *depsgraph,
|
||||||
CustomData_MeshMasks cddata_masks = *dataMask;
|
CustomData_MeshMasks cddata_masks = *dataMask;
|
||||||
object_get_datamask(*depsgraph, *ob, cddata_masks, &need_mapping);
|
object_get_datamask(*depsgraph, *ob, cddata_masks, &need_mapping);
|
||||||
|
|
||||||
if (!ob->runtime->mesh_deform_eval ||
|
if (!BKE_object_get_mesh_deform_eval(ob) ||
|
||||||
!CustomData_MeshMasks_are_matching(&(ob->runtime->last_data_mask), &cddata_masks) ||
|
!CustomData_MeshMasks_are_matching(&(ob->runtime->last_data_mask), &cddata_masks) ||
|
||||||
(need_mapping && !ob->runtime->last_need_mapping))
|
(need_mapping && !ob->runtime->last_need_mapping))
|
||||||
{
|
{
|
||||||
|
@ -1211,7 +1060,7 @@ Mesh *mesh_get_eval_deform(Depsgraph *depsgraph,
|
||||||
*depsgraph, *scene, *ob, cddata_masks, need_mapping || ob->runtime->last_need_mapping);
|
*depsgraph, *scene, *ob, cddata_masks, need_mapping || ob->runtime->last_need_mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ob->runtime->mesh_deform_eval;
|
return const_cast<Mesh *>(BKE_object_get_mesh_deform_eval(ob));
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
|
Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
|
||||||
|
@ -1219,10 +1068,10 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
|
||||||
Object *ob,
|
Object *ob,
|
||||||
const CustomData_MeshMasks *dataMask)
|
const CustomData_MeshMasks *dataMask)
|
||||||
{
|
{
|
||||||
Mesh *result;
|
GeometrySet geometry_set = mesh_calc_modifiers(
|
||||||
mesh_calc_modifiers(
|
*depsgraph, *scene, *ob, true, false, *dataMask, false);
|
||||||
*depsgraph, *scene, *ob, true, false, *dataMask, false, false, nullptr, &result, nullptr);
|
geometry_set.ensure_owns_direct_data();
|
||||||
return result;
|
return geometry_set.get_component_for_write<MeshComponent>().release();
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
|
Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
|
||||||
|
@ -1230,10 +1079,10 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
|
||||||
Object *ob,
|
Object *ob,
|
||||||
const CustomData_MeshMasks *dataMask)
|
const CustomData_MeshMasks *dataMask)
|
||||||
{
|
{
|
||||||
Mesh *result;
|
GeometrySet geometry_set = mesh_calc_modifiers(
|
||||||
mesh_calc_modifiers(
|
*depsgraph, *scene, *ob, false, false, *dataMask, false);
|
||||||
*depsgraph, *scene, *ob, false, false, *dataMask, false, false, nullptr, &result, nullptr);
|
geometry_set.ensure_owns_direct_data();
|
||||||
return result;
|
return geometry_set.get_component_for_write<MeshComponent>().release();
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
|
Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
|
||||||
|
@ -1241,10 +1090,10 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
|
||||||
Object *ob,
|
Object *ob,
|
||||||
const CustomData_MeshMasks *dataMask)
|
const CustomData_MeshMasks *dataMask)
|
||||||
{
|
{
|
||||||
Mesh *result;
|
GeometrySet geometry_set = mesh_calc_modifiers(
|
||||||
mesh_calc_modifiers(
|
*depsgraph, *scene, *ob, false, false, *dataMask, false);
|
||||||
*depsgraph, *scene, *ob, false, false, *dataMask, false, false, nullptr, &result, nullptr);
|
geometry_set.ensure_owns_direct_data();
|
||||||
return result;
|
return geometry_set.get_component_for_write<MeshComponent>().release();
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *editbmesh_get_eval_cage(Depsgraph *depsgraph,
|
Mesh *editbmesh_get_eval_cage(Depsgraph *depsgraph,
|
||||||
|
@ -1260,13 +1109,13 @@ Mesh *editbmesh_get_eval_cage(Depsgraph *depsgraph,
|
||||||
*/
|
*/
|
||||||
object_get_datamask(*depsgraph, *obedit, cddata_masks, nullptr);
|
object_get_datamask(*depsgraph, *obedit, cddata_masks, nullptr);
|
||||||
|
|
||||||
if (!obedit->runtime->editmesh_eval_cage ||
|
if (!BKE_object_get_editmesh_eval_cage(obedit) ||
|
||||||
!CustomData_MeshMasks_are_matching(&(obedit->runtime->last_data_mask), &cddata_masks))
|
!CustomData_MeshMasks_are_matching(&(obedit->runtime->last_data_mask), &cddata_masks))
|
||||||
{
|
{
|
||||||
editbmesh_build_data(*depsgraph, *scene, *obedit, cddata_masks);
|
editbmesh_build_data(*depsgraph, *scene, *obedit, cddata_masks);
|
||||||
}
|
}
|
||||||
|
|
||||||
return obedit->runtime->editmesh_eval_cage;
|
return const_cast<Mesh *>(BKE_object_get_editmesh_eval_cage(obedit));
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh *editbmesh_get_eval_cage_from_orig(Depsgraph *depsgraph,
|
Mesh *editbmesh_get_eval_cage_from_orig(Depsgraph *depsgraph,
|
||||||
|
|
|
@ -1640,13 +1640,6 @@ void BKE_object_free_derived_caches(Object *ob)
|
||||||
|
|
||||||
object_update_from_subsurf_ccg(ob);
|
object_update_from_subsurf_ccg(ob);
|
||||||
|
|
||||||
if (ob->runtime->editmesh_eval_cage &&
|
|
||||||
ob->runtime->editmesh_eval_cage != reinterpret_cast<Mesh *>(ob->runtime->data_eval))
|
|
||||||
{
|
|
||||||
BKE_id_free(nullptr, ob->runtime->editmesh_eval_cage);
|
|
||||||
}
|
|
||||||
ob->runtime->editmesh_eval_cage = nullptr;
|
|
||||||
|
|
||||||
if (ob->runtime->data_eval != nullptr) {
|
if (ob->runtime->data_eval != nullptr) {
|
||||||
if (ob->runtime->is_data_eval_owned) {
|
if (ob->runtime->is_data_eval_owned) {
|
||||||
ID *data_eval = ob->runtime->data_eval;
|
ID *data_eval = ob->runtime->data_eval;
|
||||||
|
@ -1661,11 +1654,6 @@ void BKE_object_free_derived_caches(Object *ob)
|
||||||
}
|
}
|
||||||
ob->runtime->data_eval = nullptr;
|
ob->runtime->data_eval = nullptr;
|
||||||
}
|
}
|
||||||
if (ob->runtime->mesh_deform_eval != nullptr) {
|
|
||||||
Mesh *mesh_deform_eval = ob->runtime->mesh_deform_eval;
|
|
||||||
BKE_id_free(nullptr, mesh_deform_eval);
|
|
||||||
ob->runtime->mesh_deform_eval = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restore initial pointer for copy-on-evaluation data-blocks, object->data
|
/* Restore initial pointer for copy-on-evaluation data-blocks, object->data
|
||||||
* might be pointing to an evaluated data-block data was just freed above. */
|
* might be pointing to an evaluated data-block data was just freed above. */
|
||||||
|
@ -1686,10 +1674,8 @@ void BKE_object_free_derived_caches(Object *ob)
|
||||||
ob->runtime->gpd_eval = nullptr;
|
ob->runtime->gpd_eval = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ob->runtime->geometry_set_eval != nullptr) {
|
delete ob->runtime->geometry_set_eval;
|
||||||
delete ob->runtime->geometry_set_eval;
|
ob->runtime->geometry_set_eval = nullptr;
|
||||||
ob->runtime->geometry_set_eval = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BKE_object_free_caches(Object *object)
|
void BKE_object_free_caches(Object *object)
|
||||||
|
@ -4221,26 +4207,59 @@ const Mesh *BKE_object_get_editmesh_eval_final(const Object *object)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return reinterpret_cast<Mesh *>(object->runtime->data_eval);
|
return reinterpret_cast<const Mesh *>(object->runtime->data_eval);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Mesh *BKE_object_get_editmesh_eval_cage(const Object *object)
|
const Mesh *BKE_object_get_editmesh_eval_cage(const Object *object)
|
||||||
{
|
{
|
||||||
|
using namespace blender::bke;
|
||||||
BLI_assert(!DEG_is_original_id(&object->id));
|
BLI_assert(!DEG_is_original_id(&object->id));
|
||||||
BLI_assert(object->type == OB_MESH);
|
BLI_assert(object->type == OB_MESH);
|
||||||
|
|
||||||
const Mesh *mesh = static_cast<const Mesh *>(object->data);
|
const Mesh *mesh = static_cast<const Mesh *>(object->data);
|
||||||
BLI_assert(mesh->runtime->edit_mesh != nullptr);
|
BLI_assert(mesh->runtime->edit_mesh != nullptr);
|
||||||
UNUSED_VARS_NDEBUG(mesh);
|
UNUSED_VARS_NDEBUG(mesh);
|
||||||
|
const GeometrySet *geometry_set = object->runtime->geometry_set_eval;
|
||||||
return object->runtime->editmesh_eval_cage;
|
if (!geometry_set) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const auto *component = geometry_set->get_component<GeometryComponentEditData>();
|
||||||
|
if (!component) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const MeshEditHints *edit_hints = component->mesh_edit_hints_.get();
|
||||||
|
if (!edit_hints) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const MeshComponent *mesh_component = edit_hints->mesh_cage.get();
|
||||||
|
if (!mesh_component) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return mesh_component->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Mesh *BKE_object_get_mesh_deform_eval(const Object *object)
|
const Mesh *BKE_object_get_mesh_deform_eval(const Object *object)
|
||||||
{
|
{
|
||||||
|
using namespace blender::bke;
|
||||||
BLI_assert(!DEG_is_original_id(&object->id));
|
BLI_assert(!DEG_is_original_id(&object->id));
|
||||||
BLI_assert(object->type == OB_MESH);
|
BLI_assert(object->type == OB_MESH);
|
||||||
return object->runtime->mesh_deform_eval;
|
const GeometrySet *geometry_set = object->runtime->geometry_set_eval;
|
||||||
|
if (!geometry_set) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const auto *component = geometry_set->get_component<GeometryComponentEditData>();
|
||||||
|
if (!component) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const MeshEditHints *edit_hints = component->mesh_edit_hints_.get();
|
||||||
|
if (!edit_hints) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const MeshComponent *mesh_component = edit_hints->mesh_deform.get();
|
||||||
|
if (!mesh_component) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return mesh_component->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
Lattice *BKE_object_get_lattice(const Object *object)
|
Lattice *BKE_object_get_lattice(const Object *object)
|
||||||
|
@ -4879,7 +4898,6 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int /*flag*/)
|
||||||
blender::bke::ObjectRuntime *runtime = object->runtime;
|
blender::bke::ObjectRuntime *runtime = object->runtime;
|
||||||
runtime->data_eval = nullptr;
|
runtime->data_eval = nullptr;
|
||||||
runtime->gpd_eval = nullptr;
|
runtime->gpd_eval = nullptr;
|
||||||
runtime->mesh_deform_eval = nullptr;
|
|
||||||
runtime->curve_cache = nullptr;
|
runtime->curve_cache = nullptr;
|
||||||
runtime->object_as_temp_mesh = nullptr;
|
runtime->object_as_temp_mesh = nullptr;
|
||||||
runtime->pose_backup = nullptr;
|
runtime->pose_backup = nullptr;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "BLI_implicit_sharing.hh"
|
#include "BLI_implicit_sharing.hh"
|
||||||
#include "BLI_struct_equality_utils.hh"
|
#include "BLI_struct_equality_utils.hh"
|
||||||
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
namespace blender {
|
namespace blender {
|
||||||
|
|
||||||
|
@ -89,6 +90,12 @@ template<typename T> class ImplicitSharingPtr {
|
||||||
return data_ != nullptr;
|
return data_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename U, BLI_ENABLE_IF((std::is_convertible_v<T, U>))>
|
||||||
|
operator ImplicitSharingPtr<U>() const
|
||||||
|
{
|
||||||
|
return ImplicitSharingPtr<U>(static_cast<U *>(data_));
|
||||||
|
}
|
||||||
|
|
||||||
const T *get() const
|
const T *get() const
|
||||||
{
|
{
|
||||||
return data_;
|
return data_;
|
||||||
|
|
Loading…
Reference in New Issue