Fix T34664: bevel face material can be set in tool and modifier.

Now the bevel tool, modifier, and internal operator have a material
slot # parameter that the user can set. If left at default of -1,
behavior is as current -- bevel face material is taken from the
closest original face (this may be ambiguous). If material slot
is >= 0, it gives the material slot index number for the material
to use.
This commit is contained in:
Howard Trickey 2014-07-17 09:20:22 -04:00
parent 737cb8cf7c
commit 70453c578d
Notes: blender-bot 2023-02-14 12:32:34 +01:00
Referenced by issue #34664, bevel modifier material assignment unpredictable
9 changed files with 58 additions and 29 deletions

View File

@ -127,6 +127,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "width")
col.prop(md, "segments")
col.prop(md, "profile")
col.prop(md, "material")
col = split.column()
col.prop(md, "use_only_vertices")

View File

@ -1580,6 +1580,7 @@ static BMOpDefine bmo_bevel_def = {
{"segments", BMO_OP_SLOT_INT}, /* number of segments in bevel */
{"profile", BMO_OP_SLOT_FLT}, /* profile shape, 0->1 (.5=>round) */
{"vertex_only", BMO_OP_SLOT_BOOL}, /* only bevel vertices, not edges */
{"material", BMO_OP_SLOT_INT}, /* material for bevel faces, -1 means get from adjacent faces */
{{'\0'}},
},
/* slots_out */

View File

@ -40,6 +40,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
const int seg = BMO_slot_int_get(op->slots_in, "segments");
const bool vonly = BMO_slot_bool_get(op->slots_in, "vertex_only");
const float profile = BMO_slot_float_get(op->slots_in, "profile");
const int material = BMO_slot_int_get(op->slots_in, "material");
if (offset > 0) {
BMOIter siter;
@ -60,7 +61,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
}
}
BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, false, NULL, -1);
BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, false, NULL, -1, material);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
}

View File

