Modifiers: every modifier now copies mesh settings, fixing texture space issues

Modifier stack evaluation would copy mesh settings other than mesh topology
automatically, outside of the individual modifier evaluation. This leads to hard
to understand code, and makes it unclear which settings are available in following
modifiers, and which only after the entire stack is evaluated.

Now every modifier is responsible to ensure the mesh it outputs preserves materials,
texture space and other settings, or alters them as needed.

Fixes T64739: incorrect texture space for various modifiers

Differential Revision: https://developer.blender.org/D5808
This commit is contained in:
Brecht Van Lommel 2019-09-16 10:45:49 +02:00
parent 5516e52fad
commit e7a514369f
Notes: blender-bot 2023-02-14 09:02:40 +01:00
Referenced by issue #70103, Can't select extruded Vertex.
Referenced by issue #64739, Incorrect Auto Texture Space in both viewport and render, and with and w/o modifiers
20 changed files with 93 additions and 76 deletions

View File

@ -561,7 +561,7 @@ Mesh *AbcGenericMeshWriter::getFinalMesh(bool &r_needsfree)
BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, NULL, NULL, NULL);
Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
if (r_needsfree) {
@ -1192,8 +1192,6 @@ Mesh *AbcMeshReader::read_mesh(Mesh *existing_mesh,
existing_mesh, positions->size(), 0, 0, face_indices->size(), face_counts->size());
settings.read_flag |= MOD_MESHSEQ_READ_ALL;
/* XXX fixme after 2.80; mesh->flag isn't copied by BKE_mesh_new_nomain_from_template() */
new_mesh->flag |= (existing_mesh->flag & ME_AUTOSMOOTH);
}
else {
/* If the face count changed (e.g. by triangulation), only read points.

View File

@ -78,12 +78,18 @@ struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me,
const bool add_key_index,
const struct BMeshCreateParams *params);
struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm, const struct BMeshToMeshParams *params);
struct Mesh *BKE_mesh_from_bmesh_nomain(struct BMesh *bm,
const struct BMeshToMeshParams *params,
const struct Mesh *me_settings);
struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm,
const struct CustomData_MeshMasks *cd_mask_extra);
const struct CustomData_MeshMasks *cd_mask_extra,
const struct Mesh *me_settings);
struct Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(
struct BMEditMesh *em, const struct CustomData_MeshMasks *data_mask, float (*vertexCos)[3]);
struct BMEditMesh *em,
const struct CustomData_MeshMasks *data_mask,
float (*vertexCos)[3],
const struct Mesh *me_settings);
int poly_find_loop_from_vert(const struct MPoly *poly,
const struct MLoop *loopstart,
@ -107,6 +113,7 @@ void BKE_mesh_copy_data(struct Main *bmain,
const struct Mesh *me_src,
const int flag);
struct Mesh *BKE_mesh_copy(struct Main *bmain, const struct Mesh *me);
void BKE_mesh_copy_settings(struct Mesh *me_dst, const struct Mesh *me_src);
void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd);
void BKE_mesh_ensure_skin_customdata(struct Mesh *me);

View File

@ -729,7 +729,7 @@ static Mesh *create_orco_mesh(Object *ob, Mesh *me, BMEditMesh *em, int layer)
int free;
if (em) {
mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, me);
}
else {
mesh = BKE_mesh_copy_for_eval(me, true);
@ -797,14 +797,6 @@ static void editmesh_update_statvis_color(const Scene *scene, Object *ob)
BKE_editmesh_statvis_calc(em, me->runtime.edit_data, &scene->toolsettings->statvis);
}
static void mesh_copy_autosmooth(Mesh *me, Mesh *me_orig)
{
if (me_orig->flag & ME_AUTOSMOOTH) {
me->flag |= ME_AUTOSMOOTH;
me->smoothresh = me_orig->smoothresh;
}
}
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
const CustomData_MeshMasks *final_datamask,
const bool sculpt_dyntopo,
@ -881,18 +873,8 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
/* Make sure the name is the same. This is because mesh allocation from template does not
* take care of naming. */
BLI_strncpy(mesh_eval->id.name, mesh_input->id.name, sizeof(mesh_eval->id.name));
/* Make sure materials are preserved from the input. */
if (mesh_eval->mat != NULL) {
MEM_freeN(mesh_eval->mat);
}
mesh_eval->mat = MEM_dupallocN(mesh_input->mat);
mesh_eval->totcol = mesh_input->totcol;
/* Make evaluated mesh to share same edit mesh pointer as original and copied meshes. */
mesh_eval->edit_mesh = mesh_input->edit_mesh;
/* Copy auth-smooth settings which are also not taken care about by mesh allocation from a
* template. */
mesh_eval->flag |= (mesh_input->flag & ME_AUTOSMOOTH);
mesh_eval->smoothresh = mesh_input->smoothresh;
}
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
@ -1220,8 +1202,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
MEM_freeN(deformed_verts);
deformed_verts = NULL;
}
mesh_copy_autosmooth(mesh_final, mesh_input);
}
/* create an orco mesh in parallel */
@ -1533,8 +1513,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Evaluate modifiers up to certain index to get the mesh cage. */
int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
if (r_cage && cageIndex == -1) {
mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(em_input, &final_datamask, NULL);
mesh_copy_autosmooth(mesh_cage, mesh_input);
mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
em_input, &final_datamask, NULL, mesh_input);
}
/* Clear errors before evaluation. */
@ -1574,9 +1554,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
else if (isPrevDeform && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
if (mesh_final == NULL) {
mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
mesh_copy_autosmooth(mesh_final, mesh_input);
}
BLI_assert(deformed_verts != NULL);
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
@ -1607,11 +1586,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
}
else {
mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL);
mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, NULL, mesh_input);
ASSERT_IS_VALID_MESH(mesh_final);
mesh_copy_autosmooth(mesh_final, mesh_input);
if (deformed_verts) {
BKE_mesh_vert_coords_apply(mesh_final, deformed_verts);
}
@ -1674,8 +1651,6 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
MEM_freeN(deformed_verts);
deformed_verts = NULL;
}
mesh_copy_autosmooth(mesh_final, mesh_input);
}
mesh_final->runtime.deformed_only = false;
}
@ -1695,8 +1670,10 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
me_orig->runtime.edit_data->vertexCos = MEM_dupallocN(deformed_verts);
}
mesh_cage = BKE_mesh_from_editmesh_with_coords_thin_wrap(
em_input, &final_datamask, deformed_verts ? MEM_dupallocN(deformed_verts) : NULL);
mesh_copy_autosmooth(mesh_cage, mesh_input);
em_input,
&final_datamask,
deformed_verts ? MEM_dupallocN(deformed_verts) : NULL,
mesh_input);
}
}
@ -1730,11 +1707,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
else {
/* this is just a copy of the editmesh, no need to calc normals */
mesh_final = BKE_mesh_from_editmesh_with_coords_thin_wrap(
em_input, &final_datamask, deformed_verts);
em_input, &final_datamask, deformed_verts, mesh_input);
deformed_verts = NULL;
mesh_copy_autosmooth(mesh_final, mesh_input);
/* In this case, we should never have weight-modifying modifiers in stack... */
if (do_init_statvis) {
editmesh_update_statvis_color(scene, ob);
@ -1854,11 +1829,6 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
&ob->runtime.mesh_eval);
BKE_object_boundbox_calc_from_mesh(ob, ob->runtime.mesh_eval);
/* Only copy texspace from orig mesh if some modifier (hint: smoke sim, see T58492)
* did not re-enable that flag (which always get disabled for eval mesh as a start). */
if (!(ob->runtime.mesh_eval->texflag & ME_AUTOSPACE)) {
BKE_mesh_texspace_copy_from_object(ob->runtime.mesh_eval, ob);
}
assign_object_mesh_eval(ob);

