Fix T75032: New complex solidify algorithm handles poorly merging threshold of small geometry details.

* Implemented the algortihm that would merge vertices to the weighted
  center between them.
* Exposed the merge threshold to the user.

The new default tolerance is 0.0001 (versionning code ensures that
previous default value remains in use to avoid any change in existing
files).

Review and minor changes/cleanups from Bastien Montagne (@mont29).
This commit is contained in:
Henrik Dick 2020-04-13 17:15:16 +02:00 committed by Bastien Montagne
parent c19f37764d
commit 5cf7283342
Notes: blender-bot 2023-02-14 05:04:52 +01:00
Referenced by issue #75032, New complex solidify algorithm handles poorly merging threshold of small geometry details.
6 changed files with 73 additions and 31 deletions

View File

@ -1049,6 +1049,8 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "edge_crease_inner", text="Inner")
col.prop(md, "edge_crease_outer", text="Outer")
col.prop(md, "edge_crease_rim", text="Rim")
else:
col.prop(md, "nonmanifold_merge_threshold")
col = split.column()

View File

@ -4890,7 +4890,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 283, 12)) {
/* Activate f-curve drawing in the sequencer. */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
for (ScrArea *area = screen->areabase.first; area; area = area->next) {
@ -4929,5 +4928,18 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
/* Solidify modifier merge tolerance. */
if (!DNA_struct_elem_find(fd->filesdna, "SolidifyModifierData", "float", "merge_tolerance")) {
for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Solidify) {
SolidifyModifierData *smd = (SolidifyModifierData *)md;
/* set to 0.0003 since that is what was used before, default now is 0.0001 */
smd->merge_tolerance = 0.0003f;
}
}
}
}
}
}

View File

@ -1175,6 +1175,9 @@ typedef struct SolidifyModifierData {
int flag;
short mat_ofs;
short mat_ofs_rim;
float merge_tolerance;
char _pad1[4];
} SolidifyModifierData;
/** #SolidifyModifierData.flag */

View File

@ -4523,6 +4523,13 @@ static void rna_def_modifier_solidify(BlenderRNA *brna)
RNA_def_property_enum_items(prop, nonmanifold_boundary_mode_items);
RNA_def_property_ui_text(prop, "Boundary Shape", "Selects the boundary adjustment algorithm");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "nonmanifold_merge_threshold", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "merge_tolerance");
RNA_def_property_range(prop, 0.0, 1.0);
RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
RNA_def_property_ui_text(prop, "Merge Threshold", "Distance within which degenerated geometry is merged");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_screw(BlenderRNA *brna)

View File

