[Bf-blender-cvs] [45bc21e7e21] greasepencil-object: GPencil: Redesign input samples management

Antonio Vazquez noreply at git.blender.org
Tue Oct 15 12:47:51 CEST 2019


Commit: 45bc21e7e21d64926b2e559168e58c9ec4b3d68a
Author: Antonio Vazquez
Date:   Tue Oct 15 12:47:35 2019 +0200
Branches: greasepencil-object
https://developer.blender.org/rB45bc21e7e21d64926b2e559168e58c9ec4b3d68a

GPencil: Redesign input samples management

Now, instead to generate fake events in a linear interpolation and try to smooth the line later, an arc is created between the points and try to reproduce the ballistic trajectory of the mouse/pen. This gets better results and especially when the mouse moves very fast getting a more organic result.

Also, the input samples maximum has been changed to 15.

Note: Still we need to test DOT materials to define if the samples are getting good result of we must make more dense the number of points for these materials.

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

M	source/blender/editors/gpencil/gpencil_paint.c
M	source/blender/editors/include/ED_gpencil.h
M	source/blender/makesdna/DNA_gpencil_types.h

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

diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 2d494ffeab6..39ab2099e39 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -659,117 +659,90 @@ static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int t
     tGPspoint *ptd = &points[i];
 
     float sco[2] = {0.0f};
+    float pressure = 0.0f;
+    float strength = 0.0f;
 
     /* Compute smoothed coordinate by taking the ones nearby */
     if (pta) {
       madd_v2_v2fl(sco, &pta->x, average_fac);
+      pressure += pta->pressure * average_fac;
+      strength += pta->strength * average_fac;
     }
     else {
       madd_v2_v2fl(sco, &ptc->x, average_fac);
+      pressure += ptc->pressure * average_fac;
+      strength += ptc->strength * average_fac;
     }
 
     if (ptb) {
       madd_v2_v2fl(sco, &ptb->x, average_fac);
+      pressure += ptb->pressure * average_fac;
+      strength += ptb->strength * average_fac;
     }
     else {
       madd_v2_v2fl(sco, &ptc->x, average_fac);
+      pressure += ptc->pressure * average_fac;
+      strength += ptc->strength * average_fac;
     }
 
     madd_v2_v2fl(sco, &ptc->x, average_fac);
+    pressure += ptc->pressure * average_fac;
+    strength += ptc->strength * average_fac;
 
     madd_v2_v2fl(sco, &ptd->x, average_fac);
+    pressure += ptd->pressure * average_fac;
+    strength += ptd->strength * average_fac;
 
     /* Based on influence factor, blend between original and optimal smoothed coordinate. */
     interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf);
-  }
-}
 
-/* Smooth all the sections created with fake events to avoid abrupt transitions.
- *
- * As the fake events add points between two real events, this produces a straight line, but if
- * there is 3 or more real points that used fakes, the stroke is not smooth and produces abrupt
- * angles.
- * This function reads these segments and finds the real points and smooth with the surrounding
- * points. */
-static void gp_smooth_fake_segments(tGPsdata *p)
-{
-  bGPdata *gpd = p->gpd;
-  Brush *brush = p->brush;
-
-  if (brush->gpencil_settings->input_samples < 2) {
-    return;
-  }
-
-  tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
-  tGPspoint *pt = NULL;
-  /* Index where segment starts. */
-  int from_idx = 0;
-  /* Index where segment ends. */
-  int to_idx = 0;
-
-  bool doit = false;
-  /* Loop all points except the extremes. */
-  for (int i = 1; i < gpd->runtime.sbuffer_used - 1; i++) {
-    pt = &points[i];
-    bool is_fake = (bool)(pt->tflag & GP_TPOINT_FAKE);
-    to_idx = i;
-
-    /* Detect fake points in the stroke. */
-    if ((!doit) && (is_fake)) {
-      from_idx = i;
-      doit = true;
-    }
-    /* If detect control point after fake points, select a segment with same length in both sides,
-     * except if it is more than stroke length. */
-    if ((doit) && (!is_fake)) {
-      if (i + (i - from_idx) < gpd->runtime.sbuffer_used - 1) {
-        to_idx = i + (i - from_idx);
-        /* Smooth this segments (need loop to get cumulative smooth). */
-        for (int r = 0; r < 5; r++) {
-          /* The factor is divided because a value > 0.5f is too aggressive, but in the UI is
-           * better to keep the range from 0.0f to 1.0f for usability reasons. */
-          gp_smooth_segment(gpd, brush->gpencil_settings->smart_smooth * 0.5f, from_idx, to_idx);
-        }
-      }
-      else {
-        break;
-      }
-      /* Reset to new segments. */
-      from_idx = i;
-      doit = false;
-    }
+    /* Interpolate pressure. */
+    ptc->pressure = interpf(ptc->pressure, pressure, inf);
+    /* Interpolate strength. */
+    ptc->strength = interpf(ptc->strength, strength, inf);
   }
 }
 
