Add a Self option to the Exact boolean modifier. Fixes T52425.

With this option, self-intersections in either or both operands
will be handled properly (if both sides are piecewise winding
number constant, and maybe some other cases too).
In the Boolean tool, this flag was there already but the code
forced a unary operation in that case; this commit corrects it
to make a binary operation. This flag makes the code slower, which
is why it is an option and not an always-on thing.
This commit is contained in:
Howard Trickey 2020-09-07 14:26:00 -04:00
parent 19f56cfe6c
commit de21ab418d
Notes: blender-bot 2023-02-14 11:24:03 +01:00
Referenced by issue #52425, BMesh booleans fail with self-overlapping geometry
5 changed files with 22 additions and 5 deletions

View File

@ -513,6 +513,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (md->type == eModifierType_Boolean) {
BooleanModifierData *bmd = (BooleanModifierData *)md;
bmd->solver = eBooleanModifierSolver_Fast;
bmd->flag = 0;
}
}
}

View File

@ -340,8 +340,8 @@ static bool bmesh_boolean(BMesh *bm,
IMesh m_in = mesh_from_bm(bm, looptris, looptris_tot, &m_triangulated, &arena);
std::function<int(int)> shape_fn;
int nshapes;
if (use_self) {
/* Unary boolean operation. Want every face where test_fn doesn't return -1. */
if (use_self && boolean_mode == BoolOpType::None) {
/* Unary knife operation. Want every face where test_fn doesn't return -1. */
nshapes = 1;
shape_fn = [bm, test_fn, user_data](int f) {
BMFace *bmf = BM_face_at_index(bm, f);

View File

@ -863,7 +863,7 @@ typedef struct BooleanModifierData {
struct Object *object;
char operation;
char solver;
char _pad[1];
char flag;
char bm_flag;
float double_threshold;
} BooleanModifierData;
@ -879,6 +879,10 @@ typedef enum {
eBooleanModifierSolver_Exact = 1,
} BooleanModifierSolver;
enum {
eBooleanModifierFlag_Self = (1 << 0),
};
/* bm_flag only used when G_DEBUG. */
enum {
eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 0),

View File

@ -2863,6 +2863,11 @@ static void rna_def_modifier_boolean(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Solver", "Method for calculating booleans");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_self", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", eBooleanModifierFlag_Self);
RNA_def_property_ui_text(prop, "Self", "Allow self-intersection in operands");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
/* BMesh debugging options, only used when G_DEBUG is set */
/* BMesh intersection options */

View File

@ -77,6 +77,7 @@ static void initData(ModifierData *md)
bmd->double_threshold = 1e-6f;
bmd->operation = eBooleanModifierOp_Difference;
bmd->solver = eBooleanModifierSolver_Exact;
bmd->flag = 0;
}
static bool isDisabled(const struct Scene *UNUSED(scene),
@ -319,15 +320,18 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
#ifdef WITH_GMP
const bool use_exact = bmd->solver == eBooleanModifierSolver_Exact;
const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
#else
if (bmd->solver == eBooleanModifierSolver_Exact) {
BKE_modifier_set_error(md, "Compiled without GMP, using fast solver");
}
const bool use_exact = false;
const bool use_self = false;
#endif
if (use_exact) {
BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, false, bmd->operation);
BM_mesh_boolean(
bm, looptris, tottri, bm_face_isect_pair, NULL, use_self, bmd->operation);
}
else {
BM_mesh_intersect(bm,
@ -393,7 +397,10 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
if (!use_exact) {
if (use_exact) {
uiItemR(layout, ptr, "use_self", 0, NULL, ICON_NONE);
}
else {
uiItemR(layout, ptr, "double_threshold", 0, NULL, ICON_NONE);
}