View File

@ -261,7 +261,8 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
float (**deformcos)[3])
{
ModifierData *md;
Mesh *me;
Mesh *me_input = ob->data;
Mesh *me = NULL;
int i, a, numleft = 0, numVerts = 0;
int cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
@ -270,7 +271,6 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
modifiers_clearErrors(ob);
me = NULL;
md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
/* compute the deformation matrices and coordinates for the first
@ -292,7 +292,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra
data_mask = datamasks->mask;
BLI_linklist_free((LinkNode *)datamasks, NULL);
me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL);
me = BKE_mesh_from_editmesh_with_coords_thin_wrap(em, &data_mask, NULL, me_input);
deformedVerts = editbmesh_vert_coords_alloc(em, &numVerts);
defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats");

View File

@ -659,6 +659,35 @@ Mesh *BKE_mesh_new_nomain(
return mesh;
}
/* Copy user editable settings that we want to preserve through the modifier stack
* or operations where a mesh with new topology is created based on another mesh. */
void BKE_mesh_copy_settings(Mesh *me_dst, const Mesh *me_src)
{
/* Copy general settings. */
me_dst->editflag = me_src->editflag;
me_dst->flag = me_src->flag;
me_dst->smoothresh = me_src->smoothresh;
me_dst->remesh_voxel_size = me_src->remesh_voxel_size;
me_dst->remesh_mode = me_src->remesh_mode;
/* Copy texture space. */
me_dst->texflag = me_src->texflag;
if (me_dst->bb) {
MEM_freeN(me_dst->bb);
}
me_dst->bb = MEM_dupallocN(me_src->bb);
copy_v3_v3(me_dst->loc, me_src->loc);
copy_v3_v3(me_dst->rot, me_src->rot);
copy_v3_v3(me_dst->size, me_src->size);
/* Copy materials. */
if (me_dst->mat != NULL) {
MEM_freeN(me_dst->mat);
}
me_dst->mat = MEM_dupallocN(me_src->mat);
me_dst->totcol = me_src->totcol;
}
Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
int verts_len,
int edges_len,
@ -672,7 +701,6 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL);
me_dst->mat = MEM_dupallocN(me_src->mat);
me_dst->mselect = MEM_dupallocN(me_dst->mselect);
me_dst->totvert = verts_len;
@ -682,8 +710,7 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
me_dst->totpoly = polys_len;
me_dst->cd_flag = me_src->cd_flag;
me_dst->editflag = me_src->editflag;
me_dst->texflag = me_src->texflag;
BKE_mesh_copy_settings(me_dst, me_src);
CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len);
CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len);
@ -772,18 +799,24 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me,
});
}
Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const struct BMeshToMeshParams *params)
Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm,
const struct BMeshToMeshParams *params,
const Mesh *me_settings)
{
BLI_assert(params->calc_object_remap == false);
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me(NULL, bm, mesh, params);
BKE_mesh_copy_settings(mesh, me_settings);
return mesh;
}
Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra)
Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm,
const CustomData_MeshMasks *cd_mask_extra,
const Mesh *me_settings)
{
Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL);
BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra);
BKE_mesh_copy_settings(mesh, me_settings);
return mesh;
}
@ -792,9 +825,10 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks
*/
Mesh *BKE_mesh_from_editmesh_with_coords_thin_wrap(BMEditMesh *em,
const CustomData_MeshMasks *data_mask,
float (*vertexCos)[3])
float (*vertexCos)[3],
const Mesh *me_settings)
{
Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask);
Mesh *me = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, data_mask, me_settings);
/* Use editmesh directly where possible. */
me->runtime.is_original = true;
if (vertexCos) {
@ -1949,9 +1983,6 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
{
DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
BKE_mesh_texspace_calc(mesh);
/* Clear autospace flag in evaluated mesh, so that texspace does not get recomputed when bbox is
* (e.g. after modifiers, etc.) */
mesh->texflag &= ~ME_AUTOSPACE;
/* We are here because something did change in the mesh. This means we can not trust the existing
* evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
* evaluated mesh and let objects to re-create it with updated settings. */

View File

@ -3352,14 +3352,16 @@ struct Mesh *smokeModifier_do(
if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain &&
smd->domain->flags & MOD_SMOKE_ADAPTIVE_DOMAIN && smd->domain->base_res[0]) {
result = createDomainGeometry(smd->domain, ob);
BKE_mesh_copy_settings(result, me);
}
else {
result = BKE_mesh_copy_for_eval(me, false);
}
/* XXX This is really not a nice hack, but until root of the problem is understood,
* this should be an acceptable workaround I think.
* See T58492 for details on the issue. */
result->texflag |= ME_AUTOSPACE;
/* Smoke simulation needs a texture space relative to the adaptive domain bounds, not the
* original mesh. So recompute it at this point in the modifier stack. See T58492. */
BKE_mesh_texspace_calc(result);
return result;
}

View File

@ -179,7 +179,8 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
new_mesh = BKE_mesh_from_bmesh_nomain(bm,
(&(struct BMeshToMeshParams){
.calc_object_remap = false,
}));
}),
mesh);
BM_mesh_free(bm);