@ -187,6 +187,7 @@ typedef struct BevelParams {
bool limit_offset; /* should offsets be limited by collisions? */
const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */
int vertex_group; /* vertex group index, maybe set if vertex_only */
int mat_nr; /* if >= 0, material number for bevel; else material comes from adjacent faces */
} BevelParams;
// #pragma GCC diagnostic ignored "-Wpadded"
@ -356,11 +357,12 @@ static BMFace *boundvert_rep_face(BoundVert *v)
* Make ngon from verts alone.
* Make sure to properly copy face attributes and do custom data interpolation from
* corresponding elements of face_arr, if that is non-NULL, else from facerep.
* If mat_nr >= 0 then the material of the face is set to that.
*
* \note ALL face creation goes through this function, this is important to keep!
*/
static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, const int totv,
BMFace **face_arr, BMFace *facerep, bool do_interp)
BMFace **face_arr, BMFace *facerep, int mat_nr, bool do_interp)
{
BMIter iter;
BMLoop *l;
@ -395,22 +397,24 @@ static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, const int totv,
BM_elem_flag_enable(f, BM_ELEM_TAG);
}
if (mat_nr >= 0)
f->mat_nr = mat_nr;
return f;
}
static BMFace *bev_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
BMFace *facerep, bool do_interp)
BMFace *facerep, int mat_nr, bool do_interp)
{
BMVert *varr[4] = {v1, v2, v3, v4};
return bev_create_ngon(bm, varr, v4 ? 4 : 3, NULL, facerep, do_interp);
return bev_create_ngon(bm, varr, v4 ? 4 : 3, NULL, facerep, mat_nr, do_interp);
}
static BMFace *bev_create_quad_tri_ex(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4)
BMFace *f1, BMFace *f2, BMFace *f3, BMFace *f4, int mat_nr)
{
BMVert *varr[4] = {v1, v2, v3, v4};
BMFace *farr[4] = {f1, f2, f3, f4};
return bev_create_ngon(bm, varr, v4 ? 4 : 3, farr, f1, true);
return bev_create_ngon(bm, varr, v4 ? 4 : 3, farr, f1, mat_nr, true);
}
@ -490,13 +494,13 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
* one side (f1, arbitrarily), and interpolate them all on that side.
* For face data, use f1 (arbitrarily) as face representative. */
static BMFace *bev_create_quad_straddle(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
BMFace *f1, BMFace *f2, bool is_seam)
BMFace *f1, BMFace *f2, int mat_nr, bool is_seam)
{
BMFace *f, *facerep;
BMLoop *l;
BMIter iter;
f = bev_create_quad_tri(bm, v1, v2, v3, v4, f1, false);
f = bev_create_quad_tri(bm, v1, v2, v3, v4, f1, mat_nr, false);
if (!f)
return NULL;
@ -2500,6 +2504,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
BMVert *bmv1, *bmv2, *bmv3, *bmv4;
BMFace *f, *f2, *f23;
BoundVert *vpipe;
int mat_nr = bp->mat_nr;
n = bv->vmesh->count;
ns = bv->vmesh->seg;
@ -2552,7 +2557,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
if (odd && k == ns2 && f2 && !v->any_seam)
f23 = f2;
bev_create_quad_tri_ex(bm, bmv1, bmv2, bmv3, bmv4,
f, f23, f23, f);
f, f23, f23, f, mat_nr);
}
}
} while ((v = v->next) != vm->boundstart);
@ -2589,13 +2594,13 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
BLI_array_append(vf, v->any_seam ? f : boundvert_rep_face(v));
} while ((v = v->next) != vm->boundstart);
f = boundvert_rep_face(vm->boundstart);
bev_create_ngon(bm, vv, BLI_array_count(vv), vf, f, true);
bev_create_ngon(bm, vv, BLI_array_count(vv), vf, f, mat_nr, true);
BLI_array_free(vv);
}
}
static BMFace *bevel_build_poly(BMesh *bm, BevVert *bv)
static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
{
BMFace *f;
int n, k;
@ -2625,7 +2630,7 @@ static BMFace *bevel_build_poly(BMesh *bm, BevVert *bv)
}
} while ((v = v->next) != vm->boundstart);
if (n > 2) {
f = bev_create_ngon(bm, vv, n, vf, boundvert_rep_face(v), true);
f = bev_create_ngon(bm, vv, n, vf, boundvert_rep_face(v), bp->mat_nr, true);
}
else {
f = NULL;
@ -2634,12 +2639,12 @@ static BMFace *bevel_build_poly(BMesh *bm, BevVert *bv)
return f;
}
static void bevel_build_trifan(BMesh *bm, BevVert *bv)
static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
{
BMFace *f;
BLI_assert(next_bev(bv, NULL)->seg == 1 || bv->selcount == 1);
f = bevel_build_poly(bm, bv);
f = bevel_build_poly(bp, bm, bv);
if (f) {
/* we have a polygon which we know starts at the previous vertex, make it into a fan */
@ -2669,12 +2674,12 @@ static void bevel_build_trifan(BMesh *bm, BevVert *bv)
}
}
static void bevel_build_quadstrip(BMesh *bm, BevVert *bv)
static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv)
{
BMFace *f;
BLI_assert(bv->selcount == 2);
f = bevel_build_poly(bm, bv);
f = bevel_build_poly(bp, bm, bv);
if (f) {
/* we have a polygon which we know starts at this vertex, make it into strips */
@ -2813,16 +2818,16 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
bevel_build_one_wire(bm, bv);
break;
case M_POLY:
bevel_build_poly(bm, bv);
bevel_build_poly(bp, bm, bv);
break;
case M_ADJ:
bevel_build_rings(bp, bm, bv);
break;
case M_TRI_FAN:
bevel_build_trifan(bm, bv);
bevel_build_trifan(bp, bm, bv);
break;
case M_QUAD_STRIP:
bevel_build_quadstrip(bm, bv);
bevel_build_quadstrip(bp, bm, bv);
break;
}
}
@ -3173,7 +3178,7 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
}
if (do_rebuild) {
n = BLI_array_count(vv);
f_new = bev_create_ngon(bm, vv, n, NULL, f, true);
f_new = bev_create_ngon(bm, vv, n, NULL, f, -1, true);
for (k = 0; k < BLI_array_count(vv_fix); k++) {
bev_merge_uvs(bm, vv_fix[k]);
@ -3382,8 +3387,9 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
VMesh *vm1, *vm2;
EdgeHalf *e1, *e2;
BMEdge *bme1, *bme2;
BMFace *f1, *f2, *f;
BMFace *f1, *f2, *f, *newf;
int k, nseg, i1, i2, odd, mid;
int mat_nr = bp->mat_nr;
if (!BM_edge_is_manifold(bme))
return;
@ -3422,7 +3428,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
vm2 = bv2->vmesh;
if (nseg == 1) {
bev_create_quad_straddle(bm, bmv1, bmv2, bmv3, bmv4, f1, f2, e1->is_seam);
newf = bev_create_quad_straddle(bm, bmv1, bmv2, bmv3, bmv4, f1, f2, mat_nr, e1->is_seam);
}
else {
bmv1i = bmv1;
@ -3433,11 +3439,11 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
bmv4i = mesh_vert(vm1, i1, 0, k)->v;
bmv3i = mesh_vert(vm2, i2, 0, nseg - k)->v;
if (odd && k == mid + 1) {
bev_create_quad_straddle(bm, bmv1i, bmv2i, bmv3i, bmv4i, f1, f2, e1->is_seam);
bev_create_quad_straddle(bm, bmv1i, bmv2i, bmv3i, bmv4i, f1, f2, mat_nr, e1->is_seam);
}
else {
f = (k <= mid) ? f1 : f2;
bev_create_quad_tri(bm, bmv1i, bmv2i, bmv3i, bmv4i, f, true);
bev_create_quad_tri(bm, bmv1i, bmv2i, bmv3i, bmv4i, f, mat_nr, true);
}
bmv1i = bmv4i;
bmv2i = bmv3i;
@ -3676,7 +3682,7 @@ static float bevel_limit_offset(BMesh *bm, BevelParams *bp)
void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type,
const float segments, const float profile,
const bool vertex_only, const bool use_weights, const bool limit_offset,
const struct MDeformVert *dvert, const int vertex_group)
const struct MDeformVert *dvert, const int vertex_group, const int mat)
{
BMIter iter;
BMVert *v, *v_next;
@ -3694,6 +3700,7 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type,
bp.limit_offset = limit_offset;
bp.dvert = dvert;
bp.vertex_group = vertex_group;
bp.mat_nr = mat;
if (bp.pro_super_r < 0.60f)
bp.pro_super_r = 0.60f; /* TODO: implement 0 case properly */

View File

@ -31,6 +31,7 @@ struct MDeformVert;
void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type, const float segments,
const float profile, const bool vertex_only, const bool use_weights,
const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group);
const bool limit_offset, const struct MDeformVert *dvert, const int vertex_group,
const int mat);
#endif /* __BMESH_BEVEL_H__ */

