[Bf-blender-cvs] [ad5ac8c833c] sculpt-mode-features: Mask filter: Dirty and constrast mask filters

Pablo Dobarro noreply at git.blender.org
Fri Jun 7 16:28:17 CEST 2019


Commit: ad5ac8c833caa0c902054ba7e7dddf926769cd82
Author: Pablo Dobarro
Date:   Fri Jun 7 16:27:59 2019 +0200
Branches: sculpt-mode-features
https://developer.blender.org/rBad5ac8c833caa0c902054ba7e7dddf926769cd82

Mask filter: Dirty and constrast mask filters

The funcionality should be the same as the dirty vertex colors operator.
This filter can be used to generate cavity mask for sculpting and
painting. I also added a contrast filter to control the cavity mask.
The contrast filter can be implemented with a real time preview in a
future version instead of incrementing the contrast with fixed steps.

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

M	release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/editors/sculpt_paint/sculpt_intern.h

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

diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index a1a0f7cd636..5ce53e3990d 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -979,6 +979,7 @@ class _defs_sculpt:
             sub.use_property_split = False
             sub.prop(props, "type", expand=False)
             sub.prop(props, "iterations")
+            sub.prop(props, "dirty_only")
 
         return dict(
             idname="builtin.mask_filter",
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 9dc592c51f5..d22750c1f89 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1674,6 +1674,43 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
   }
 }
 
+static float neighbor_dirty_mask(SculptSession *ss, const int vert)
+{
+  const MeshElemMap *vert_map = &ss->pmap[vert];
+  const MVert *mvert = ss->mvert;
+
+  int i = 0;
+  int total = 0;
+  float avg[3];
+  zero_v3(avg);
+  for (i = 0; i < vert_map->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) {
+        float normalized[3];
+        sub_v3_v3v3(normalized, mvert[f_adj_v[j]].co, mvert[vert].co);
+        normalize_v3(normalized);
+        add_v3_v3(avg, normalized);
+        total++;
+      }
+    }
+  }
+  if (total > 0) {
+    mul_v3_fl(avg, 1.0f / total);
+    float normal[3];
+    normal_short_to_float_v3(normal, mvert[vert].no);
+    float dot = dot_v3v3(avg, normal);
+    float ang = acos(dot);
+    if (ang < DEG2RAD(0)) {
+      ang = DEG2RAD(0);
+    }
+    return ang;
+  }
+  return 0;
+}
+
 static float neighbor_min_mask(SculptSession *ss, const int vert, float *prev_mask)
 {
   const MeshElemMap *vert_map = &ss->pmap[vert];
@@ -8221,6 +8258,8 @@ typedef enum eSculptMaskFilterTypes {
   MASK_FILTER_SHARPEN = 1,
   MASK_FILTER_GROW = 2,
   MASK_FILTER_SHRINK = 3,
+  MASK_FILTER_DIRTY = 4,
+  MASK_FILTER_CONTRAST = 5,
 } eSculptMaskFilterTypes;
 
 EnumPropertyItem prop_mask_filter_types[] = {
@@ -8228,6 +8267,8 @@ EnumPropertyItem prop_mask_filter_types[] = {
     {MASK_FILTER_SHARPEN, "SHARPEN", 0, "Sharpen Mask", "Sharpen mask"},
     {MASK_FILTER_GROW, "GROW", 0, "Grow Mask", "Grow mask"},
     {MASK_FILTER_SHRINK, "SHRINK", 0, "Shrink Mask", "Shrink mask"},
+    {MASK_FILTER_DIRTY, "DIRTY", 0, "Dirty Mask", "Dirty mask"},
+    {MASK_FILTER_CONTRAST, "CONTRAST", 0, "Contrast Mask", "Contrast mask"},
     {0, NULL, 0, NULL, NULL},
 };
 
@@ -8246,6 +8287,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
   BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
   {
     float val;
+    float contrast, delta, gain, offset;
     switch (mode) {
       case MASK_FILTER_BLUR:
         if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
@@ -8287,6 +8329,28 @@ static void mask_filter_task_cb(void *__restrict userdata,
           CLAMP(*vd.mask, 0.0f, 1.0f);
         }
         break;
+      case MASK_FILTER_DIRTY:
+        if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
+          val = neighbor_dirty_mask(ss, vd.vert_indices[vd.i]);
+          data->prev_mask[vd.vert_indices[vd.i]] = val;
+        }
+        break;
+      case MASK_FILTER_CONTRAST:
+        if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
+          contrast = 0.1;
+          delta = contrast / 2.0f;
+          gain = 1.0f - delta * 2.0f;
+          if (contrast > 0) {
+            gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
+            offset = gain * (-delta);
+          }
+          else {
+            delta *= -1;
+            offset = gain * (delta);
+          }
+          *vd.mask = gain * (*vd.mask) + offset;
+        }
+        break;
     }
     if (vd.mvert)
       vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@@ -8332,8 +8396,12 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
     sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
   }
 
+  if (mode == MASK_FILTER_DIRTY) {
+    iterations = 1;
+  }
+
   for (int i = 0; i < iterations; i++) {
-    if (ELEM(mode, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
+    if (ELEM(mode, MASK_FILTER_GROW, MASK_FILTER_SHRINK, MASK_FILTER_DIRTY)) {
       prev_mask = MEM_dupallocN(ss->vmask);
     }
 
@@ -8355,6 +8423,38 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
       MEM_freeN(prev_mask);
   }
 
+  if (mode == MASK_FILTER_DIRTY) {
+    float min = FLT_MAX;
+    float max = FLT_MIN;
+    for (int i = 0; i < ss->totvert; i++) {
+      float val = prev_mask[i];
+      if (val < min) {
+        min = val;
+      }
+      if (val > max) {
+        max = val;
+      }
+    }
+
+    float range = max - min;
+    if (range < 0.0001f) {
+      range = 0;
+    }
+    else {
+      range = 1.0f / range;
+    }
+
+    bool dirty_only = RNA_boolean_get(op->ptr, "dirty_only");
+    for (int i = 0; i < ss->totvert; i++) {
+      ss->vmask[i] += 1 - ((prev_mask[i] - min) * range);
+      if (dirty_only) {
+        ss->vmask[i] = fmin(ss->vmask[i], 0.5) * 2.0f;
+      }
+      CLAMP(ss->vmask[i], 0.0f, 1.0f);
+    }
+    MEM_freeN(prev_mask);
+  }
+
   sculpt_undo_push_end();
 
   if (nodes)
@@ -8383,6 +8483,7 @@ void SCULPT_OT_mask_filter(struct wmOperatorType *ot)
   /* rna */
   ot->prop = RNA_def_enum(ot->srna, "type", prop_mask_filter_types, MASK_FILTER_BLUR, "Type", "");
   ot->prop = RNA_def_int(ot->srna, "iterations", 1, 1, 100, "Iterations", "", 1, 50);
+  ot->prop = RNA_def_boolean(ot->srna, "dirty_only", false, "Dirty Only", "");
 }
 
 static void do_color_fill_task_cb(void *__restrict userdata,
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 2f83a12c8b6..dedbcc59ef2 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -303,6 +303,8 @@ typedef struct FilterCache {
   /* unmasked nodes */
   PBVHNode **nodes;
   int totnode;
+
+  float *dirty_mask;
 } FilterCache;
 
 typedef struct StrokeCache {



More information about the Bf-blender-cvs mailing list