Mesh: Avoid copying positions in object mode modifier stack

Remove the use of a separate contiguous positions array now that
they are stored that way in the first place. This allows removing the
complexity of tracking whether it is allocated and deformed in the
mesh modifier stack.

Instead of deferring the creation of the final mesh until after the
positions have been copied and deformed, create the final mesh
first and then deform its positions.

Since vertex and face normals are calculated lazily, we can rely on
individual modifiers to calculate them as necessary and simplify
the modifier stack. This was hard to change before because of the
separate array of deformed positions.

Differential Revision: https://developer.blender.org/D16971
This commit is contained in:
Hans Goudey 2023-02-06 14:34:16 -05:00
parent a38d99e0b2
commit d20f992322
Notes: blender-bot 2023-10-17 10:35:30 +02:00
Referenced by issue #103789, Remove unnecessary mesh position copying
Referenced by issue #106802, Regression: sculpt with shape keys looses deformation of previous stroke
Referenced by issue #112448, Regression: Child hair particles set to "Interpolated" causes jittering when the based vertex changes position
Referenced by pull request #113679, Fix #112448: Leading deform modifiers skip adding original coordinates
Referenced by commit 9b0188db03, Fix #112448: Leading deform modifiers skip adding original coordinates
Referenced by commit d7e501ce3b, Fix #112448: Leading deform modifiers skip adding original coordinates
2 changed files with 23 additions and 71 deletions

View File

@ -661,23 +661,17 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
GeometrySet **r_geometry_set)
{
using namespace blender::bke;
/* Input and final mesh. Final mesh is only created the moment the first
* constructive modifier is executed, or a deform modifier needs normals
* or certain data layers. */
/* 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;
BLI_assert((mesh_input->id.tag & LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT) == 0);
/* TODO: Remove use of `deformed_verts` in mesh modifier stack
* since mesh positions are now stored in a contiguous array. */
float(*deformed_verts)[3] = nullptr;
int num_deformed_verts = mesh_input->totvert;
bool isPrevDeform = false;
/* Mesh with constructive modifiers but no deformation applied. Tracked
* along with final mesh if undeformed / orco coordinates are requested
* for texturing. */
@ -761,20 +755,15 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) {
blender::bke::ScopedModifierTimer modifier_timer{*md};
if (!deformed_verts) {
deformed_verts = BKE_mesh_vert_coords_alloc(mesh_input, &num_deformed_verts);
if (!mesh_final) {
mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
ASSERT_IS_VALID_MESH(mesh_final);
}
else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
if (mesh_final == nullptr) {
mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
ASSERT_IS_VALID_MESH(mesh_final);
}
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
BKE_modifier_deform_verts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
isPrevDeform = true;
BKE_modifier_deform_verts(md,
&mectx,
mesh_final,
BKE_mesh_vert_positions_for_write(mesh_final),
mesh_final->totvert);
}
else {
break;
@ -786,10 +775,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
* coordinates (like vertex paint). */
if (r_deform) {
mesh_deform = BKE_mesh_copy_for_eval(mesh_input, true);
if (deformed_verts) {
BKE_mesh_vert_coords_apply(mesh_deform, deformed_verts);
}
}
}
@ -858,36 +843,19 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
/* How to apply modifier depends on (a) what we already have as
* a result of previous modifiers (could be a Mesh or just
* deformed vertices) and (b) what type the modifier is. */
if (mti->type == eModifierTypeType_OnlyDeform) {
/* No existing verts to deform, need to build them. */
if (!deformed_verts) {
if (mesh_final) {
/* Deforming a mesh, read the vertex locations
* out of the mesh and deform them. Once done with this
* run of deformers verts will be written back. */
deformed_verts = BKE_mesh_vert_coords_alloc(mesh_final, &num_deformed_verts);
}
else {
deformed_verts = BKE_mesh_vert_coords_alloc(mesh_input, &num_deformed_verts);
}
if (!mesh_final) {
mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
ASSERT_IS_VALID_MESH(mesh_final);
}
/* if this is not the last modifier in the stack then recalculate the normals
* to avoid giving bogus normals to the next modifier see: T23673. */
else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
if (mesh_final == nullptr) {
mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
ASSERT_IS_VALID_MESH(mesh_final);
}
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
BKE_modifier_deform_verts(md, &mectx, mesh_final, deformed_verts, num_deformed_verts);
BKE_modifier_deform_verts(md,
&mectx,
mesh_final,
BKE_mesh_vert_positions_for_write(mesh_final),
mesh_final->totvert);
}
else {
bool check_for_needs_mapping = false;
/* apply vertex coordinates or build a Mesh as necessary */
if (mesh_final != nullptr) {
if (have_non_onlydeform_modifiers_appled == false) {
/* If we only deformed, we won't have initialized #CD_ORIGINDEX.
@ -901,10 +869,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
check_for_needs_mapping = true;
}
if (deformed_verts) {
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
have_non_onlydeform_modifiers_appled = true;
/* determine which data layers are needed by following modifiers */
@ -985,11 +949,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_id_free(nullptr, mesh_final);
}
mesh_final = mesh_next;
if (deformed_verts) {
MEM_freeN(deformed_verts);
deformed_verts = nullptr;
}
}
/* create an orco mesh in parallel */
@ -1060,8 +1019,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
mesh_final->runtime->deformed_only = false;
}
isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
if (sculpt_mode && md->type == eModifierType_Multires) {
multires_applied = true;
}
@ -1073,22 +1030,14 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
BKE_modifier_free_temporary_data(md);
}
/* Yay, we are done. If we have a Mesh and deformed vertices,
* we need to apply these back onto the Mesh. If we have no
* Mesh then we need to build one. */
if (mesh_final == nullptr) {
if (deformed_verts == nullptr && allow_shared_mesh) {
if (allow_shared_mesh) {
mesh_final = mesh_input;
}
else {
mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
}
}
if (deformed_verts) {
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
MEM_freeN(deformed_verts);
deformed_verts = nullptr;
}
/* 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. */

View File

@ -1017,6 +1017,9 @@ void BKE_modifier_deform_verts(ModifierData *md,
modwrap_dependsOnNormals(me);
}
mti->deformVerts(md, ctx, me, vertexCos, numVerts);
if (me) {
BKE_mesh_tag_coords_changed(me);
}
}
void BKE_modifier_deform_vertsEM(ModifierData *md,