Hello all—I’ve never contributed to Blender before, but I’ve recently taken an interest in making some improvements to the bevel modifier to better support non-circular superellipse profiles. I’ve outlined the motivation at some length in a Blender Stack Exchange question, but the executive summary is that currently, beveling using a rectangular (i.e. “Profile Shape” >0.50) superellipse profile produces a lot of unhelpful geometry:
In the above image, I’ve used 0.85 for the profile shape, which produces a nice curve, but requires 35 bevel segments! That’s totally unnecessary—the bevel modifier currently tries to make each bevel segment equal width, but that means a lot of the faces end up nearly coplanar. What I really want is for the edges to be denser at the corners, where there’s more curvature.
To fix this, I’ve taken a stab at implementing a different algorithm, which produces results like this, instead:
As you can see, the result looks quite nice despite the small amount of geometry. My current approach is also relatively computationally inexpensive compared to the existing bevel spacing strategy, since it uses a closed-form solution for each vertex’s location, avoiding the iterative approximation process needed by the equal-width strategy. Of course, all that said, I do not propose replacing the existing spacing algorithm, only adding an alternative option; you can see the option listed as “Profile Spacing” in the screenshot above.
My patch is currently quite small, but I unfortunately can’t claim it’s nearly complete yet. Although it seems to work well on simple examples like the one above, I have not yet implemented n-ary intersections (called M_ADJ
in the code) or miters, so beveling all edges of a cube using this strategy produces some highly unsatisfactory results at the corners:
I am currently looking into fixing this, but this is quite a bit trickier, so it would be nice to know if this is something other people would be interested in before I go to the effort of figuring out how to do it properly. If anyone has any thoughts, questions, suggestions, or words of encouragement, it would be appreciated.
Also, if anyone is interested in trying this out for themselves, I have included my very work-in-progress patch below, since it really is very small:
bevel-angle-spacing.patch
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 9404bfe..b5bfd8a 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -5396,6 +5396,7 @@ def km_bevel_modal_map(_params):
("OUTER_MITER_CHANGE", {"type": 'O', "value": 'PRESS', "any": True}, None),
("INNER_MITER_CHANGE", {"type": 'I', "value": 'PRESS', "any": True}, None),
("PROFILE_TYPE_CHANGE", {"type": 'Z', "value": 'PRESS', "any": True}, None),
+ ("PROFILE_SPACING_CHANGE", {"type": 'G', "value": 'PRESS', "any": True}, None),
("VERTEX_MESH_CHANGE", {"type": 'N', "value": 'PRESS', "any": True}, None),
])
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index bccac00..6e7c4a4 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -1732,6 +1732,12 @@ static BMO_FlagSet bmo_enum_bevel_profile_type[] = {
{0, NULL},
};
+static BMO_FlagSet bmo_enum_bevel_spacing_type[] = {
+ {BEVEL_SPACING_WIDTH, "WIDTH"},
+ {BEVEL_SPACING_ANGLE, "ANGLE"},
+ {0, NULL},
+};
+
static BMO_FlagSet bmo_enum_bevel_face_strength_type[] = {
{BEVEL_FACE_STRENGTH_NONE, "NONE"},
{BEVEL_FACE_STRENGTH_NEW, "NEW"},
@@ -1775,6 +1781,8 @@ static BMOpDefine bmo_bevel_def = {
bmo_enum_bevel_profile_type}, /* The profile type to use for bevel. */
{"segments", BMO_OP_SLOT_INT}, /* number of segments in bevel */
{"profile", BMO_OP_SLOT_FLT}, /* profile shape, 0->1 (.5=>round) */
+ {"profile_spacing", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM},
+ bmo_enum_bevel_spacing_type}, /* Whether to space segments by width or angle. */
{"affect", BMO_OP_SLOT_INT, {(int)BMO_OP_SLOT_SUBTYPE_INT_ENUM},
bmo_enum_bevel_affect_type}, /* Whether to bevel vertices or edges. */
{"clamp_overlap", BMO_OP_SLOT_BOOL}, /* do not allow beveled edges/vertices to overlap each other */
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index 706979a..cd52ea7 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -295,7 +295,7 @@ typedef struct BMOpSlot {
((slot >= (op)->slots_out) && (slot < &(op)->slots_out[BMO_OP_MAX_SLOTS])))
/* Limit hit, so expanded for bevel operator. Compiler complains if limit is hit. */
-#define BMO_OP_MAX_SLOTS 21
+#define BMO_OP_MAX_SLOTS 22
/* BMOpDefine->type_flag */
typedef enum {
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index 2d9e244..217b1b1 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -117,6 +117,12 @@ enum {
BEVEL_PROFILE_CUSTOM,
};
+/* Bevel superellipse sample spacing mode */
+enum {
+ BEVEL_SPACING_WIDTH,
+ BEVEL_SPACING_ANGLE,
+};
+
/* Bevel face_strength_mode values: should match face_str mode enum in DNA_modifier_types.h */
enum {
BEVEL_FACE_STRENGTH_NONE,
diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c
index 4e708b5..8a7c291 100644
--- a/source/blender/bmesh/operators/bmo_bevel.c
+++ b/source/blender/bmesh/operators/bmo_bevel.c
@@ -37,6 +37,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
const int seg = BMO_slot_int_get(op->slots_in, "segments");
const int affect_type = BMO_slot_int_get(op->slots_in, "affect");
const float profile = BMO_slot_float_get(op->slots_in, "profile");
+ const int profile_spacing = BMO_slot_int_get(op->slots_in, "profile_spacing");
const bool clamp_overlap = BMO_slot_bool_get(op->slots_in, "clamp_overlap");
const int material = BMO_slot_int_get(op->slots_in, "material");
const bool loop_slide = BMO_slot_bool_get(op->slots_in, "loop_slide");
@@ -79,6 +80,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
profile_type,
seg,
profile,
+ profile_spacing,
affect_type,
false,
clamp_overlap,
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index cef97f2..78253c3 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -342,6 +342,8 @@ typedef struct BevelParams {
float profile;
/** Superellipse parameter for edge profile. */
float pro_super_r;
+ /** Superellipse sample spacing mode: even widths or even angles. */
+ int profile_spacing;
/** Bevel amount affected by weights on edges or verts. */
bool use_weights;
/** Should bevel prefer to slide along edges rather than keep widths spec? */
@@ -4443,7 +4445,9 @@ static int tri_corner_test(BevelParams *bp, BevVert *bv)
int in_plane_e = 0;
/* The superellipse snapping of this case isn't helpful with custom profiles enabled. */
- if (bp->affect_type == BEVEL_AFFECT_VERTICES || bp->profile_type == BEVEL_PROFILE_CUSTOM) {
+ if (bp->affect_type == BEVEL_AFFECT_VERTICES
+ || bp->profile_type == BEVEL_PROFILE_CUSTOM
+ || bp->profile_spacing == BEVEL_SPACING_ANGLE) {
return -1;
}
if (bv->vmesh->count != 3) {
@@ -6919,7 +6923,7 @@ static double find_superellipse_chord_endpoint(double x0, double dtarget, float
* for r<1 use only x in [mx,1]. Points are initially spaced and iteratively
* repositioned to have the same distance.
*/
-static void find_even_superellipse_chords_general(int seg, float r, double *xvals, double *yvals)
+static void find_even_width_superellipse_chords_general(int seg, float r, double *xvals, double *yvals)
{
const int smoothitermax = 10;
const double error_tol = 1e-7;
@@ -7019,7 +7023,7 @@ static void find_even_superellipse_chords_general(int seg, float r, double *xval
* form for equidistant parametrization.
* xvals and yvals should be size n+1.
*/
-static void find_even_superellipse_chords(int n, float r, double *xvals, double *yvals)
+static void find_even_width_superellipse_chords(int n, float r, double *xvals, double *yvals)
{
bool seg_odd = n % 2;
int n2 = n / 2;
@@ -7087,7 +7091,73 @@ static void find_even_superellipse_chords(int n, float r, double *xvals, double
return;
}
/* For general case use the more expensive search algorithm. */
- find_even_superellipse_chords_general(n, r, xvals, yvals);
+ find_even_width_superellipse_chords_general(n, r, xvals, yvals);
+}
+
+static void find_even_angle_superellipse_chords(int n, float r, double *xvals, double *yvals)
+{
+ int n2 = n / 2;
+
+ if (r == PRO_SQUARE_IN_R) {
+ xvals[0] = 0;
+ yvals[0] = 1;
+ xvals[n] = 1;
+ yvals[n] = 0;
+ for (int i = 0; i < n; i++) {
+ xvals[i] = 0;
+ yvals[i] = 0;
+ }
+ }
+ else if (r == PRO_SQUARE_R) {
+ xvals[0] = 0;
+ yvals[0] = 1;
+ xvals[n] = 1;
+ yvals[n] = 0;
+ for (int i = 0; i < n; i++) {
+ xvals[i] = 1;
+ yvals[i] = 1;
+ }
+ }
+ else if (r <= 1.0) {
+ for (int i = 0; i <= n2; i++) {
+ double yval = pow(1.0 - (i / (double)n), 1.0 / r);
+ xvals[i] = 1.0 - superellipse_co(1.0 - yval, r, false);
+ yvals[i] = yval;
+ xvals[n - i] = yvals[i];
+ yvals[n - i] = xvals[i];
+ }
+ }
+ else if (r >= 2.0) {
+ double step_angle = (M_PI / 2) / n;
+ for (int i = 0; i <= n2; i++) {
+ xvals[i] = pow(sin(i * step_angle), 2.0 / r);
+ yvals[i] = superellipse_co(xvals[i], r, true);
+ xvals[n - i] = yvals[i];
+ yvals[n - i] = xvals[i];
+ }
+ }
+ else {
+ double interp_fac = r - 1.0;
+ double step_angle = (M_PI / 2) / n;
+ for (int i = 0; i <= n2; i++) {
+ double x_concave = pow(i / (double)n, 1.0 / r);
+ double x_convex = pow(sin(i * step_angle), 2.0 / r);
+ xvals[i] = interpd(x_convex, x_concave, interp_fac);
+ yvals[i] = superellipse_co(xvals[i], r, true);
+ xvals[n - i] = yvals[i];
+ yvals[n - i] = xvals[i];
+ }
+ }
+}
+
+static void find_even_superellipse_chords(int n, float r, double *xvals, double *yvals, int spacing)
+{
+ switch (spacing) {
+ case BEVEL_SPACING_WIDTH:
+ return find_even_width_superellipse_chords(n, r, xvals, yvals);
+ case BEVEL_SPACING_ANGLE:
+ return find_even_angle_superellipse_chords(n, r, xvals, yvals);
+ }
}
/**
@@ -7195,7 +7265,7 @@ static void set_profile_spacing(BevelParams *bp, ProfileSpacing *pro_spacing, bo
}
else {
find_even_superellipse_chords(
- seg_2, bp->pro_super_r, pro_spacing->xvals_2, pro_spacing->yvals_2);
+ seg_2, bp->pro_super_r, pro_spacing->xvals_2, pro_spacing->yvals_2, bp->profile_spacing);
}
}
@@ -7215,7 +7285,7 @@ static void set_profile_spacing(BevelParams *bp, ProfileSpacing *pro_spacing, bo
}
}
else {
- find_even_superellipse_chords(seg, bp->pro_super_r, pro_spacing->xvals, pro_spacing->yvals);
+ find_even_superellipse_chords(seg, bp->pro_super_r, pro_spacing->xvals, pro_spacing->yvals, bp->profile_spacing);
}
}
@@ -7457,6 +7527,7 @@ void BM_mesh_bevel(BMesh *bm,
const int profile_type,
const int segments,
const float profile,
+ const int profile_spacing,
const bool affect_type,
const bool use_weights,
const bool limit_offset,
@@ -7488,6 +7559,7 @@ void BM_mesh_bevel(BMesh *bm,
.seg = max_ii(segments, 1),
.profile = profile,
.pro_super_r = -logf(2.0) / logf(sqrtf(profile)), /* Convert to superellipse exponent. */
+ .profile_spacing = profile_spacing,
.affect_type = affect_type,
.use_weights = use_weights,
.loop_slide = loop_slide,
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index de57e1c..5a46135 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -29,6 +29,7 @@ void BM_mesh_bevel(BMesh *bm,
const int profile_type,
const int segments,
const float profile,
+ const int profile_spacing,
const bool affect_type,
const bool use_weights,
const bool limit_offset,
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 43492cd..13bf95b 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -121,6 +121,7 @@ enum {
BEV_MODAL_OUTER_MITER_CHANGE,
BEV_MODAL_INNER_MITER_CHANGE,
BEV_MODAL_PROFILE_TYPE_CHANGE,
+ BEV_MODAL_PROFILE_SPACING_CHANGE,
BEV_MODAL_VERTEX_MESH_CHANGE,
};
@@ -160,13 +161,17 @@ static void edbm_bevel_update_status_text(bContext *C, wmOperator *op)
}
PropertyRNA *prop;
- const char *mode_str, *omiter_str, *imiter_str, *vmesh_str, *profile_type_str, *affect_str;
+ const char *mode_str, *omiter_str, *imiter_str, *vmesh_str, *profile_type_str,
+ *profile_spacing_str, *affect_str;
prop = RNA_struct_find_property(op->ptr, "offset_type");
RNA_property_enum_name_gettexted(
C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &mode_str);
prop = RNA_struct_find_property(op->ptr, "profile_type");
RNA_property_enum_name_gettexted(
C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &profile_type_str);
+ prop = RNA_struct_find_property(op->ptr, "profile_spacing");
+ RNA_property_enum_name_gettexted(
+ C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &profile_spacing_str);
prop = RNA_struct_find_property(op->ptr, "miter_outer");
RNA_property_enum_name_gettexted(
C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &omiter_str);
@@ -196,6 +201,7 @@ static void edbm_bevel_update_status_text(bContext *C, wmOperator *op)
"%s: Mark Seam (%s), "
"%s: Mark Sharp (%s), "
"%s: Profile Type (%s), "
+ "%s: Spacing (%s), "
"%s: Intersection (%s)"),
WM_MODALKEY(BEV_MODAL_CONFIRM),
WM_MODALKEY(BEV_MODAL_CANCEL),
@@ -223,6 +229,8 @@ static void edbm_bevel_update_status_text(bContext *C, wmOperator *op)
WM_bool_as_string(RNA_boolean_get(op->ptr, "mark_sharp")),
WM_MODALKEY(BEV_MODAL_PROFILE_TYPE_CHANGE),
profile_type_str,
+ WM_MODALKEY(BEV_MODAL_PROFILE_SPACING_CHANGE),
+ profile_spacing_str,
WM_MODALKEY(BEV_MODAL_VERTEX_MESH_CHANGE),
vmesh_str);
@@ -328,6 +336,7 @@ static bool edbm_bevel_calc(wmOperator *op)
const int profile_type = RNA_enum_get(op->ptr, "profile_type");
const int segments = RNA_int_get(op->ptr, "segments");
const float profile = RNA_float_get(op->ptr, "profile");
+ const int profile_spacing = RNA_enum_get(op->ptr, "profile_spacing");
const bool affect = RNA_enum_get(op->ptr, "affect");
const bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap");
const int material_init = RNA_int_get(op->ptr, "material");
@@ -363,10 +372,10 @@ static bool edbm_bevel_calc(wmOperator *op)
&bmop,
op,
"bevel geom=%hev offset=%f segments=%i affect=%i offset_type=%i "
- "profile_type=%i profile=%f clamp_overlap=%b material=%i loop_slide=%b "
- "mark_seam=%b mark_sharp=%b harden_normals=%b face_strength_mode=%i "
- "miter_outer=%i miter_inner=%i spread=%f smoothresh=%f custom_profile=%p "
- "vmesh_method=%i",
+ "profile_type=%i profile=%f profile_spacing=%i clamp_overlap=%b "
+ "material=%i loop_slide=%b mark_seam=%b mark_sharp=%b harden_normals=%b "
+ "face_strength_mode=%i miter_outer=%i miter_inner=%i spread=%f "
+ "smoothresh=%f custom_profile=%p vmesh_method=%i",
BM_ELEM_SELECT,
offset,
segments,
@@ -374,6 +383,7 @@ static bool edbm_bevel_calc(wmOperator *op)
offset_type,
profile_type,
profile,
+ profile_spacing,
clamp_overlap,
material,
loop_slide,
@@ -654,6 +664,7 @@ wmKeyMap *bevel_modal_keymap(wmKeyConfig *keyconf)
"Change Inner Miter",
"Cycle through inner miter kinds"},
{BEV_MODAL_PROFILE_TYPE_CHANGE, "PROFILE_TYPE_CHANGE", 0, "Cycle through profile types", ""},
+ {BEV_MODAL_PROFILE_SPACING_CHANGE, "PROFILE_SPACING_CHANGE", 0, "Cycle through profile spacing modes", ""},
{BEV_MODAL_VERTEX_MESH_CHANGE,
"VERTEX_MESH_CHANGE",
0,
@@ -881,6 +892,19 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
+ case BEV_MODAL_PROFILE_SPACING_CHANGE: {
+ int profile_type = RNA_enum_get(op->ptr, "profile_spacing");
+ profile_type++;
+ if (profile_type > BEVEL_SPACING_ANGLE) {
+ profile_type = BEVEL_SPACING_WIDTH;
+ }
+ RNA_enum_set(op->ptr, "profile_spacing", profile_type);
+ edbm_bevel_calc(op);
+ edbm_bevel_update_status_text(C, op);
+ handled = true;
+ break;
+ }
+
case BEV_MODAL_VERTEX_MESH_CHANGE: {
int vmesh_method = RNA_enum_get(op->ptr, "vmesh_method");
vmesh_method++;
@@ -978,7 +1002,11 @@ static void edbm_bevel_ui(bContext *C, wmOperator *op)
row = uiLayoutRow(layout, false);
uiItemR(row, op->ptr, "profile_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- if (profile_type == BEVEL_PROFILE_CUSTOM) {
+ if (profile_type == BEVEL_PROFILE_SUPERELLIPSE) {
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, op->ptr, "profile_spacing", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ }
+ else if (profile_type == BEVEL_PROFILE_CUSTOM) {
/* Get an RNA pointer to ToolSettings to give to the curve profile template code. */
Scene *scene = CTX_data_scene(C);
RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
@@ -1021,6 +1049,20 @@ void MESH_OT_bevel(wmOperatorType *ot)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem prop_profile_spacing_items[] = {
+ {BEVEL_SPACING_WIDTH,
+ "WIDTH",
+ 0,
+ "Width",
+ "Produce evenly-sized bevel segments"},
+ {BEVEL_SPACING_ANGLE,
+ "ANGLE",
+ 0,
+ "Angle",
+ "Adaptively size bevel segments to minimize variation in angle"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
static const EnumPropertyItem face_strength_mode_items[] = {
{BEVEL_FACE_STRENGTH_NONE, "NONE", 0, "None", "Do not set face strength"},
{BEVEL_FACE_STRENGTH_NEW, "NEW", 0, "New", "Set face strength on new faces only"},
@@ -1121,6 +1163,13 @@ void MESH_OT_bevel(wmOperatorType *ot)
PROFILE_HARD_MIN,
1.0f);
+ RNA_def_enum(ot->srna,
+ "profile_spacing",
+ prop_profile_spacing_items,
+ 0,
+ "Profile Spacing",
+ "Method for distributing bevel segments along the profile");
+
RNA_def_enum(ot->srna,
"affect",
prop_affect_items,
diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h
index d8e48c5..bc53449 100644
--- a/source/blender/makesdna/DNA_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_modifier_defaults.h
@@ -55,7 +55,7 @@
.res = 1, \
.flags = 0, \
.val_flags = MOD_BEVEL_AMT_OFFSET, \
- .profile_type = MOD_BEVEL_PROFILE_SUPERELLIPSE, \
+ .profile_type = MOD_BEVEL_SPACING_WIDTH, \
.lim_flags = MOD_BEVEL_ANGLE, \
.e_flags = 0, \
.mat = -1, \
@@ -65,6 +65,7 @@
.miter_outer = MOD_BEVEL_MITER_SHARP, \
.affect_type = MOD_BEVEL_AFFECT_EDGES, \
.profile = 0.5f, \
+ .profile_spacing = MOD_BEVEL_SPACING_WIDTH, \
.bevel_angle = DEG2RADF(30.0f), \
.spread = 0.1f, \
.defgrp_name = "", \
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index ca6f146..d4f9129 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -434,7 +434,8 @@ typedef struct BevelModifierData {
short vmesh_method;
/** Whether to affect vertices or edges. */
char affect_type;
- char _pad;
+ /** TODO */
+ char profile_spacing;
/** Controls profile shape (0->1, .5 is round). */
float profile;
/** if the MOD_BEVEL_ANGLE is set,
@@ -489,6 +490,12 @@ enum {
MOD_BEVEL_PROFILE_CUSTOM = 1,
};
+/* BevelModifierData->profile_spacing */
+enum {
+ MOD_BEVEL_SPACING_WIDTH = 0,
+ MOD_BEVEL_SPACING_ANGLE = 1,
+};
+
/* BevelModifierData->edge_flags */
enum {
MOD_BEVEL_MARK_SEAM = (1 << 0),
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 67335b8..d501583 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -4027,6 +4027,20 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem prop_profile_spacing_items[] = {
+ {MOD_BEVEL_SPACING_WIDTH,
+ "WIDTH",
+ 0,
+ "Width",
+ "Produce evenly-sized bevel segments"},
+ {MOD_BEVEL_SPACING_ANGLE,
+ "ANGLE",
+ 0,
+ "Angle",
+ "Adaptively size bevel segments to minimize variation in angle"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
static EnumPropertyItem prop_harden_normals_items[] = {
{MOD_BEVEL_FACE_STRENGTH_NONE, "FSTR_NONE", 0, "None", "Do not set face strength"},
{MOD_BEVEL_FACE_STRENGTH_NEW, "FSTR_NEW", 0, "New", "Set face strength on new faces only"},
@@ -4150,6 +4164,13 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Profile", "The profile shape (0.5 = round)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "profile_spacing", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "profile_spacing");
+ RNA_def_property_enum_items(prop, prop_profile_spacing_items);
+ RNA_def_property_ui_text(
+ prop, "Spacing", "Method for distributing bevel segments along the profile");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "material", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "mat");
RNA_def_property_range(prop, -1, SHRT_MAX);
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index a94411d..4a28e03 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -218,6 +218,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
profile_type,
bmd->res,
bmd->profile,
+ bmd->profile_spacing,
bmd->affect_type,
bmd->lim_flags & MOD_BEVEL_WEIGHT,
do_clamp,
@@ -338,7 +339,10 @@ static void profile_panel_draw(const bContext *UNUSED(C), Panel *panel)
IFACE_("Miter Shape"),
ICON_NONE);
- if (profile_type == MOD_BEVEL_PROFILE_CUSTOM) {
+ if (profile_type == MOD_BEVEL_PROFILE_SUPERELLIPSE) {
+ uiItemR(layout, ptr, "profile_spacing", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ }
+ else if (profile_type == MOD_BEVEL_PROFILE_CUSTOM) {
uiLayout *sub = uiLayoutColumn(layout, false);
uiLayoutSetPropDecorate(sub, false);
uiTemplateCurveProfile(sub, ptr, "custom_profile");
I’m not sure who currently “owns” the bevel code, so to speak, especially since I imagine much of it has existed for a very long time, but it would be super helpful if anyone could give me a basic overview of how all the BevVert
/VMesh
stuff fits together. I’ve mostly been able to figure things out on my own so far, and I imagine I can continue to do so given enough time, but I suspect a little extra perspective would go a long way.