[Bf-blender-cvs] [bad96e5c7c7] sculpt-mode-features: Sculpt mask: Mask by normal operator

Pablo Dobarro noreply at git.blender.org
Mon Apr 22 01:10:04 CEST 2019


Commit: bad96e5c7c7ed721941e7bf0d96f4b2481052349
Author: Pablo Dobarro
Date:   Mon Apr 22 01:09:47 2019 +0200
Branches: sculpt-mode-features
https://developer.blender.org/rBbad96e5c7c7ed721941e7bf0d96f4b2481052349

Sculpt mask: Mask by normal operator

This is an experimental operator that can be used to generate mask for
faces in hard surface sculpts. It does not have UI and without undo
support the behaviour is unpredictable, but this code can be used to add
another automasking mode to the automasking system.

===================================================================

M	source/blender/editors/sculpt_paint/sculpt.c

===================================================================

diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index d7ded4e6995..129d191a924 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -7606,6 +7606,134 @@ void SCULPT_OT_color_fill(struct wmOperatorType *ot)
 	ot->flag = OPTYPE_REGISTER;
 }
 
+static int sculpt_mask_by_normal_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
+{
+	Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+	Object *ob = CTX_data_active_object(C);
+	SculptSession *ss = ob->sculpt;
+	ARegion *ar = CTX_wm_region(C);
+	PBVH *pbvh = ob->sculpt->pbvh;
+	struct Scene *scene = CTX_data_scene(C);
+	Depsgraph *depsgraph = CTX_data_depsgraph(C);
+	PBVHNode **nodes;
+	int totnode;
+
+	/* Disable for multires and dyntopo for now */
+	if (BKE_pbvh_type(pbvh) != PBVH_FACES) {
+		ss->use_orco = false;
+		return OPERATOR_CANCELLED;
+	}
+
+	/* Initial setup */
+	BKE_sculpt_update_mesh_elements(depsgraph, scene, sd, ob, true, true);
+
+	BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+	sculpt_undo_push_begin("Mask Coplanar");
+	for (int i = 0; i < totnode; i++) {
+		sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
+		BKE_pbvh_node_mark_redraw(nodes[i]);
+	}
+
+	/* Mask generation */
+	int init_vert = ss->active_vertex_mesh_index;
+
+	BLI_Stack *stack;
+	MVert *mvert = ss->mvert;
+	float threshold;
+	int *mvert_visited = MEM_callocN(ss->totvert * sizeof (int), "visited vertices");
+
+	threshold = RNA_float_get(op->ptr, "threshold");
+
+	stack = BLI_stack_new(sizeof(int), "verts stack");
+	BLI_stack_push(stack, &init_vert);
+
+	while(!BLI_stack_is_empty(stack)){
+		int vert;
+		BLI_stack_pop(stack, &vert);
+		MeshElemMap *vert_map = &ss->pmap[vert];
+		if(mvert_visited[vert] == 0) {
+			ss->vmask[vert] = 1.0f;
+			mvert[vert].flag |= ME_VERT_PBVH_UPDATE;
+			mvert_visited[vert] = 1;
+		}
+		int i = 0;
+		for (i = 0; i < ss->pmap[vert].count; i++) {
+			const MPoly *p = &ss->mpoly[vert_map->indices[i]];
+			unsigned f_adj_v[2];
+			if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
+				int j;
+				for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
+					if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
+						if(mvert_visited[f_adj_v[j]] == 0){
+							mvert_visited[f_adj_v[j]] = 1;
+							float original_normal[3];
+							float new_normal[3];
+							normal_short_to_float_v3(original_normal, mvert[vert].no);
+							normal_short_to_float_v3(new_normal, mvert[f_adj_v[j]].no);
+							if (dot_v3v3(original_normal, new_normal) > threshold) {
+								ss->vmask[f_adj_v[j]] = dot_v3v3(original_normal, new_normal);
+								mvert[f_adj_v[j]].flag |= ME_VERT_PBVH_UPDATE;
+								BLI_stack_push(stack, &f_adj_v[j]);
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	MEM_freeN(mvert_visited);
+
+	/* Smooth iterations */
+	SculptThreadedTaskData data = {
+	    .sd = sd, .ob = ob, .nodes = nodes,  .smooth_value = 0.5f, .filter_type = MASK_FILTER_BLUR,
+	};
+
+	int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
+	for (int i = 0; i < smooth_iterations; i++) {
+		ParallelRangeSettings settings;
+		BLI_parallel_range_settings_defaults(&settings);
+		settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+		BLI_task_parallel_range(
+			    0, totnode,
+			    &data,
+			    mask_filter_task_cb,
+			    &settings);
+	}
+
+	/* Invert mask */
+	if (RNA_boolean_get(op->ptr, "invert")) {
+		for (int i = 0; i < ss->totvert; i++) {
+			ss->vmask[i] = 1.0f - ss->vmask[i];
+		}
+	}
+
+	sculpt_undo_push_end();
+	ED_region_tag_redraw(ar);
+
+	WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+	return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_mask_by_normal(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Mask by normal";
+	ot->idname = "SCULPT_OT_mask_by_normal";
+	ot->description = "Creates a mask limited by the normal difference of the vertices";
+
+	/* api callbacks */
+	ot->invoke = sculpt_mask_by_normal_invoke;
+	ot->poll = sculpt_mode_poll;
+
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+	ot->prop = RNA_def_float(ot->srna, "threshold", 0.9993f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
+	ot->prop = RNA_def_int(ot->srna, "smooth_iterations", 2, 0, 10, "Smooth iterations", "", 0, 10);
+	ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "");
+}
+
+
 
 
 void ED_operatortypes_sculpt(void)
@@ -7623,4 +7751,5 @@ void ED_operatortypes_sculpt(void)
 	WM_operatortype_append(SCULPT_OT_mesh_filter);
 	WM_operatortype_append(SCULPT_OT_mask_filter);
 	WM_operatortype_append(SCULPT_OT_color_fill);
+	WM_operatortype_append(SCULPT_OT_mask_by_normal);
 }



More information about the Bf-blender-cvs mailing list