@ -53,6 +53,7 @@ static void initData(ModifierData *md)
smd->mode = MOD_SOLIDIFY_MODE_EXTRUDE;
smd->nonmanifold_offset_mode = MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS;
smd->nonmanifold_boundary_mode = MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_NONE;
smd->merge_tolerance = 0.0001f;
}
static void requiredDataMask(Object *UNUSED(ob),

View File

@ -291,6 +291,15 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
/* Vert edge adjacent map. */
OldVertEdgeRef **vert_adj_edges = MEM_calloc_arrayN(
numVerts, sizeof(*vert_adj_edges), "vert_adj_edges in solidify");
/* Original vertex positions (changed for degenerated geometry). */
float(*orig_mvert_co)[3] = MEM_malloc_arrayN(
numVerts, sizeof(*orig_mvert_co), "orig_mvert_co in solidify");
/* Fill in the original vertex positions. */
for (uint i = 0; i < numVerts; i++) {
orig_mvert_co[i][0] = orig_mvert[i].co[0];
orig_mvert_co[i][1] = orig_mvert[i].co[1];
orig_mvert_co[i][2] = orig_mvert[i].co[2];
}
/* Create edge to #NewEdgeRef map. */
{
@ -344,33 +353,35 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
bool *face_singularity = MEM_calloc_arrayN(
numPolys, sizeof(*face_singularity), "face_sides_arr in solidify");
const float merge_tolerance_sqr = smd->merge_tolerance * smd->merge_tolerance;
uint *combined_verts = MEM_calloc_arrayN(
numVerts, sizeof(*combined_verts), "combined_verts in solidify");
ed = orig_medge;
for (uint i = 0; i < numEdges; i++, ed++) {
if (edge_adj_faces_len[i] > 0) {
const uint v1 = vm[ed->v1];
const uint v2 = vm[ed->v2];
uint v1 = vm[ed->v1];
uint v2 = vm[ed->v2];
if (v1 != v2) {
sub_v3_v3v3(edgedir, orig_mvert[v2].co, orig_mvert[v1].co);
if (v2 < v1) {
SWAP(uint, v1, v2);
}
sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]);
orig_edge_lengths[i] = len_squared_v3(edgedir);
if (orig_edge_lengths[i] <= FLT_EPSILON) {
if (v2 > v1) {
for (uint j = v2; j < numVerts; j++) {
if (vm[j] == v2) {
vm[j] = v1;
vert_adj_edges_len[v1] += vert_adj_edges_len[j];
vert_adj_edges_len[j] = 0;
}
}
}
else if (v2 < v1) {
for (uint j = v1; j < numVerts; j++) {
if (vm[j] == v1) {
vm[j] = v2;
vert_adj_edges_len[v2] += vert_adj_edges_len[j];
vert_adj_edges_len[j] = 0;
}
if (orig_edge_lengths[i] <= merge_tolerance_sqr) {
mul_v3_fl(edgedir,
(combined_verts[v2] + 1) /
(float)(combined_verts[v1] + combined_verts[v2] + 2));
add_v3_v3(orig_mvert_co[v1], edgedir);
for (uint j = v2; j < numVerts; j++) {
if (vm[j] == v2) {
vm[j] = v1;
}
}
vert_adj_edges_len[v1] += vert_adj_edges_len[v2];
vert_adj_edges_len[v2] = 0;
combined_verts[v1] += combined_verts[v2] + 1;
if (do_shell) {
numNewLoops -= edge_adj_faces_len[i] * 2;
}
@ -429,6 +440,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
}
MEM_freeN(face_singularity);
MEM_freeN(combined_verts);
}
/* Create vert_adj_edges for verts. */
@ -668,7 +680,7 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
const uint v1 = vm[ed->v1];
const uint v2 = vm[ed->v2];
if (edge_adj_faces_len[i] > 0) {
sub_v3_v3v3(edgedir, orig_mvert[v2].co, orig_mvert[v1].co);
sub_v3_v3v3(edgedir, orig_mvert_co[v2], orig_mvert_co[v1]);
mul_v3_fl(edgedir, 1.0f / orig_edge_lengths[i]);
OldEdgeFaceRef *adj_faces = edge_adj_faces[i];
@ -1496,8 +1508,9 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
ml_prev = ml;
ml = ml_next;
}
angle = angle_v3v3v3(
orig_mvert[vm[ml_prev->v]].co, mv->co, orig_mvert[vm[ml_next->v]].co);
angle = angle_v3v3v3(orig_mvert_co[vm[ml_prev->v]],
orig_mvert_co[i],
orig_mvert_co[vm[ml_next->v]]);
if (face->reversed) {
total_angle_back += angle * ofs * ofs;
}
@ -1591,7 +1604,8 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
uint k;
for (k = 1; k + 1 < g->edges_len; k++, edge_ptr++) {
MEdge *e = orig_medge + (*edge_ptr)->old_edge;
sub_v3_v3v3(tmp, orig_mvert[vm[e->v1] == i ? e->v2 : e->v1].co, mv->co);
sub_v3_v3v3(
tmp, orig_mvert_co[vm[e->v1] == i ? e->v2 : e->v1], orig_mvert_co[i]);
add_v3_v3(move_nor, tmp);
}
if (k == 1) {
@ -1613,10 +1627,12 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
MEdge *e1_edge = orig_medge + g->edges[g->edges_len - 1]->old_edge;
float e0[3];
float e1[3];
sub_v3_v3v3(
e0, orig_mvert[vm[e0_edge->v1] == i ? e0_edge->v2 : e0_edge->v1].co, mv->co);
sub_v3_v3v3(
e1, orig_mvert[vm[e1_edge->v1] == i ? e1_edge->v2 : e1_edge->v1].co, mv->co);
sub_v3_v3v3(e0,
orig_mvert_co[vm[e0_edge->v1] == i ? e0_edge->v2 : e0_edge->v1],
orig_mvert_co[i]);
sub_v3_v3v3(e1,
orig_mvert_co[vm[e1_edge->v1] == i ? e1_edge->v2 : e1_edge->v1],
orig_mvert_co[i]);
if (smd->nonmanifold_boundary_mode == MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_FLAT) {
cross_v3_v3v3(constr_nor, e0, e1);
}
@ -1702,16 +1718,17 @@ Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
}
}
mul_v3_fl(nor, scalar_vgroup);
add_v3_v3v3(g->co, nor, mv->co);
add_v3_v3v3(g->co, nor, orig_mvert_co[i]);
}
else {
copy_v3_v3(g->co, mv->co);
copy_v3_v3(g->co, orig_mvert_co[i]);
}
}
}
}
}
MEM_freeN(orig_mvert_co);
if (null_faces) {
MEM_freeN(null_faces);
}