-static void gp_add_arc_segments(tGPsdata *p)
+/* Add arc points between two mouse events using the previous segment to determine the vertice of
+ * the arc.
+ *        /* CTL
+ *       / |
+ *      /  |
+ * PtA +...|...+ PtB
+ *    /
+ *   /
+ *  + PtA - 1
+ * /
+ * CTL is the vertice of the triangle created between PtA and PtB */
+static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
 {
-  const int segments = 4;
-  const float minlen_sq = 20.0f * 20.0f;
   bGPdata *gpd = p->gpd;
-  // Brush *brush = p->brush;
   if (gpd->runtime.sbuffer_used < 3) {
     return;
   }
 
-  int idx = gpd->runtime.sbuffer_used;
+  int idx_old = gpd->runtime.sbuffer_used;
+
+  /* Add space for new arc points. */
+  gpd->runtime.sbuffer_used += segments - 1;
+
+  /* Check if still room in buffer or add more. */
+  gpd->runtime.sbuffer = ED_gpencil_sbuffer_ensure(
+      gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, false);
+
   tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
   tGPspoint *pt = NULL;
-  tGPspoint *pt_before = &points[idx - 3]; /* current - 2 */
-  tGPspoint *pt_prev = &points[idx - 2];   /* previous */
-  tGPspoint *pt_cur = &points[idx - 1];    /* actual */
+  tGPspoint *pt_before = &points[idx_old - 1]; /* current - 2 */
+  tGPspoint *pt_prev = &points[idx_old - 2];   /* previous */
 
   /* Create two vectors, previous and half way of the actual to get the vertex of the triangle for
    * arc curve.
    */
   float v_prev[2], v_cur[2], v_half[2];
-  sub_v2_v2v2(v_cur, &pt_cur->x, &pt_prev->x);
-  /* Do not add points to very short segments. */
-  if (len_squared_v2(v_cur) < minlen_sq) {
-    return;
-  }
+  sub_v2_v2v2(v_cur, mval, &pt_prev->x);
 
   sub_v2_v2v2(v_prev, &pt_prev->x, &pt_before->x);
-  interp_v2_v2v2(v_half, &pt_prev->x, &pt_cur->x, 0.5f);
+  interp_v2_v2v2(v_half, &pt_prev->x, mval, 0.5f);
   sub_v2_v2(v_half, &pt_prev->x);
 
   /* Project the half vector to the previous vector and calculate the mid projected point. */
@@ -783,83 +756,33 @@ static void gp_add_arc_segments(tGPsdata *p)
   float ctl[2];
   add_v2_v2v2(ctl, &pt_prev->x, v_prev);
 
-  /* Move last buffer point and add space for new arc points. */
-  gpd->runtime.sbuffer_used += segments;
-  pt = &points[gpd->runtime.sbuffer_used - 1];
-
-  copy_v2_v2(&pt->x, &pt_cur->x);
-  pt->pressure = pt_cur->pressure;
-  pt->strength = pt_cur->strength;
-
   float step = M_PI_2 / (float)(segments + 1);
   float a = step;
 
   float midpoint[2], start[2], end[2], cp1[2], corner[2];
-  mid_v2_v2v2(midpoint, &pt_prev->x, &pt_cur->x);
+  mid_v2_v2v2(midpoint, &pt_prev->x, mval);
   copy_v2_v2(start, &pt_prev->x);
-  copy_v2_v2(end, &pt_cur->x);
+  copy_v2_v2(end, mval);
   copy_v2_v2(cp1, ctl);
 
   corner[0] = midpoint[0] - (cp1[0] - midpoint[0]);
   corner[1] = midpoint[1] - (cp1[1] - midpoint[1]);
 
-  float fi = 1.0f / (float)(segments + 1.0f);
   for (int i = 0; i < segments; i++) {
-    pt = &points[idx + i - 1];
+    pt = &points[idx_old + i - 1];
     pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
     pt->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
 
-    /* Interpolate values */
-    float f = fi * (float)(i + 1.0f);
-    pt->pressure = interpf(pt_cur->pressure, pt_prev->pressure, f);
-    pt->strength = interpf(pt_cur->strength, pt_prev->strength, f);
+    /* Set pressure and strength equals to previous. It will be smoothed later. */
+    pt->pressure = pt_prev->pressure;
+    pt->strength = pt_prev->strength;
 
     a += step;
   }
 }
 