View File

@ -146,15 +146,19 @@ static bool edbm_bevel_calc(wmOperator *op)
const int segments = RNA_int_get(op->ptr, "segments");
const float profile = RNA_float_get(op->ptr, "profile");
const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only");
int material = RNA_int_get(op->ptr, "material");
/* revert to original mesh */
if (opdata->is_modal) {
EDBM_redo_state_restore(opdata->mesh_backup, em, false);
}
if (em->ob)
material = CLAMPIS(material, -1, em->ob->totcol - 1);
EDBM_op_init(em, &bmop, op,
"bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f",
BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile);
"bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f material=%i",
BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, material);
BMO_op_exec(em->bm, &bmop);
@ -445,4 +449,5 @@ void MESH_OT_bevel(wmOperatorType *ot)
RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8);
RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f);
RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex only", "Bevel only vertices");
RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100);
}

View File

@ -308,6 +308,9 @@ typedef struct BevelModifierData {
short val_flags; /* used to interpret the bevel value */
short lim_flags; /* flags to tell the tool how to limit the bevel */
short e_flags; /* flags to direct how edge weights are applied to verts */
short mat; /* material index if >= 0, else material inherited from surrounding faces */
short pad;
int pad2;
float profile; /* controls profile shape (0->1, .5 is round) */
/* if the MOD_BEVEL_ANGLE is set, this will be how "sharp" an edge must be before it gets beveled */
float bevel_angle;

View File

@ -2239,6 +2239,13 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.15f, 1.0f, 0.05, 2);
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, "material", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "mat");
RNA_def_property_range(prop, -1, SHRT_MAX);
RNA_def_property_ui_text(prop, "Material", "Material index of generated faces, -1 for automatic");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)

View File

@ -57,6 +57,7 @@ static void initData(ModifierData *md)
bmd->val_flags = MOD_BEVEL_AMT_OFFSET;
bmd->lim_flags = 0;
bmd->e_flags = 0;
bmd->mat = -1;
bmd->profile = 0.5f;
bmd->bevel_angle = DEG2RADF(30.0f);
bmd->defgrp_name[0] = '\0';
@ -73,6 +74,7 @@ static void copyData(ModifierData *md, ModifierData *target)
tbmd->val_flags = bmd->val_flags;
tbmd->lim_flags = bmd->lim_flags;
tbmd->e_flags = bmd->e_flags;
tbmd->mat = bmd->mat;
tbmd->profile = bmd->profile;
tbmd->bevel_angle = bmd->bevel_angle;
BLI_strncpy(tbmd->defgrp_name, bmd->defgrp_name, sizeof(tbmd->defgrp_name));
@ -109,6 +111,7 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *ob,
const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0;
const bool do_clamp = !(bmd->flags & MOD_BEVEL_OVERLAP_OK);
const int offset_type = bmd->val_flags;
const int mat = CLAMPIS(bmd->mat, -1, ob->totcol - 1);
bm = DM_to_bmesh(dm, true);
if ((bmd->lim_flags & MOD_BEVEL_VGROUP) && bmd->defgrp_name[0])
@ -165,7 +168,7 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *ob,
BM_mesh_bevel(bm, bmd->value, offset_type, bmd->res, bmd->profile,
vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp,
dvert, vgroup);
dvert, vgroup, mat);
result = CDDM_from_bmesh(bm, true);