View File

@ -212,7 +212,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
spread,
mesh->smoothresh);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
/* Make sure we never alloc'd these. */
BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL);

View File

@ -316,7 +316,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MEM_freeN(looptris);
}
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);

View File

@ -199,7 +199,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
updateFaceCount(ctx, dmd, bm->totface);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
/* make sure we never alloc'd these */
BLI_assert(bm->vtoolflagpool == NULL && bm->etoolflagpool == NULL && bm->ftoolflagpool == NULL);
BLI_assert(bm->vtable == NULL && bm->etable == NULL && bm->ftable == NULL);

View File

@ -97,7 +97,7 @@ static Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd)
/* BM_mesh_validate(bm); */ /* for troubleshooting */
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;

View File

@ -513,6 +513,12 @@ static Mesh *fluidsim_read_cache(
return NULL;
}
BKE_mesh_copy_settings(newmesh, orgmesh);
/* Fluid simulation has a texture space that based on the bounds of the fluid mesh.
* This does not seem particularly useful, but it's backwards compatible. */
BKE_mesh_texspace_calc(newmesh);
/* load vertex velocities, if they exist...
* TODO? use generate flag as loading flag as well?
* warning, needs original .bobj.gz mesh loading filename */

View File

@ -118,7 +118,7 @@ static Mesh *doBiscetOnMirrorPlane(MirrorModifierData *mmd,
}
}
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
return result;

