Support for bridge tool subdivisions, smoothing and shape along the profile.

also added the underlying subdivision as a standalone operator in the edge menu, named: subdivide edge-ring.
http://www.graphicall.org/ftp/ideasman42/bridge_subd.png
This commit is contained in:
2013-05-23 06:19:04 +00:00
parent 4625e70430
commit 0ff22044cd
15 changed files with 1468 additions and 38 deletions

View File

@@ -139,6 +139,11 @@ bool BLI_ghashIterator_done(GHashIterator *ghi);
BLI_ghashIterator_done(&gh_iter_) == false; \
BLI_ghashIterator_step(&gh_iter_))
#define GHASH_ITER_INDEX(gh_iter_, ghash_, i_) \
for (BLI_ghashIterator_init(&gh_iter_, ghash_), i_ = 0; \
BLI_ghashIterator_done(&gh_iter_) == false; \
BLI_ghashIterator_step(&gh_iter_), i_++)
/* *** */
unsigned int BLI_ghashutil_ptrhash(const void *key);

View File

@@ -62,6 +62,7 @@ set(SRC
operators/bmo_smooth_laplacian.c
operators/bmo_split_edges.c
operators/bmo_subdivide.c
operators/bmo_subdivide_edgering.c
operators/bmo_symmetrize.c
operators/bmo_triangulate.c
operators/bmo_unsubdivide.c

View File

@@ -504,9 +504,28 @@ const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store)
return el_store->co;
}
#define NODE_AS_V(n) ((BMVert *)((LinkData *)n)->data)
#define NODE_AS_CO(n) ((BMVert *)((LinkData *)n)->data)->co
/**
* edges are assined to one vert -> the next.
*/
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr)
{
LinkData *node;
int i = 0;
for (node = el_store->verts.first; node && node->next; node = node->next) {
e_arr[i++] = BM_edge_exists(NODE_AS_V(node), NODE_AS_V(node->next));
BLI_assert(e_arr[i - 1] != NULL);
}
if (el_store->flag & BM_EDGELOOP_IS_CLOSED) {
e_arr[i] = BM_edge_exists(NODE_AS_V(el_store->verts.first), NODE_AS_V(el_store->verts.last));
BLI_assert(e_arr[i] != NULL);
}
BLI_assert(el_store->len == i + 1);
}
void BM_edgeloop_calc_center(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
{
LinkData *node_curr = el_store->verts.last;

View File

@@ -54,6 +54,7 @@ int BM_edgeloop_length_get(struct BMEdgeLoopStore *el_store);
struct ListBase *BM_edgeloop_verts_get(struct BMEdgeLoopStore *el_store);
const float *BM_edgeloop_normal_get(struct BMEdgeLoopStore *el_store);
const float *BM_edgeloop_center_get(struct BMEdgeLoopStore *el_store);
void BM_edgeloop_edges_get(struct BMEdgeLoopStore *el_store, BMEdge **e_arr);
void BM_edgeloop_calc_center(BMesh *bm, struct BMEdgeLoopStore *el_store);
void BM_edgeloop_calc_normal(BMesh *bm, struct BMEdgeLoopStore *el_store);
void BM_edgeloop_flip(BMesh *bm, struct BMEdgeLoopStore *el_store);
@@ -61,7 +62,11 @@ void BM_edgeloop_expand(BMesh *bm, struct BMEdgeLoopStore *el_sto
bool BM_edgeloop_overlap_check(struct BMEdgeLoopStore *el_store_a, struct BMEdgeLoopStore *el_store_b);
#define BM_EDGELOOP_NEXT(el_store, elink) \
#define BM_EDGELINK_NEXT(el_store, elink) \
(elink)->next ? elink->next : (BM_edgeloop_is_closed(el_store) ? BM_edgeloop_verts_get(el_store)->first : NULL)
#define BM_EDGELOOP_NEXT(el_store) \
(CHECK_TYPE_INLINE(el_store, struct BMEdgeLoopStore), \
(struct BMEdgeLoopStore *)((LinkData *)el_store)->next)
#endif /* __BMESH_EDGELOOP_H__ */

View File

@@ -523,6 +523,7 @@ static BMOpDefine bmo_bridge_loops_def = {
},
/* slots_out */
{{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* new faces */
{"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* new edges */
{{'\0'}},
},
bmo_bridge_loops_exec,
@@ -1021,6 +1022,28 @@ static BMOpDefine bmo_subdivide_edges_def = {
BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
};
/*
* Subdivide Edge-Ring.
*
* Take an edge-ring, and supdivide with interpolation options.
*/
static BMOpDefine bmo_subdivide_edgering_def = {
"subdivide_edgering",
/* slots_in */
{{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input vertices */
{"interp_mode", BMO_OP_SLOT_INT},
{"smooth", BMO_OP_SLOT_FLT},
{"cuts", BMO_OP_SLOT_INT},
{"profile_shape", BMO_OP_SLOT_INT},
{"profile_shape_factor", BMO_OP_SLOT_FLT},
{{'\0'}},
},
{{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */
{{'\0'}}}, /* no output */
bmo_subdivide_edgering_exec,
BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
};
/*
* Delete Geometry.
*
@@ -1756,6 +1779,7 @@ const BMOpDefine *bmo_opdefines[] = {
&bmo_split_def,
&bmo_split_edges_def,
&bmo_subdivide_edges_def,
&bmo_subdivide_edgering_def,
&bmo_symmetrize_def,
&bmo_transform_def,
&bmo_translate_def,

View File

@@ -61,6 +61,18 @@ enum {
SIM_CMP_LT
};
/* subdivide_edgering */
enum {
/* just subdiv */
SUBD_RING_INTERP_LINEAR,
/* single bezier spline - curve follows bezier rotation */
SUBD_RING_INTERP_PATH,
/* beziers based on adjacent faces (fallback to tangent) */
SUBD_RING_INTERP_SURF,
};
/* similar face selection slot values */
enum {
SIMFACE_MATERIAL = 201,

View File

@@ -97,6 +97,7 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op);
void bmo_split_edges_exec(BMesh *bm, BMOperator *op);
void bmo_split_exec(BMesh *bm, BMOperator *op);
void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op);
void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op);
void bmo_symmetrize_exec(BMesh *bm, BMOperator *op);
void bmo_transform_exec(BMesh *bm, BMOperator *op);
void bmo_translate_exec(BMesh *bm, BMOperator *op);

View File

@@ -1416,6 +1416,7 @@ BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2)
BMEdge *e;
BLI_assert(v1 != v2);
BLI_assert(v1->head.htype == BM_VERT && v2->head.htype == BM_VERT);
BM_ITER_ELEM (e, &iter, v1, BM_EDGES_OF_VERT) {
if (e->v1 == v2 || e->v2 == v2)
@@ -1756,3 +1757,27 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed)
return vol;
}
float bmesh_subd_falloff_calc(const int falloff, float val)
{
switch (falloff) {
case SUBD_FALLOFF_SMOOTH:
val = 3.0f * val * val - 2.0f * val * val * val;
break;
case SUBD_FALLOFF_SPHERE:
val = sqrtf(2.0f * val - val * val);
break;
case SUBD_FALLOFF_ROOT:
val = sqrtf(val);
break;
case SUBD_FALLOFF_SHARP:
val = val * val;
break;
case SUBD_FALLOFF_LIN:
break;
default:
BLI_assert(0);
}
return val;
}

View File

@@ -116,4 +116,7 @@ bool BM_face_is_any_edge_flag_test(BMFace *f, const char hflag);
float BM_mesh_calc_volume(BMesh *bm, bool is_signed);
/* not really any good place to put this */
float bmesh_subd_falloff_calc(const int falloff, float val);
#endif /* __BMESH_QUERIES_H__ */

View File

@@ -37,6 +37,7 @@
#include "intern/bmesh_operators_private.h" /* own include */
#define EDGE_MARK 4
#define EDGE_OUT 8
#define FACE_OUT 16
/* el_a and el_b _must_ be same size */
@@ -129,6 +130,15 @@ static void bm_bridge_best_rotation(struct BMEdgeLoopStore *el_store_a, struct B
}
}
static void bm_face_edges_tag_out(BMesh *bm, BMFace *f)
{
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT);
} while ((l_iter = l_iter->next) != l_first);
}
static bool bm_edge_test_cb(BMEdge *e, void *bm_v)
{
return BMO_elem_flag_test((BMesh *)bm_v, e, EDGE_MARK);
@@ -144,6 +154,7 @@ static void bridge_loop_pair(BMesh *bm,
int el_store_a_len, el_store_b_len;
bool el_store_b_free = false;
float el_dir[3];
const bool use_edgeout = true;
el_store_a_len = BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store_a);
el_store_b_len = BM_edgeloop_length_get((struct BMEdgeLoopStore *)el_store_b);
@@ -188,7 +199,7 @@ static void bridge_loop_pair(BMesh *bm,
for (i = 0; i < 2; i++, winding_dir = -winding_dir) {
LinkData *el;
for (el = BM_edgeloop_verts_get(estore_pair[i])->first; el; el = el->next) {
LinkData *el_next = BM_EDGELOOP_NEXT(estore_pair[i], el);
LinkData *el_next = BM_EDGELINK_NEXT(estore_pair[i], el);
if (el_next) {
BMEdge *e = BM_edge_exists(el->data, el_next->data);
if (e && BM_edge_is_boundary(e)) {
@@ -242,8 +253,8 @@ static void bridge_loop_pair(BMesh *bm,
BMLoop *l_2_next = NULL;
if (is_closed) {
el_a_next = BM_EDGELOOP_NEXT(el_store_a, el_a);
el_b_next = BM_EDGELOOP_NEXT(el_store_b, el_b);
el_a_next = BM_EDGELINK_NEXT(el_store_a, el_a);
el_b_next = BM_EDGELINK_NEXT(el_store_b, el_b);
}
else {
el_a_next = el_a->next;
@@ -309,6 +320,11 @@ static void bridge_loop_pair(BMesh *bm,
BMO_elem_flag_enable(bm, f, FACE_OUT);
BM_elem_flag_enable(f, BM_ELEM_TAG);
/* tag all edges of the face, untag the loop edges after */
if (use_edgeout) {
bm_face_edges_tag_out(bm, f);
}
if (el_a_next == el_a_first) {
break;
}
@@ -349,12 +365,52 @@ static void bridge_loop_pair(BMesh *bm,
BMO_op_initf(bm, &op_sub, 0,
"beautify_fill faces=%hf edges=ae use_restrict_tag=%b",
BM_ELEM_TAG, true);
if (use_edgeout) {
BMOIter siter;
BMFace *f;
BMO_ITER (f, &siter, op_sub.slots_in, "faces", BM_FACE) {
BMO_elem_flag_enable(bm, f, FACE_OUT);
bm_face_edges_tag_out(bm, f);
}
}
BMO_op_exec(bm, &op_sub);
/* there may also be tagged faces that didnt rotate, mark input */
BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "geom.out", BM_FACE, FACE_OUT);
if (use_edgeout) {
BMOIter siter;
BMFace *f;
BMO_ITER (f, &siter, op_sub.slots_out, "geom.out", BM_FACE) {
BMO_elem_flag_enable(bm, f, FACE_OUT);
bm_face_edges_tag_out(bm, f);
}
}
else {
BMO_slot_buffer_flag_enable(bm, op_sub.slots_out, "geom.out", BM_FACE, FACE_OUT);
}
BMO_op_finish(bm, &op_sub);
}
if (use_edgeout && use_merge == false) {
/* we've enabled all face edges above, now disable all loop edges */
struct BMEdgeLoopStore *estore_pair[2] = {el_store_a, el_store_b};
int i;
for (i = 0; i < 2; i++) {
LinkData *el;
for (el = BM_edgeloop_verts_get(estore_pair[i])->first; el; el = el->next) {
LinkData *el_next = BM_EDGELINK_NEXT(estore_pair[i], el);
if (el_next) {
if (el->data != el_next->data) {
BMEdge *e = BM_edge_exists(el->data, el_next->data);
BMO_elem_flag_disable(bm, e, EDGE_OUT);
}
}
}
}
}
if (el_store_b_free) {
BM_edgeloop_free(el_store_b);
}
@@ -434,22 +490,13 @@ void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op)
change = true;
}
if ((count == 2) && (BM_edgeloop_length_get(eloops.first) == BM_edgeloop_length_get(eloops.last))) {
}
else if (count == 2) {
}
else {
}
cleanup:
BM_mesh_edgeloops_free(&eloops);
if (change) {
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT);
if (use_merge == false) {
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "faces.out", BM_FACE, FACE_OUT);
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT);
}
}
}

View File

@@ -178,25 +178,7 @@ static void alter_co(BMesh *bm, BMVert *v, BMEdge *UNUSED(origed), const SubDPar
/* falloff for multi subdivide */
val = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
switch (params->smooth_falloff) {
case SUBD_FALLOFF_SMOOTH:
val = 3.0f * val * val - 2.0f * val * val * val;
break;
case SUBD_FALLOFF_SPHERE:
val = sqrtf(2.0f * val - val * val);
break;
case SUBD_FALLOFF_ROOT:
val = sqrtf(val);
break;
case SUBD_FALLOFF_SHARP:
val = val * val;
break;
case SUBD_FALLOFF_LIN:
break;
default:
BLI_assert(0);
}
val = bmesh_subd_falloff_calc(params->smooth_falloff, val);
mul_v3_fl(tvec, params->smooth * val * len);

File diff suppressed because it is too large Load Diff

View File

@@ -51,6 +51,8 @@
#include "BKE_main.h"
#include "BKE_editmesh.h"
#include "BLF_translation.h"
#include "RNA_define.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
@@ -143,6 +145,103 @@ void MESH_OT_subdivide(wmOperatorType *ot)
RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50);
}
/* -------------------------------------------------------------------- */
/* Edge Ring Subdiv
* (bridge code shares props)
*/
struct EdgeRingOpSubdProps {
int interp_mode;
int cuts;
float smooth;
int profile_shape;
float profile_shape_factor;
};
static void mesh_operator_edgering_props(wmOperatorType *ot, const int cuts_default)
{
/* Note, these values must match delete_mesh() event values */
static EnumPropertyItem prop_subd_edgering_types[] = {
{SUBD_RING_INTERP_LINEAR, "LINEAR", 0, "Linear", ""},
{SUBD_RING_INTERP_PATH, "PATH", 0, "Blend Path", ""},
{SUBD_RING_INTERP_SURF, "SURFACE", 0, "Blend Surface", ""},
{0, NULL, 0, NULL, NULL}
};
PropertyRNA *prop;
prop = RNA_def_int(ot->srna, "number_cuts", cuts_default, 0, INT_MAX, "Number of Cuts", "", 0, 64);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_enum(ot->srna, "interpolation", prop_subd_edgering_types, SUBD_RING_INTERP_PATH,
"Interpolation", "Interpolation method");
RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, FLT_MAX,
"Smoothness", "Smoothness factor", 0.0f, 2.0f);
/* profile-shape */
RNA_def_float(ot->srna, "profile_shape_factor", 0.0f, -FLT_MAX, FLT_MAX,
"Profile Factor", "", -2.0f, 2.0f);
prop = RNA_def_property(ot->srna, "profile_shape", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, proportional_falloff_curve_only_items);
RNA_def_property_enum_default(prop, PROP_SMOOTH);
RNA_def_property_ui_text(prop, "Profile Shape", "Shape of the profile");
RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
}
static void mesh_operator_edgering_props_get(wmOperator *op, struct EdgeRingOpSubdProps *op_props)
{
op_props->interp_mode = RNA_enum_get(op->ptr, "interpolation");
op_props->cuts = RNA_int_get(op->ptr, "number_cuts");
op_props->smooth = RNA_float_get(op->ptr, "smoothness");
op_props->profile_shape = RNA_enum_get(op->ptr, "profile_shape");
op_props->profile_shape_factor = RNA_float_get(op->ptr, "profile_shape_factor");
}
static int edbm_subdivide_edge_ring_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
struct EdgeRingOpSubdProps op_props;
mesh_operator_edgering_props_get(op, &op_props);
if (!EDBM_op_callf(em, op,
"subdivide_edgering edges=%he interp_mode=%i cuts=%i smooth=%f "
"profile_shape=%i profile_shape_factor=%f",
BM_ELEM_SELECT, op_props.interp_mode, op_props.cuts, op_props.smooth,
op_props.profile_shape, op_props.profile_shape_factor))
{
return OPERATOR_CANCELLED;
}
EDBM_update_generic(em, true, true);
return OPERATOR_FINISHED;
}
void MESH_OT_subdivide_edgering(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Subdivide Edge-Ring";
ot->description = "";
ot->idname = "MESH_OT_subdivide_edgering";
/* api callbacks */
ot->exec = edbm_subdivide_edge_ring_exec;
ot->poll = ED_operator_editmesh;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
mesh_operator_edgering_props(ot, 10);
}
static int edbm_unsubdivide_exec(bContext *C, wmOperator *op)
{
@@ -3823,6 +3922,22 @@ static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
"delete geom=%hf context=%i",
BM_ELEM_TAG, DEL_FACES);
}
if (use_merge == false) {
struct EdgeRingOpSubdProps op_props;
mesh_operator_edgering_props_get(op, &op_props);
if (op_props.cuts) {
/* we only need face normals updated */
EDBM_mesh_normals_update(em);
BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
"subdivide_edgering edges=%S interp_mode=%i cuts=%i smooth=%f "
"profile_shape=%i profile_shape_factor=%f",
&bmop, "edges.out", op_props.interp_mode, op_props.cuts, op_props.smooth,
op_props.profile_shape, op_props.profile_shape_factor);
}
}
}
if (totface_del_arr) {
@@ -3865,6 +3980,8 @@ void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_merge", false, "Merge", "Merge rather than creating faces");
RNA_def_float(ot->srna, "merge_factor", 0.5f, 0.0f, 1.0f, "Merge Factor", "", 0.0f, 1.0f);
mesh_operator_edgering_props(ot, 0);
}
static int edbm_wireframe_exec(bContext *C, wmOperator *op)

View File

@@ -159,6 +159,7 @@ extern struct EnumPropertyItem *corner_type_items;
/* *** editmesh_tools.c *** */
void MESH_OT_subdivide(struct wmOperatorType *ot);
void MESH_OT_subdivide_edgering(struct wmOperatorType *ot);
void MESH_OT_unsubdivide(struct wmOperatorType *ot);
void MESH_OT_normals_make_consistent(struct wmOperatorType *ot);
void MESH_OT_vertices_smooth(struct wmOperatorType *ot);

View File

@@ -62,6 +62,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_normals_make_consistent);
WM_operatortype_append(MESH_OT_merge);
WM_operatortype_append(MESH_OT_subdivide);
WM_operatortype_append(MESH_OT_subdivide_edgering);
WM_operatortype_append(MESH_OT_unsubdivide);
WM_operatortype_append(MESH_OT_faces_select_linked_flat);
WM_operatortype_append(MESH_OT_edges_select_sharp);