-/* Smooth the section added with fake events when pen moves very fast. */
-static void gp_smooth_fake_events(tGPsdata *p, int size_before, int size_after)
-{
-  bGPdata *gpd = p->gpd;
-  const short totpoints = size_after - size_before - 1;
-  /* Do nothing if not enough data to smooth out. */
-  if (totpoints < 1) {
-    return;
-  }
-
-  /* Back two points to get smoother effect. */
-  size_before -= 2;
-  CLAMP_MIN(size_before, 1);
-
-  tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
-  /* Extreme points. */
-  const tGPspoint *pta = &points[size_before - 1];
-  const tGPspoint *ptb = &points[size_after - 1];
-  tGPspoint *pt1, *pt2;
-  int i;
-
-  /* Get total length of the segment to smooth. */
-  float totlen = 0.0f;
-  for (i = size_before; i < size_after; i++) {
-    pt1 = &points[i - 1];
-    pt2 = &points[i];
-    totlen += len_v2v2(&pt1->x, &pt2->x);
-  }
-  /* Smooth interpolating the position of the points. */
-  float pointlen = 0.0f;
-  for (i = size_before; i < size_after - 1; i++) {
-    pt1 = &points[i - 1];
-    pt2 = &points[i];
-    pointlen += len_v2v2(&pt1->x, &pt2->x);
-    pt2->pressure = interpf(ptb->pressure, pta->pressure, pointlen / totlen);
-    pt2->strength = interpf(ptb->strength, pta->strength, pointlen / totlen);
-  }
-}
-
 /* add current stroke-point to buffer (returns whether point was successfully added) */
-static short gp_stroke_addpoint(
-    tGPsdata *p, const float mval[2], float pressure, double curtime, bool is_fake)
+static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
 {
   bGPdata *gpd = p->gpd;
   Brush *brush = p->brush;
@@ -918,14 +841,6 @@ static short gp_stroke_addpoint(
     /* get pointer to destination point */
     pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
 
-    /* Set if point was created by fake events. */
-    if (is_fake) {
-      pt->tflag |= GP_TPOINT_FAKE;
-    }
-    else {
-      pt->tflag &= ~GP_TPOINT_FAKE;
-    }
-
     /* store settings */
     /* pressure */
     if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
@@ -1438,11 +1353,6 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
       }
     }
 
-    /* Smooth any point created with fake events when the mouse/pen move very fast. */
-    if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) == 0) {
-      gp_smooth_fake_segments(p);
-    }
-
     pt = gps->points;
     dvert = gps->dvert;
 
@@ -2826,8 +2736,7 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
 /* ------------------------------- */
 
 /* create a new stroke point at the point indicated by the painting context */
-static void gpencil_draw_apply(
-    bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph, bool is_fake)
+static void gpencil_draw_apply(bContext *C, w

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list