View File

@ -268,7 +268,7 @@ static void generate_ocean_geometry_uvs(void *__restrict userdata,
}
}
static Mesh *generate_ocean_geometry(OceanModifierData *omd)
static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig)
{
Mesh *result;
@ -296,6 +296,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd)
gogd.sy /= gogd.ry;
result = BKE_mesh_new_nomain(num_verts, 0, 0, num_polys * 4, num_polys);
BKE_mesh_copy_settings(result, mesh_orig);
gogd.mverts = result->mvert;
gogd.mpolys = result->mpoly;
@ -377,7 +378,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
}
if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
result = generate_ocean_geometry(omd);
result = generate_ocean_geometry(omd, mesh);
BKE_mesh_ensure_normals(result);
}
else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {

View File

@ -168,7 +168,7 @@ static void deformVerts(ModifierData *md,
if (em) {
/* In edit mode get directly from the edit mesh. */
psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
psmd->mesh_original = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, mesh);
}
else {
/* Otherwise get regular mesh. */

View File

@ -185,6 +185,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *UNUSED(c
}
}
BKE_mesh_copy_settings(result, mesh);
BKE_mesh_calc_edges(result, true, false);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;

View File

@ -1871,7 +1871,7 @@ static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd)
return NULL;
}
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, origmesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;

View File

@ -65,7 +65,7 @@ static Mesh *triangulate_mesh(Mesh *mesh,
BM_mesh_triangulate(bm, quad_method, ngon_method, min_vertices, false, NULL, NULL, NULL);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, &cddata_masks, mesh);
BM_mesh_free(bm);
if (keep_clnors) {

View File

@ -182,7 +182,7 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
else if (ob->type == OB_MESH) {
if (em) {
mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL);
mesh = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, ob->data);
}
else {
/* TODO(sybren): after modifier conversion of DM to Mesh is done, check whether

View File

@ -91,7 +91,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
MAX2(ob->totcol - 1, 0),
false);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL);
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;