WIP: Mesh: Improve and simplify modifier evaluation logic #119968
|
@ -681,7 +681,7 @@ void BKE_armature_deform_coords_with_editmesh(const Object *ob_arm,
|
|||
int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
BMEditMesh *em_target);
|
||||
const BMEditMesh *em_target);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -423,7 +423,7 @@ void BKE_curve_deform_coords_with_editmesh(const Object *ob_curve,
|
|||
int defgrp_index,
|
||||
short flag,
|
||||
short defaxis,
|
||||
BMEditMesh *em_target);
|
||||
const BMEditMesh *em_target);
|
||||
|
||||
/**
|
||||
* \param orco: Input vec and orco = local coord in curve space
|
||||
|
|
|
@ -40,6 +40,7 @@ struct Scene;
|
|||
* #Mesh.runtime.edit_mesh stores a pointer to this structure.
|
||||
*/
|
||||
struct BMEditMesh {
|
||||
/* Always owned by an original mesh in edit mode. */
|
||||
BMesh *bm;
|
||||
|
||||
/**
|
||||
|
|
|
@ -168,6 +168,13 @@ struct GeometrySet {
|
|||
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.
|
||||
*/
|
||||
|
@ -428,11 +435,11 @@ struct GeometrySet {
|
|||
* Retrieve the pointer to a component without creating it if it does not exist,
|
||||
* unlike #get_component_for_write.
|
||||
*/
|
||||
GeometryComponent *get_component_ptr(GeometryComponent::Type type);
|
||||
template<typename Component> Component *get_component_ptr()
|
||||
GeometryComponent *get_component_for_write_ptr(GeometryComponent::Type type);
|
||||
template<typename Component> Component *get_component_for_write_ptr()
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
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
|
||||
* 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<MeshEditHints> mesh_edit_hints_;
|
||||
|
||||
GeometryComponentEditData();
|
||||
|
||||
GeometryComponentPtr copy() const final;
|
||||
|
|
|
@ -106,6 +106,6 @@ void BKE_lattice_deform_coords_with_editmesh(const Object *ob_lattice,
|
|||
short flag,
|
||||
const char *defgrp_name,
|
||||
float fac,
|
||||
BMEditMesh *em_target);
|
||||
const BMEditMesh *em_target);
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -223,7 +223,7 @@ struct ModifierTypeInfo {
|
|||
*/
|
||||
void (*deform_verts_EM)(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
BMEditMesh *em,
|
||||
const BMEditMesh *em,
|
||||
Mesh *mesh,
|
||||
blender::MutableSpan<blender::float3> positions);
|
||||
|
||||
|
@ -578,7 +578,7 @@ void BKE_modifier_deform_verts(ModifierData *md,
|
|||
|
||||
void BKE_modifier_deform_vertsEM(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
BMEditMesh *em,
|
||||
const BMEditMesh *em,
|
||||
Mesh *mesh,
|
||||
blender::MutableSpan<blender::float3> positions);
|
||||
|
||||
|
|
|
@ -84,22 +84,6 @@ struct ObjectRuntime {
|
|||
*/
|
||||
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
|
||||
* to gpd_eval.
|
||||
|
|
|
@ -88,8 +88,12 @@ using blender::bke::MeshComponent;
|
|||
# define ASSERT_IS_VALID_MESH(mesh)
|
||||
#endif
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
static void mesh_init_origspace(Mesh *mesh);
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
static float *dm_getVertArray(DerivedMesh *dm)
|
||||
|
@ -237,7 +241,7 @@ void DM_release(DerivedMesh *dm)
|
|||
MEM_SAFE_FREE(dm->face_offsets);
|
||||
}
|
||||
|
||||
void BKE_mesh_runtime_eval_to_meshkey(Mesh *me_deformed, Mesh *mesh, KeyBlock *kb)
|
||||
void BKE_mesh_runtime_eval_to_meshkey(const Mesh *me_deformed, Mesh *mesh, KeyBlock *kb)
|
||||
{
|
||||
/* Just a shallow wrapper around #BKE_keyblock_convert_from_mesh,
|
||||
* that ensures both evaluated mesh and original one has same number of vertices. */
|
||||
|
@ -463,6 +467,8 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
|
|||
mesh_eval->runtime->edit_mesh = mesh_input->runtime->edit_mesh;
|
||||
}
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
/**
|
||||
* Modifies the given mesh and geometry set. The mesh is not passed as part of the mesh component
|
||||
* in the \a geometry_set input, it is only passed in \a input_mesh and returned in the return
|
||||
|
@ -471,56 +477,30 @@ 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
|
||||
* by modifiers to allow outputting non-mesh data from modifiers.
|
||||
*/
|
||||
static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
|
||||
const ModifierEvalContext &mectx,
|
||||
Mesh *input_mesh,
|
||||
GeometrySet &geometry_set)
|
||||
static void modifier_modify_mesh_and_geometry_set(ModifierData *md,
|
||||
const ModifierEvalContext &mectx,
|
||||
GeometrySet &geometry_set)
|
||||
{
|
||||
Mesh *mesh_output = nullptr;
|
||||
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
|
||||
if (mti->modify_geometry_set == nullptr) {
|
||||
mesh_output = BKE_modifier_modify_mesh(md, &mectx, input_mesh);
|
||||
if (mti->modify_geometry_set) {
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||
}
|
||||
mti->modify_geometry_set(md, &mectx, &geometry_set);
|
||||
}
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
Mesh *new_mesh = BKE_modifier_modify_mesh(md, &mectx, geometry_set.get_mesh_for_write());
|
||||
geometry_set.replace_mesh(new_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)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::bke;
|
||||
BKE_mesh_wrapper_ensure_mdata(&mesh);
|
||||
MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
const AttributeReader positions = attributes.lookup<float3>("position");
|
||||
attributes.remove("rest_position");
|
||||
|
@ -538,31 +518,38 @@ static void set_rest_position(Mesh &mesh)
|
|||
}
|
||||
}
|
||||
|
||||
static void 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 bool allow_shared_mesh,
|
||||
/* return args */
|
||||
Mesh **r_deform,
|
||||
Mesh **r_final,
|
||||
GeometrySet **r_geometry_set)
|
||||
static MeshEditHints &geometry_mesh_edit_hints_ensure(GeometrySet &geometry)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
/* Input mesh shouldn't be modified. */
|
||||
Mesh *mesh_input = (Mesh *)ob->data;
|
||||
/* The final mesh is the result of calculating all enabled modifiers. */
|
||||
Mesh *mesh_final = nullptr;
|
||||
/* The result of calculating all leading deform modifiers. */
|
||||
Mesh *mesh_deform = nullptr;
|
||||
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
|
||||
GeometrySet geometry_set_final;
|
||||
auto &edit_data = geometry.get_component_for_write<GeometryComponentEditData>();
|
||||
if (!edit_data.mesh_edit_hints_) {
|
||||
edit_data.mesh_edit_hints_ = std::make_unique<MeshEditHints>();
|
||||
}
|
||||
return *edit_data.mesh_edit_hints_;
|
||||
}
|
||||
|
||||
static void save_deform_mesh(GeometrySet &geometry)
|
||||
{
|
||||
if (const Mesh *mesh = geometry.get_mesh()) {
|
||||
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);
|
||||
|
||||
GeometrySet geometry_set = GeometrySet::from_mesh(const_cast<Mesh *>(mesh_input),
|
||||
GeometryOwnershipType::ReadOnly);
|
||||
|
||||
/* Mesh with constructive modifiers but no deformation applied. Tracked
|
||||
* along with final mesh if undeformed / orco coordinates are requested
|
||||
* for texturing. */
|
||||
|
@ -605,11 +592,9 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
BKE_modifiers_clear_errors(ob);
|
||||
|
||||
if (ob->modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
|
||||
if (mesh_final == nullptr) {
|
||||
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
|
||||
ASSERT_IS_VALID_MESH(mesh_final);
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
set_rest_position(*mesh);
|
||||
}
|
||||
set_rest_position(*mesh_final);
|
||||
}
|
||||
|
||||
/* Apply all leading deform modifiers. */
|
||||
|
@ -623,20 +608,17 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
|
||||
if (mti->type == ModifierTypeType::OnlyDeform && !sculpt_dyntopo) {
|
||||
ScopedModifierTimer modifier_timer{*md};
|
||||
if (!mesh_final) {
|
||||
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
|
||||
ASSERT_IS_VALID_MESH(mesh_final);
|
||||
}
|
||||
|
||||
if (mti->required_data_mask) {
|
||||
CustomData_MeshMasks mask{};
|
||||
mti->required_data_mask(md, &mask);
|
||||
if (mask.vmask & CD_MASK_ORCO) {
|
||||
add_orco_mesh(ob, nullptr, mesh_final, nullptr, CD_ORCO);
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
if (mti->required_data_mask) {
|
||||
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_final, mesh_final->vert_positions_for_write());
|
||||
BKE_modifier_deform_verts(md, &mectx, mesh, mesh->vert_positions_for_write());
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
|
@ -646,9 +628,7 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
/* Result of all leading deforming modifiers is cached for
|
||||
* places that wish to use the original mesh but with deformed
|
||||
* coordinates (like vertex paint). */
|
||||
if (r_deform) {
|
||||
mesh_deform = BKE_mesh_copy_for_eval(mesh_final ? mesh_final : mesh_input);
|
||||
}
|
||||
save_deform_mesh(geometry_set);
|
||||
}
|
||||
|
||||
/* Apply all remaining constructive and deforming modifiers. */
|
||||
|
@ -706,45 +686,31 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
continue;
|
||||
}
|
||||
|
||||
blender::bke::ScopedModifierTimer modifier_timer{*md};
|
||||
ScopedModifierTimer modifier_timer{*md};
|
||||
|
||||
/* Add orco mesh as layer if needed by this modifier. */
|
||||
if (mesh_final && mesh_orco && mti->required_data_mask) {
|
||||
CustomData_MeshMasks mask = {0};
|
||||
mti->required_data_mask(md, &mask);
|
||||
if (mask.vmask & CD_MASK_ORCO) {
|
||||
add_orco_mesh(ob, nullptr, mesh_final, mesh_orco, CD_ORCO);
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
if (mesh_orco && mti->required_data_mask) {
|
||||
CustomData_MeshMasks mask = {0};
|
||||
mti->required_data_mask(md, &mask);
|
||||
if (mask.vmask & CD_MASK_ORCO) {
|
||||
add_orco_mesh(ob, nullptr, mesh, mesh_orco, CD_ORCO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mti->type == ModifierTypeType::OnlyDeform) {
|
||||
if (!mesh_final) {
|
||||
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
|
||||
ASSERT_IS_VALID_MESH(mesh_final);
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
BKE_modifier_deform_verts(md, &mectx, mesh, mesh->vert_positions_for_write());
|
||||
}
|
||||
BKE_modifier_deform_verts(md, &mectx, mesh_final, mesh_final->vert_positions_for_write());
|
||||
}
|
||||
else {
|
||||
bool check_for_needs_mapping = false;
|
||||
if (mesh_final != 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_final = BKE_mesh_copy_for_eval(mesh_input);
|
||||
ASSERT_IS_VALID_MESH(mesh_final);
|
||||
check_for_needs_mapping = true;
|
||||
}
|
||||
|
||||
have_non_onlydeform_modifiers_applied = true;
|
||||
|
||||
/* determine which data layers are needed by following modifiers */
|
||||
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
|
||||
* constructive modifier. Modifiers will then do mapping mostly
|
||||
* automatic by copying them through CustomData_copy_data along
|
||||
|
@ -756,70 +722,54 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX))
|
||||
{
|
||||
/* calc */
|
||||
CustomData_add_layer(
|
||||
&mesh_final->vert_data, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->verts_num);
|
||||
CustomData_add_layer(
|
||||
&mesh_final->edge_data, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->edges_num);
|
||||
CustomData_add_layer(
|
||||
&mesh_final->face_data, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->faces_num);
|
||||
CustomData_add_layer(&mesh->vert_data, CD_ORIGINDEX, CD_CONSTRUCT, mesh->verts_num);
|
||||
CustomData_add_layer(&mesh->edge_data, CD_ORIGINDEX, CD_CONSTRUCT, mesh->edges_num);
|
||||
CustomData_add_layer(&mesh->face_data, CD_ORIGINDEX, CD_CONSTRUCT, mesh->faces_num);
|
||||
|
||||
/* Not worth parallelizing this,
|
||||
* gives less than 0.1% overall speedup in best of best cases... */
|
||||
range_vn_i((int *)CustomData_get_layer_for_write(
|
||||
&mesh_final->vert_data, CD_ORIGINDEX, mesh_final->verts_num),
|
||||
mesh_final->verts_num,
|
||||
&mesh->vert_data, CD_ORIGINDEX, mesh->verts_num),
|
||||
mesh->verts_num,
|
||||
0);
|
||||
range_vn_i((int *)CustomData_get_layer_for_write(
|
||||
&mesh_final->edge_data, CD_ORIGINDEX, mesh_final->edges_num),
|
||||
mesh_final->edges_num,
|
||||
&mesh->edge_data, CD_ORIGINDEX, mesh->edges_num),
|
||||
mesh->edges_num,
|
||||
0);
|
||||
range_vn_i((int *)CustomData_get_layer_for_write(
|
||||
&mesh_final->face_data, CD_ORIGINDEX, mesh_final->faces_num),
|
||||
mesh_final->faces_num,
|
||||
&mesh->face_data, CD_ORIGINDEX, mesh->faces_num),
|
||||
mesh->faces_num,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
/* set the Mesh to only copy needed data */
|
||||
CustomData_MeshMasks mask = md_datamask->mask;
|
||||
/* needMapping check here fixes bug #28112, otherwise it's
|
||||
* possible that it won't be copied */
|
||||
CustomData_MeshMasks_update(&mask, &append_mask);
|
||||
if (need_mapping) {
|
||||
mask.vmask |= CD_MASK_ORIGINDEX;
|
||||
mask.emask |= CD_MASK_ORIGINDEX;
|
||||
mask.pmask |= CD_MASK_ORIGINDEX;
|
||||
}
|
||||
mesh_set_only_copy(mesh_final, &mask);
|
||||
/* set the Mesh to only copy needed data */
|
||||
CustomData_MeshMasks mask = md_datamask->mask;
|
||||
/* needMapping check here fixes bug #28112, otherwise it's
|
||||
* possible that it won't be copied */
|
||||
CustomData_MeshMasks_update(&mask, &append_mask);
|
||||
if (need_mapping) {
|
||||
mask.vmask |= CD_MASK_ORIGINDEX;
|
||||
mask.emask |= CD_MASK_ORIGINDEX;
|
||||
mask.pmask |= CD_MASK_ORIGINDEX;
|
||||
}
|
||||
mesh_set_only_copy(mesh, &mask);
|
||||
|
||||
/* add cloth rest shape key if needed */
|
||||
if (mask.vmask & CD_MASK_CLOTH_ORCO) {
|
||||
add_orco_mesh(ob, nullptr, mesh_final, mesh_orco, CD_CLOTH_ORCO);
|
||||
}
|
||||
/* add cloth rest shape key if needed */
|
||||
if (mask.vmask & CD_MASK_CLOTH_ORCO) {
|
||||
add_orco_mesh(ob, nullptr, mesh, mesh_orco, CD_CLOTH_ORCO);
|
||||
}
|
||||
|
||||
/* add an origspace layer if needed */
|
||||
if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) {
|
||||
if (!CustomData_has_layer(&mesh_final->corner_data, CD_ORIGSPACE_MLOOP)) {
|
||||
CustomData_add_layer(&mesh_final->corner_data,
|
||||
CD_ORIGSPACE_MLOOP,
|
||||
CD_SET_DEFAULT,
|
||||
mesh_final->corners_num);
|
||||
mesh_init_origspace(mesh_final);
|
||||
/* add an origspace layer if needed */
|
||||
if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) {
|
||||
if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) {
|
||||
CustomData_add_layer(
|
||||
&mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num);
|
||||
mesh_init_origspace(mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(
|
||||
md, mectx, mesh_final, geometry_set_final);
|
||||
ASSERT_IS_VALID_MESH(mesh_next);
|
||||
|
||||
if (mesh_next) {
|
||||
/* if the modifier returned a new mesh, release the old one */
|
||||
if (mesh_final != mesh_next) {
|
||||
BLI_assert(mesh_final != mesh_input);
|
||||
BKE_id_free(nullptr, mesh_final);
|
||||
}
|
||||
mesh_final = mesh_next;
|
||||
}
|
||||
modifier_modify_mesh_and_geometry_set(md, mectx, geometry_set);
|
||||
|
||||
/* create an orco mesh in parallel */
|
||||
if (nextmask.vmask & CD_MASK_ORCO) {
|
||||
|
@ -840,17 +790,14 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
CustomData_MeshMasks_update(&temp_cddata_masks, &nextmask);
|
||||
mesh_set_only_copy(mesh_orco, &temp_cddata_masks);
|
||||
|
||||
mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco);
|
||||
ASSERT_IS_VALID_MESH(mesh_next);
|
||||
|
||||
if (mesh_next) {
|
||||
/* if the modifier returned a new mesh, release the old one */
|
||||
if (mesh_orco != mesh_next) {
|
||||
Mesh *mesh_orco_new = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco);
|
||||
ASSERT_IS_VALID_MESH(mesh_orco_new);
|
||||
if (mesh_orco_new) {
|
||||
if (mesh_orco != mesh_orco_new) {
|
||||
BLI_assert(mesh_orco != mesh_input);
|
||||
BKE_id_free(nullptr, mesh_orco);
|
||||
}
|
||||
|
||||
mesh_orco = mesh_next;
|
||||
mesh_orco = mesh_orco_new;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -866,21 +813,23 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
nextmask.pmask |= CD_MASK_ORIGINDEX;
|
||||
mesh_set_only_copy(mesh_orco_cloth, &nextmask);
|
||||
|
||||
mesh_next = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth);
|
||||
ASSERT_IS_VALID_MESH(mesh_next);
|
||||
|
||||
if (mesh_next) {
|
||||
/* if the modifier returned a new mesh, release the old one */
|
||||
if (mesh_orco_cloth != mesh_next) {
|
||||
Mesh *mesh_orco_cloth_new = BKE_modifier_modify_mesh(md, &mectx_orco, mesh_orco_cloth);
|
||||
ASSERT_IS_VALID_MESH(mesh_orco_cloth_new);
|
||||
if (mesh_orco_cloth_new) {
|
||||
if (mesh_orco_cloth != mesh_orco_cloth_new) {
|
||||
BLI_assert(mesh_orco != mesh_input);
|
||||
BKE_id_free(nullptr, mesh_orco_cloth);
|
||||
}
|
||||
|
||||
mesh_orco_cloth = mesh_next;
|
||||
mesh_orco_cloth = mesh_orco_cloth_new;
|
||||
}
|
||||
}
|
||||
|
||||
mesh_final->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) {
|
||||
|
@ -894,32 +843,6 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
BKE_modifier_free_temporary_data(md);
|
||||
}
|
||||
|
||||
if (mesh_final == nullptr) {
|
||||
if (allow_shared_mesh) {
|
||||
mesh_final = mesh_input;
|
||||
}
|
||||
else {
|
||||
mesh_final = 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_final != 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_final, mesh_orco, CD_ORCO);
|
||||
}
|
||||
|
||||
if (mesh_deform) {
|
||||
add_orco_mesh(ob, nullptr, mesh_deform, nullptr, CD_ORCO);
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh_orco) {
|
||||
BKE_id_free(nullptr, mesh_orco);
|
||||
}
|
||||
|
@ -929,46 +852,18 @@ static void mesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
|
||||
/* Remove temporary data layer only needed for modifier evaluation.
|
||||
* Save some memory, and ensure GPU subdivision does not need to deal with this. */
|
||||
CustomData_free_layers(&mesh_final->vert_data, CD_CLOTH_ORCO, mesh_final->verts_num);
|
||||
|
||||
/* Compute normals. */
|
||||
if (is_own_mesh) {
|
||||
mesh_calc_finalize(mesh_input, mesh_final);
|
||||
}
|
||||
else {
|
||||
blender::bke::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. */
|
||||
blender::threading::isolate_task([&] {
|
||||
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
|
||||
mesh_calc_finalize(mesh_input, mesh_final);
|
||||
runtime->mesh_eval = mesh_final;
|
||||
});
|
||||
}
|
||||
else {
|
||||
/* Already finalized by another instance, reuse. */
|
||||
mesh_final = runtime->mesh_eval;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Already finalized by another instance, reuse. */
|
||||
mesh_final = runtime->mesh_eval;
|
||||
if (const Mesh *mesh = geometry_set.get_mesh()) {
|
||||
if (CustomData_has_layer(&mesh->vert_data, CD_CLOTH_ORCO)) {
|
||||
Mesh *mesh_mut = geometry_set.get_mesh_for_write();
|
||||
CustomData_free_layers(&mesh_mut->vert_data, CD_CLOTH_ORCO, mesh_mut->verts_num);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return final mesh */
|
||||
*r_final = mesh_final;
|
||||
if (r_deform) {
|
||||
*r_deform = mesh_deform;
|
||||
}
|
||||
if (r_geometry_set) {
|
||||
*r_geometry_set = new GeometrySet(std::move(geometry_set_final));
|
||||
}
|
||||
return geometry_set;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
bool editbmesh_modifier_is_enabled(const Scene *scene,
|
||||
const Object *ob,
|
||||
ModifierData *md,
|
||||
|
@ -989,6 +884,8 @@ bool editbmesh_modifier_is_enabled(const Scene *scene,
|
|||
return true;
|
||||
}
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
static MutableSpan<float3> mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh)
|
||||
{
|
||||
switch (mesh->runtime->wrapper_type) {
|
||||
|
@ -1006,21 +903,21 @@ static MutableSpan<float3> mesh_wrapper_vert_coords_ensure_for_write(Mesh *mesh)
|
|||
return {};
|
||||
}
|
||||
|
||||
static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
|
||||
const Scene *scene,
|
||||
Object *ob,
|
||||
const CustomData_MeshMasks *dataMask,
|
||||
/* return args */
|
||||
Mesh **r_cage,
|
||||
Mesh **r_final,
|
||||
GeometrySet **r_geometry_set)
|
||||
static void save_cage_mesh(GeometrySet &geometry)
|
||||
{
|
||||
Mesh *mesh_input = (Mesh *)ob->data;
|
||||
BMEditMesh *em_input = mesh_input->runtime->edit_mesh.get();
|
||||
if (const Mesh *mesh = geometry.get_mesh()) {
|
||||
MeshEditHints &edit_data = geometry_mesh_edit_hints_ensure(geometry);
|
||||
edit_data.mesh_cage = geometry.get_component_ptr<MeshComponent>();
|
||||
}
|
||||
}
|
||||
|
||||
Mesh *mesh_cage = nullptr;
|
||||
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
|
||||
GeometrySet geometry_set_final;
|
||||
static GeometrySet editbmesh_calc_modifiers(Depsgraph *depsgraph,
|
||||
const Scene *scene,
|
||||
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.get();
|
||||
|
||||
/* Mesh with constructive modifiers but no deformation applied. Tracked
|
||||
* along with final mesh if undeformed / orco coordinates are requested
|
||||
|
@ -1050,12 +947,12 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
CDMaskLink *md_datamask = datamasks;
|
||||
CustomData_MeshMasks append_mask = CD_MASK_BAREMESH;
|
||||
|
||||
Mesh *mesh_final = BKE_mesh_wrapper_from_editmesh(
|
||||
mesh_input->runtime->edit_mesh, &final_datamask, mesh_input);
|
||||
GeometrySet geometry_set = GeometrySet::from_mesh(
|
||||
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);
|
||||
if (r_cage && cageIndex == -1) {
|
||||
mesh_cage = mesh_final;
|
||||
if (cageIndex == -1) {
|
||||
save_cage_mesh(geometry_set);
|
||||
}
|
||||
|
||||
/* The mesh from edit mode should not have any original index layers already, since those
|
||||
|
@ -1068,8 +965,9 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
BKE_modifiers_clear_errors(ob);
|
||||
|
||||
if (ob->modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh_final);
|
||||
set_rest_position(*mesh_final);
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
set_rest_position(*mesh);
|
||||
}
|
||||
}
|
||||
|
||||
bool non_deform_modifier_applied = false;
|
||||
|
@ -1080,47 +978,30 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
}
|
||||
|
||||
blender::bke::ScopedModifierTimer modifier_timer{*md};
|
||||
Mesh *mesh = geometry_set.get_mesh_for_write();
|
||||
|
||||
/* Add an orco mesh as layer if needed by this modifier. */
|
||||
if (mesh_orco && mti->required_data_mask) {
|
||||
CustomData_MeshMasks mask = {0};
|
||||
mti->required_data_mask(md, &mask);
|
||||
if (mask.vmask & CD_MASK_ORCO) {
|
||||
add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO);
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh_final == 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_final = BKE_mesh_copy_for_eval(mesh_final);
|
||||
if (mesh_cage->runtime->edit_mesh) {
|
||||
mesh_final->runtime->edit_mesh = mesh_cage->runtime->edit_mesh;
|
||||
mesh_final->runtime->is_original_bmesh = true;
|
||||
if (mesh_cage->runtime->edit_data) {
|
||||
mesh_final->runtime->edit_data = std::make_unique<blender::bke::EditMeshData>(
|
||||
*mesh_cage->runtime->edit_data);
|
||||
}
|
||||
add_orco_mesh(ob, em_input, mesh, mesh_orco, CD_ORCO);
|
||||
}
|
||||
}
|
||||
|
||||
if (mti->type == ModifierTypeType::OnlyDeform) {
|
||||
if (mti->deform_verts_EM) {
|
||||
BKE_modifier_deform_vertsEM(md,
|
||||
&mectx,
|
||||
em_input,
|
||||
mesh_final,
|
||||
mesh_wrapper_vert_coords_ensure_for_write(mesh_final));
|
||||
BKE_mesh_wrapper_tag_positions_changed(mesh_final);
|
||||
BKE_modifier_deform_vertsEM(
|
||||
md, &mectx, em_input, mesh, mesh_wrapper_vert_coords_ensure_for_write(mesh));
|
||||
BKE_mesh_wrapper_tag_positions_changed(mesh);
|
||||
}
|
||||
else {
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh_final);
|
||||
BKE_modifier_deform_verts(md, &mectx, mesh_final, mesh_final->vert_positions_for_write());
|
||||
mesh_final->tag_positions_changed();
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||
BKE_modifier_deform_verts(md, &mectx, mesh, mesh->vert_positions_for_write());
|
||||
}
|
||||
}
|
||||
else {
|
||||
Mesh *mesh = geometry_set.get_mesh_for_write();
|
||||
non_deform_modifier_applied = true;
|
||||
|
||||
/* create an orco derivedmesh in parallel */
|
||||
|
@ -1157,33 +1038,25 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
mask.emask |= CD_MASK_ORIGINDEX;
|
||||
mask.pmask |= CD_MASK_ORIGINDEX;
|
||||
|
||||
mesh_set_only_copy(mesh_final, &mask);
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
mesh_set_only_copy(mesh, &mask);
|
||||
|
||||
if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) {
|
||||
if (!CustomData_has_layer(&mesh_final->corner_data, CD_ORIGSPACE_MLOOP)) {
|
||||
CustomData_add_layer(&mesh_final->corner_data,
|
||||
CD_ORIGSPACE_MLOOP,
|
||||
CD_SET_DEFAULT,
|
||||
mesh_final->corners_num);
|
||||
mesh_init_origspace(mesh_final);
|
||||
if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) {
|
||||
if (!CustomData_has_layer(&mesh->corner_data, CD_ORIGSPACE_MLOOP)) {
|
||||
CustomData_add_layer(
|
||||
&mesh->corner_data, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh->corners_num);
|
||||
mesh_init_origspace(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
mesh->runtime->deformed_only = false;
|
||||
}
|
||||
|
||||
Mesh *mesh_next = modifier_modify_mesh_and_geometry_set(
|
||||
md, mectx, mesh_final, geometry_set_final);
|
||||
ASSERT_IS_VALID_MESH(mesh_next);
|
||||
|
||||
if (mesh_next) {
|
||||
if (mesh_final != mesh_next) {
|
||||
BKE_id_free(nullptr, mesh_final);
|
||||
}
|
||||
mesh_final = mesh_next;
|
||||
}
|
||||
mesh_final->runtime->deformed_only = false;
|
||||
modifier_modify_mesh_and_geometry_set(md, mectx, geometry_set);
|
||||
}
|
||||
|
||||
if (r_cage && i == cageIndex) {
|
||||
mesh_cage = mesh_final;
|
||||
if (i == cageIndex) {
|
||||
blender::bke::save_cage_mesh(geometry_set);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1191,24 +1064,18 @@ static void editbmesh_calc_modifiers(Depsgraph *depsgraph,
|
|||
|
||||
/* Add orco coordinates to final and deformed mesh if requested. */
|
||||
if (final_datamask.vmask & CD_MASK_ORCO) {
|
||||
/* FIXME(@ideasman42): avoid the need to convert to mesh data just to add an orco layer. */
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh_final);
|
||||
|
||||
add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO);
|
||||
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh_orco) {
|
||||
BKE_id_free(nullptr, mesh_orco);
|
||||
}
|
||||
|
||||
/* Return final mesh. */
|
||||
*r_final = mesh_final;
|
||||
if (r_cage) {
|
||||
*r_cage = mesh_cage;
|
||||
}
|
||||
if (r_geometry_set) {
|
||||
*r_geometry_set = new GeometrySet(std::move(geometry_set_final));
|
||||
}
|
||||
return geometry_set;
|
||||
}
|
||||
|
||||
static void mesh_build_extra_data(const Depsgraph *depsgraph,
|
||||
|
@ -1228,53 +1095,28 @@ static void mesh_build_data(Depsgraph *depsgraph,
|
|||
const CustomData_MeshMasks *dataMask,
|
||||
const bool need_mapping)
|
||||
{
|
||||
#if 0 /* XXX This is already taken care of in #mesh_calc_modifiers... */
|
||||
if (need_mapping) {
|
||||
/* Also add the flag so that it is recorded in lastDataMask. */
|
||||
dataMask->vmask |= CD_MASK_ORIGINDEX;
|
||||
dataMask->emask |= CD_MASK_ORIGINDEX;
|
||||
dataMask->pmask |= CD_MASK_ORIGINDEX;
|
||||
}
|
||||
#endif
|
||||
const Mesh *mesh_input = static_cast<const Mesh *>(ob->data);
|
||||
|
||||
Mesh *mesh_eval = nullptr, *mesh_deform_eval = nullptr;
|
||||
GeometrySet *geometry_set_eval = nullptr;
|
||||
mesh_calc_modifiers(depsgraph,
|
||||
scene,
|
||||
ob,
|
||||
true,
|
||||
need_mapping,
|
||||
dataMask,
|
||||
true,
|
||||
true,
|
||||
&mesh_deform_eval,
|
||||
&mesh_eval,
|
||||
&geometry_set_eval);
|
||||
GeometrySet geometry_set = mesh_calc_modifiers(
|
||||
depsgraph, scene, ob, true, need_mapping, dataMask, true);
|
||||
|
||||
/* 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);
|
||||
const Mesh *mesh_eval = geometry_set.get_mesh();
|
||||
|
||||
/* 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;
|
||||
BKE_object_eval_assign_data(ob, &const_cast<ID &>(mesh_eval->id), false);
|
||||
ob->runtime->geometry_set_eval = new GeometrySet(std::move(geometry_set));
|
||||
|
||||
ob->runtime->mesh_deform_eval = mesh_deform_eval;
|
||||
ob->runtime->last_data_mask = *dataMask;
|
||||
ob->runtime->last_need_mapping = need_mapping;
|
||||
|
||||
/* Make sure that drivers can target shapekey properties.
|
||||
* Note that this causes a potential inconsistency, as the shapekey may have a
|
||||
* different topology than the evaluated mesh. */
|
||||
BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id));
|
||||
mesh_eval->key = mesh->key;
|
||||
if (mesh_input->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 (DEG_is_active(depsgraph)) {
|
||||
|
@ -1285,48 +1127,58 @@ static void mesh_build_data(Depsgraph *depsgraph,
|
|||
mesh_build_extra_data(depsgraph, ob, mesh_eval);
|
||||
}
|
||||
|
||||
static void ensure_mesh_component_mdata(GeometrySet &geometry_set)
|
||||
{
|
||||
const Mesh *mesh = geometry_set.get_mesh();
|
||||
}
|
||||
|
||||
static void editbmesh_build_data(Depsgraph *depsgraph,
|
||||
const Scene *scene,
|
||||
Object *obedit,
|
||||
CustomData_MeshMasks *dataMask)
|
||||
{
|
||||
Mesh *mesh = static_cast<Mesh *>(obedit->data);
|
||||
Mesh *me_cage;
|
||||
Mesh *me_final;
|
||||
GeometrySet *non_mesh_components;
|
||||
const Mesh *mesh_input = static_cast<const Mesh *>(obedit->data);
|
||||
|
||||
editbmesh_calc_modifiers(
|
||||
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;
|
||||
GeometrySet geometry_set = editbmesh_calc_modifiers(depsgraph, scene, obedit, dataMask);
|
||||
|
||||
/* Object has edit_mesh but is not in edit mode (object shares mesh datablock with another object
|
||||
* with is in edit mode).
|
||||
* Convert edit mesh to mesh until the draw manager can draw mesh wrapper which is not in the
|
||||
* edit mode. */
|
||||
if (!(obedit->mode & OB_MODE_EDIT)) {
|
||||
BKE_mesh_wrapper_ensure_mdata(me_final);
|
||||
if (me_final != me_cage) {
|
||||
BKE_mesh_wrapper_ensure_mdata(me_cage);
|
||||
MeshEditHints &edit_hints =
|
||||
*geometry_set.get_component_for_write<GeometryComponentEditData>().mesh_edit_hints_;
|
||||
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 {
|
||||
edit_hints.mesh_cage = edit_hints.mesh_cage->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);
|
||||
BKE_object_eval_assign_data(obedit, &me_final->id, is_mesh_eval_owned);
|
||||
Mesh *mesh_final = const_cast<Mesh *>(geometry_set.get_mesh());
|
||||
|
||||
BKE_object_eval_assign_data(obedit, &mesh_final->id, false);
|
||||
|
||||
/* Make sure that drivers can target shapekey properties.
|
||||
* Note that this causes a potential inconsistency, as the shapekey may have a
|
||||
* different topology than the evaluated mesh. */
|
||||
BLI_assert(mesh->key == nullptr || DEG_is_evaluated_id(&mesh->key->id));
|
||||
me_final->key = mesh->key;
|
||||
BLI_assert(mesh_input->key == nullptr || DEG_is_evaluated_id(&mesh_input->key->id));
|
||||
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 = non_mesh_components;
|
||||
obedit->runtime->geometry_set_eval = new GeometrySet(std::move(geometry_set));
|
||||
|
||||
obedit->runtime->last_data_mask = *dataMask;
|
||||
}
|
||||
|
@ -1385,11 +1237,14 @@ static void object_get_datamask(const Depsgraph *depsgraph,
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
void makeDerivedMesh(Depsgraph *depsgraph,
|
||||
const Scene *scene,
|
||||
Object *ob,
|
||||
const CustomData_MeshMasks *dataMask)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
BLI_assert(ob->type == OB_MESH);
|
||||
|
||||
/* Evaluated meshes aren't supposed to be created on original instances. If you do,
|
||||
|
@ -1426,6 +1281,7 @@ Mesh *mesh_get_eval_deform(Depsgraph *depsgraph,
|
|||
Object *ob,
|
||||
const CustomData_MeshMasks *dataMask)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
BMEditMesh *em = ((Mesh *)ob->data)->runtime->edit_mesh.get();
|
||||
if (em != nullptr) {
|
||||
/* There is no such a concept as deformed mesh in edit mode.
|
||||
|
@ -1450,7 +1306,7 @@ Mesh *mesh_get_eval_deform(Depsgraph *depsgraph,
|
|||
CustomData_MeshMasks cddata_masks = *dataMask;
|
||||
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) ||
|
||||
(need_mapping && !ob->runtime->last_need_mapping))
|
||||
{
|
||||
|
@ -1459,7 +1315,7 @@ Mesh *mesh_get_eval_deform(Depsgraph *depsgraph,
|
|||
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,
|
||||
|
@ -1467,10 +1323,11 @@ Mesh *mesh_create_eval_final(Depsgraph *depsgraph,
|
|||
Object *ob,
|
||||
const CustomData_MeshMasks *dataMask)
|
||||
{
|
||||
Mesh *result;
|
||||
mesh_calc_modifiers(
|
||||
depsgraph, scene, ob, true, false, dataMask, false, false, nullptr, &result, nullptr);
|
||||
return result;
|
||||
using namespace blender::bke;
|
||||
GeometrySet geometry_set = mesh_calc_modifiers(
|
||||
depsgraph, scene, ob, true, false, dataMask, false);
|
||||
geometry_set.ensure_owns_direct_data();
|
||||
return geometry_set.get_component_for_write<MeshComponent>().release();
|
||||
}
|
||||
|
||||
Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
|
||||
|
@ -1478,10 +1335,11 @@ Mesh *mesh_create_eval_no_deform(Depsgraph *depsgraph,
|
|||
Object *ob,
|
||||
const CustomData_MeshMasks *dataMask)
|
||||
{
|
||||
Mesh *result;
|
||||
mesh_calc_modifiers(
|
||||
depsgraph, scene, ob, false, false, dataMask, false, false, nullptr, &result, nullptr);
|
||||
return result;
|
||||
using namespace blender::bke;
|
||||
GeometrySet geometry_set = mesh_calc_modifiers(
|
||||
depsgraph, scene, ob, false, false, dataMask, false);
|
||||
geometry_set.ensure_owns_direct_data();
|
||||
return geometry_set.get_component_for_write<MeshComponent>().release();
|
||||
}
|
||||
|
||||
Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
|
||||
|
@ -1489,10 +1347,11 @@ Mesh *mesh_create_eval_no_deform_render(Depsgraph *depsgraph,
|
|||
Object *ob,
|
||||
const CustomData_MeshMasks *dataMask)
|
||||
{
|
||||
Mesh *result;
|
||||
mesh_calc_modifiers(
|
||||
depsgraph, scene, ob, false, false, dataMask, false, false, nullptr, &result, nullptr);
|
||||
return result;
|
||||
using namespace blender::bke;
|
||||
GeometrySet geometry_set = mesh_calc_modifiers(
|
||||
depsgraph, scene, ob, false, false, dataMask, false);
|
||||
geometry_set.ensure_owns_direct_data();
|
||||
return geometry_set.get_component_for_write<MeshComponent>().release();
|
||||
}
|
||||
|
||||
/***/
|
||||
|
@ -1503,6 +1362,7 @@ Mesh *editbmesh_get_eval_cage(Depsgraph *depsgraph,
|
|||
BMEditMesh * /*em*/,
|
||||
const CustomData_MeshMasks *dataMask)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
CustomData_MeshMasks cddata_masks = *dataMask;
|
||||
|
||||
/* if there's no derived mesh or the last data mask used doesn't include
|
||||
|
@ -1510,13 +1370,13 @@ Mesh *editbmesh_get_eval_cage(Depsgraph *depsgraph,
|
|||
*/
|
||||
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))
|
||||
{
|
||||
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,
|
||||
|
@ -1570,6 +1430,8 @@ void mesh_get_mapped_verts_coords(Mesh *mesh_eval, blender::MutableSpan<blender:
|
|||
}
|
||||
}
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
static void mesh_init_origspace(Mesh *mesh)
|
||||
{
|
||||
const float default_osf[4][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
|
||||
|
@ -1644,3 +1506,5 @@ static void mesh_init_origspace(Mesh *mesh)
|
|||
|
||||
BKE_mesh_tessface_clear(mesh);
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
|
|
@ -489,7 +489,7 @@ static void armature_deform_coords_impl(const Object *ob_arm,
|
|||
const char *defgrp_name,
|
||||
blender::Span<MDeformVert> dverts,
|
||||
const Mesh *me_target,
|
||||
BMEditMesh *em_target,
|
||||
const BMEditMesh *em_target,
|
||||
bGPDstroke *gps_target)
|
||||
{
|
||||
const bArmature *arm = static_cast<const bArmature *>(ob_arm->data);
|
||||
|
@ -710,7 +710,7 @@ void BKE_armature_deform_coords_with_editmesh(const Object *ob_arm,
|
|||
int deformflag,
|
||||
float (*vert_coords_prev)[3],
|
||||
const char *defgrp_name,
|
||||
BMEditMesh *em_target)
|
||||
const BMEditMesh *em_target)
|
||||
{
|
||||
armature_deform_coords_impl(ob_arm,
|
||||
ob_target,
|
||||
|
|
|
@ -204,7 +204,7 @@ static void curve_deform_coords_impl(const Object *ob_curve,
|
|||
const int defgrp_index,
|
||||
const short flag,
|
||||
const short defaxis,
|
||||
BMEditMesh *em_target)
|
||||
const BMEditMesh *em_target)
|
||||
{
|
||||
Curve *cu;
|
||||
int a;
|
||||
|
@ -391,7 +391,7 @@ void BKE_curve_deform_coords_with_editmesh(const Object *ob_curve,
|
|||
const int defgrp_index,
|
||||
const short flag,
|
||||
const short defaxis,
|
||||
BMEditMesh *em_target)
|
||||
const BMEditMesh *em_target)
|
||||
{
|
||||
curve_deform_coords_impl(ob_curve,
|
||||
ob_target,
|
||||
|
|
|
@ -133,7 +133,7 @@ GeometryComponent &GeometrySet::get_component_for_write(GeometryComponent::Type
|
|||
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)) {
|
||||
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()
|
||||
{
|
||||
MeshComponent *component = this->get_component_ptr<MeshComponent>();
|
||||
MeshComponent *component = this->get_component_for_write_ptr<MeshComponent>();
|
||||
return component == nullptr ? nullptr : component->get_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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -569,7 +569,7 @@ CurvesEditHints *GeometrySet::get_curve_edit_hints_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();
|
||||
}
|
||||
|
||||
|
|
|
@ -339,7 +339,7 @@ static void lattice_deform_coords_impl(const Object *ob_lattice,
|
|||
const char *defgrp_name,
|
||||
const float fac,
|
||||
const Mesh *me_target,
|
||||
BMEditMesh *em_target)
|
||||
const BMEditMesh *em_target)
|
||||
{
|
||||
LatticeDeformData *lattice_deform_data;
|
||||
const MDeformVert *dvert = nullptr;
|
||||
|
@ -459,7 +459,7 @@ void BKE_lattice_deform_coords_with_editmesh(const Object *ob_lattice,
|
|||
const short flag,
|
||||
const char *defgrp_name,
|
||||
const float fac,
|
||||
BMEditMesh *em_target)
|
||||
const BMEditMesh *em_target)
|
||||
{
|
||||
lattice_deform_coords_impl(ob_lattice,
|
||||
ob_target,
|
||||
|
|
|
@ -929,7 +929,7 @@ void BKE_modifier_deform_verts(ModifierData *md,
|
|||
|
||||
void BKE_modifier_deform_vertsEM(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
BMEditMesh *em,
|
||||
const BMEditMesh *em,
|
||||
Mesh *mesh,
|
||||
blender::MutableSpan<blender::float3> positions)
|
||||
{
|
||||
|
|
|
@ -1636,13 +1636,6 @@ void BKE_object_free_derived_caches(Object *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->is_data_eval_owned) {
|
||||
ID *data_eval = ob->runtime->data_eval;
|
||||
|
@ -1657,11 +1650,6 @@ void BKE_object_free_derived_caches(Object *ob)
|
|||
}
|
||||
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
|
||||
* might be pointing to an evaluated data-block data was just freed above. */
|
||||
|
@ -1682,10 +1670,8 @@ void BKE_object_free_derived_caches(Object *ob)
|
|||
ob->runtime->gpd_eval = nullptr;
|
||||
}
|
||||
|
||||
if (ob->runtime->geometry_set_eval != nullptr) {
|
||||
delete ob->runtime->geometry_set_eval;
|
||||
ob->runtime->geometry_set_eval = nullptr;
|
||||
}
|
||||
delete ob->runtime->geometry_set_eval;
|
||||
ob->runtime->geometry_set_eval = nullptr;
|
||||
}
|
||||
|
||||
void BKE_object_free_caches(Object *object)
|
||||
|
@ -4217,26 +4203,59 @@ const Mesh *BKE_object_get_editmesh_eval_final(const Object *object)
|
|||
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)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
BLI_assert(!DEG_is_original_id(&object->id));
|
||||
BLI_assert(object->type == OB_MESH);
|
||||
|
||||
const Mesh *mesh = static_cast<const Mesh *>(object->data);
|
||||
BLI_assert(mesh->runtime->edit_mesh != nullptr);
|
||||
UNUSED_VARS_NDEBUG(mesh);
|
||||
|
||||
return object->runtime->editmesh_eval_cage;
|
||||
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_cage.get();
|
||||
if (!mesh_component) {
|
||||
return nullptr;
|
||||
}
|
||||
return mesh_component->get();
|
||||
}
|
||||
|
||||
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(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)
|
||||
|
@ -4875,7 +4894,6 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int /*flag*/)
|
|||
blender::bke::ObjectRuntime *runtime = object->runtime;
|
||||
runtime->data_eval = nullptr;
|
||||
runtime->gpd_eval = nullptr;
|
||||
runtime->mesh_deform_eval = nullptr;
|
||||
runtime->curve_cache = nullptr;
|
||||
runtime->object_as_temp_mesh = nullptr;
|
||||
runtime->pose_backup = nullptr;
|
||||
|
|
|
@ -89,6 +89,12 @@ template<typename T> class ImplicitSharingPtr {
|
|||
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
|
||||
{
|
||||
return data_;
|
||||
|
|
|
@ -139,7 +139,7 @@ static void deform_verts(ModifierData *md,
|
|||
|
||||
static void deform_verts_EM(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
BMEditMesh *em,
|
||||
const BMEditMesh *em,
|
||||
Mesh *mesh,
|
||||
blender::MutableSpan<blender::float3> positions)
|
||||
{
|
||||
|
|
|
@ -116,7 +116,7 @@ static void deform_verts(ModifierData *md,
|
|||
|
||||
static void deform_verts_EM(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
BMEditMesh *em,
|
||||
const BMEditMesh *em,
|
||||
Mesh *mesh,
|
||||
blender::MutableSpan<blender::float3> positions)
|
||||
{
|
||||
|
|
|
@ -107,7 +107,7 @@ static void deform_verts(ModifierData *md,
|
|||
|
||||
static void deform_verts_EM(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
BMEditMesh *em,
|
||||
const BMEditMesh *em,
|
||||
Mesh *mesh,
|
||||
blender::MutableSpan<blender::float3> positions)
|
||||
{
|
||||
|
|
|
@ -69,7 +69,7 @@ static void deform_matrices(ModifierData *md,
|
|||
|
||||
static void deform_verts_EM(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
BMEditMesh * /*em*/,
|
||||
const BMEditMesh * /*em*/,
|
||||
Mesh *mesh,
|
||||
blender::MutableSpan<blender::float3> positions)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue