Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_gpencil_geom.h58
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc467
-rw-r--r--source/blender/blenloader/intern/versioning_300.c18
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c31
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c11
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c30
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c26
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c8
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c10
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c77
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_brush.c5
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c7
14 files changed, 442 insertions, 309 deletions
diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h
index 4127030e96f..ad3b1971ca9 100644
--- a/source/blender/blenkernel/BKE_gpencil_geom.h
+++ b/source/blender/blenkernel/BKE_gpencil_geom.h
@@ -220,30 +220,78 @@ bool BKE_gpencil_stroke_sample(struct bGPdata *gpd,
* \param gps: Stroke to smooth
* \param i: Point index
* \param inf: Amount of smoothing to apply
+ * \param iterations: Radius of points to consider, equivalent to iterations
* \param smooth_caps: Apply smooth to stroke extremes
+ * \param keep_shape: Smooth out fine details first
+ * \param r_gps: Stroke to put the result into
*/
-bool BKE_gpencil_stroke_smooth_point(struct bGPDstroke *gps, int i, float inf, bool smooth_caps);
+bool BKE_gpencil_stroke_smooth_point(struct bGPDstroke *gps,
+ int point_index,
+ float influence,
+ int iterations,
+ bool smooth_caps,
+ bool keep_shape,
+ struct bGPDstroke *r_gps);
/**
* Apply smooth strength to stroke point.
* \param gps: Stroke to smooth
* \param point_index: Point index
* \param influence: Amount of smoothing to apply
+ * \param iterations: Radius of points to consider, equivalent to iterations
+ * \param r_gps: Stroke to put the result into
*/
-bool BKE_gpencil_stroke_smooth_strength(struct bGPDstroke *gps, int point_index, float influence);
+bool BKE_gpencil_stroke_smooth_strength(struct bGPDstroke *gps,
+ int point_index,
+ float influence,
+ int iterations,
+ struct bGPDstroke *r_gps);
/**
* Apply smooth for thickness to stroke point (use pressure).
* \param gps: Stroke to smooth
* \param point_index: Point index
* \param influence: Amount of smoothing to apply
+ * \param iterations: Radius of points to consider, equivalent to iterations
+ * \param r_gps: Stroke to put the result into
*/
-bool BKE_gpencil_stroke_smooth_thickness(struct bGPDstroke *gps, int point_index, float influence);
+bool BKE_gpencil_stroke_smooth_thickness(struct bGPDstroke *gps,
+ int point_index,
+ float influence,
+ int iterations,
+ struct bGPDstroke *r_gps);
/**
- * Apply smooth for UV rotation to stroke point (use pressure).
+ * Apply smooth for UV rotation/factor to stroke point.
* \param gps: Stroke to smooth
* \param point_index: Point index
* \param influence: Amount of smoothing to apply
+ * \param iterations: Radius of points to consider, equivalent to iterations
+ * \param r_gps: Stroke to put the result into
*/
-bool BKE_gpencil_stroke_smooth_uv(struct bGPDstroke *gps, int point_index, float influence);
+bool BKE_gpencil_stroke_smooth_uv(struct bGPDstroke *gps,
+ int point_index,
+ float influence,
+ int iterations,
+ struct bGPDstroke *r_gps);
+/**
+ * Apply smooth operation to the stroke.
+ * \param gps: Stroke to smooth
+ * \param influence: The interpolation factor for the smooth and the original stroke
+ * \param iterations: Radius of points to consider, equivalent to iterations
+ * \param smooth_position: Smooth point locations
+ * \param smooth_strength: Smooth point strength
+ * \param smooth_thickness: Smooth point thickness
+ * \param smooth_uv: Smooth uv rotation/factor
+ * \param keep_shape: Use different distribution for smooth locations to keep the shape
+ * \param weights: per point weights to multiply influence with (optional, can be null)
+ */
+void BKE_gpencil_stroke_smooth(struct bGPDstroke *gps,
+ const float influence,
+ const int iterations,
+ const bool smooth_position,
+ const bool smooth_strength,
+ const bool smooth_thickness,
+ const bool smooth_uv,
+ const bool keep_shape,
+ const float *weights);
/**
* Close grease pencil stroke.
* \param gps: Stroke to close
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index a5eff1f9d5a..a0b6ab2d654 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -980,74 +980,116 @@ bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist, const short mo
/** \name Stroke Smooth Positions
* \{ */
-bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf, const bool smooth_caps)
+bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps,
+ int i,
+ float influence,
+ int iterations,
+ const bool smooth_caps,
+ const bool keep_shape,
+ bGPDstroke *r_gps)
{
- bGPDspoint *pt = &gps->points[i];
- float sco[3] = {0.0f};
- const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
-
- /* Do nothing if not enough points to smooth out */
- if (gps->totpoints <= 2) {
+ /* If nothing to do, return early */
+ if (gps->totpoints <= 2 || iterations <= 0) {
return false;
}
- /* Only affect endpoints by a fraction of the normal strength,
- * to prevent the stroke from shrinking too much
+ /* Overview of the algorithm here and in the following smooth functions:
+ * The smooth functions return the new attribute in question for a single point.
+ * The result is stored in r_gps->points[i], while the data is read from gps.
+ * To get a correct result, duplicate the stroke point data and read from the copy,
+ * while writing to the real stroke. Not doing that will result in acceptable, but
+ * asymmetric results.
+ * This algorithm works as long as all points are being smoothed. If there is
+ * points that should not get smoothed, use the old repeat smooth pattern with
+ * the parameter "iterations" set to 1 or 2. (2 matches the old algorithm).
*/
- if ((!smooth_caps) && (!is_cyclic && ELEM(i, 0, gps->totpoints - 1))) {
- inf *= 0.1f;
- }
-
- /* Compute smoothed coordinate by taking the ones nearby */
- /* XXX: This is potentially slow,
- * and suffers from accumulation error as earlier points are handled before later ones. */
- {
- /* XXX: this is hardcoded to look at 2 points on either side of the current one
- * (i.e. 5 items total). */
- const int steps = 2;
- const float average_fac = 1.0f / (float)(steps * 2 + 1);
- int step;
-
- /* add the point itself */
- madd_v3_v3fl(sco, &pt->x, average_fac);
-
- /* n-steps before/after current point */
- /* XXX: review how the endpoints are treated by this algorithm. */
- /* XXX: falloff measures should also introduce some weighting variations,
- * so that further-out points get less weight. */
- for (step = 1; step <= steps; step++) {
- bGPDspoint *pt1, *pt2;
- int before = i - step;
- int after = i + step;
-
- if (is_cyclic) {
- if (before < 0) {
- /* Sub to end point (before is already negative). */
- before = gps->totpoints + before;
- CLAMP(before, 0, gps->totpoints - 1);
- }
- if (after > gps->totpoints - 1) {
- /* Add to start point. */
- after = after - gps->totpoints;
- CLAMP(after, 0, gps->totpoints - 1);
+
+ const bGPDspoint *pt = &gps->points[i];
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
+ /* If smooth_caps is false, the caps will not be translated by smoothing. */
+ if (!smooth_caps && !is_cyclic && ELEM(i, 0, gps->totpoints - 1)) {
+ copy_v3_v3(&r_gps->points[i].x, &pt->x);
+ return true;
+ }
+
+ /* This function uses a binomial kernel, which is the discrete version of gaussian blur.
+ * The weight for a vertex at the relative index i is
+ * w = nCr(n, j + n/2) / 2^n = (n/1 * (n-1)/2 * ... * (n-j-n/2)/(j+n/2)) / 2^n
+ * All weights together sum up to 1
+ * This is equivalent to doing multiple iterations of averaging neighbors,
+ * where n = iterations * 2 and -n/2 <= j <= n/2
+ *
+ * Now the problem is that nCr(n, j + n/2) is very hard to compute for n > 500, since even
+ * double precision isn't sufficient. A very good robust approximation for n > 20 is
+ * nCr(n, j + n/2) / 2^n = sqrt(2/(pi*n)) * exp(-2*j*j/n)
+ *
+ * There is one more problem left: The old smooth algorithm was doing a more aggressive
+ * smooth. To solve that problem, choose a different n/2, which does not match the range and
+ * normalize the weights on finish. This may cause some artifacts at low values.
+ *
+ * keep_shape is a new option to stop the stroke from severly deforming.
+ * It uses different partially negative weights.
+ * w = 2 * (nCr(n, j + n/2) / 2^n) - (nCr(3*n, j + n) / 2^(3*n))
+ * ~ 2 * sqrt(2/(pi*n)) * exp(-2*j*j/n) - sqrt(2/(pi*3*n)) * exp(-2*j*j/(3*n))
+ * All weigths still sum up to 1.
+ * Note these weights only work because the averaging is done in relative coordinates.
+ */
+ float sco[3] = {0.0f, 0.0f, 0.0f};
+ float tmp[3];
+ const int n_half = keep_shape ? (iterations * iterations) / 8 + iterations :
+ (iterations * iterations) / 4 + 2 * iterations + 12;
+ double w = keep_shape ? 2.0 : 1.0;
+ double w2 = keep_shape ?
+ (1.0 / M_SQRT3) * exp((2 * iterations * iterations) / (double)(n_half * 3)) :
+ 0.0;
+ double total_w = 0.0;
+ for (int step = iterations; step > 0; step--) {
+ int before = i - step;
+ int after = i + step;
+ float w_before = (float)(w - w2);
+ float w_after = (float)(w - w2);
+
+ if (is_cyclic) {
+ before = (before % gps->totpoints + gps->totpoints) % gps->totpoints;
+ after = after % gps->totpoints;
+ }
+ else {
+ if (before < 0) {
+ if (!smooth_caps) {
+ w_before *= -before / (float)i;
}
+ before = 0;
}
- else {
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
+ if (after > gps->totpoints - 1) {
+ if (!smooth_caps) {
+ w_after *= (after - (gps->totpoints - 1)) / (float)(gps->totpoints - 1 - i);
+ }
+ after = gps->totpoints - 1;
}
+ }
- pt1 = &gps->points[before];
- pt2 = &gps->points[after];
+ /* Add both these points in relative coordinates to the weighted average sum. */
+ sub_v3_v3v3(tmp, &gps->points[before].x, &pt->x);
+ madd_v3_v3fl(sco, tmp, w_before);
+ sub_v3_v3v3(tmp, &gps->points[after].x, &pt->x);
+ madd_v3_v3fl(sco, tmp, w_after);
- /* add both these points to the average-sum (s += p[i]/n) */
- madd_v3_v3fl(sco, &pt1->x, average_fac);
- madd_v3_v3fl(sco, &pt2->x, average_fac);
- }
+ total_w += w_before;
+ total_w += w_after;
+
+ w *= (n_half + step) / (double)(n_half + 1 - step);
+ w2 *= (n_half * 3 + step) / (double)(n_half * 3 + 1 - step);
}
+ total_w += w - w2;
+ /* The accumulated weight total_w should be
+ * ~sqrt(M_PI * n_half) * exp((iterations * iterations) / n_half) < 100
+ * here, but sometimes not quite. */
+ mul_v3_fl(sco, (float)(1.0 / total_w));
+ /* Shift back to global coordinates. */
+ add_v3_v3(sco, &pt->x);
- /* Based on influence factor, blend between original and optimal smoothed coordinate */
- interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
+ /* Based on influence factor, blend between original and optimal smoothed coordinate. */
+ interp_v3_v3v3(&r_gps->points[i].x, &pt->x, sco, influence);
return true;
}
@@ -1058,74 +1100,54 @@ bool BKE_gpencil_stroke_smooth_point(bGPDstroke *gps, int i, float inf, const bo
/** \name Stroke Smooth Strength
* \{ */
-bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float influence)
+bool BKE_gpencil_stroke_smooth_strength(
+ bGPDstroke *gps, int i, float influence, int iterations, bGPDstroke *r_gps)
{
- bGPDspoint *ptb = &gps->points[point_index];
- const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
-
- /* Do nothing if not enough points */
- if ((gps->totpoints <= 2) || (point_index < 1)) {
+ /* If nothing to do, return early */
+ if (gps->totpoints <= 2 || iterations <= 0) {
return false;
}
- /* Only affect endpoints by a fraction of the normal influence */
- float inf = influence;
- if (!is_cyclic && ELEM(point_index, 0, gps->totpoints - 1)) {
- inf *= 0.01f;
- }
- /* Limit max influence to reduce pop effect. */
- CLAMP_MAX(inf, 0.98f);
-
- float total = 0.0f;
- float max_strength = 0.0f;
- const int steps = 4;
- const float average_fac = 1.0f / (float)(steps * 2 + 1);
- int step;
- /* add the point itself */
- total += ptb->strength * average_fac;
- max_strength = ptb->strength;
+ /* See BKE_gpencil_stroke_smooth_point for details on the algorithm. */
- /* n-steps before/after current point */
- for (step = 1; step <= steps; step++) {
- bGPDspoint *pt1, *pt2;
- int before = point_index - step;
- int after = point_index + step;
+ const bGPDspoint *pt = &gps->points[i];
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
+ float strength = 0.0f;
+ const int n_half = (iterations * iterations) / 4 + iterations;
+ double w = 1.0;
+ double total_w = 0.0;
+ for (int step = iterations; step > 0; step--) {
+ int before = i - step;
+ int after = i + step;
+ float w_before = (float)w;
+ float w_after = (float)w;
if (is_cyclic) {
- if (before < 0) {
- /* Sub to end point (before is already negative). */
- before = gps->totpoints + before;
- CLAMP(before, 0, gps->totpoints - 1);
- }
- if (after > gps->totpoints - 1) {
- /* Add to start point. */
- after = after - gps->totpoints;
- CLAMP(after, 0, gps->totpoints - 1);
- }
+ before = (before % gps->totpoints + gps->totpoints) % gps->totpoints;
+ after = after % gps->totpoints;
}
else {
CLAMP_MIN(before, 0);
CLAMP_MAX(after, gps->totpoints - 1);
}
- pt1 = &gps->points[before];
- pt2 = &gps->points[after];
- /* add both these points to the average-sum (s += p[i]/n) */
- total += pt1->strength * average_fac;
- total += pt2->strength * average_fac;
- /* Save max value. */
- if (max_strength < pt1->strength) {
- max_strength = pt1->strength;
- }
- if (max_strength < pt2->strength) {
- max_strength = pt2->strength;
- }
+ /* Add both these points in relative coordinates to the weighted average sum. */
+ strength += w_before * (gps->points[before].strength - pt->strength);
+ strength += w_after * (gps->points[after].strength - pt->strength);
+
+ total_w += w_before;
+ total_w += w_after;
+
+ w *= (n_half + step) / (double)(n_half + 1 - step);
}
+ total_w += w;
+ /* The accumulated weight total_w should be
+ * ~sqrt(M_PI * n_half) * exp((iterations * iterations) / n_half) < 100
+ * here, but sometimes not quite. */
+ strength /= total_w;
/* Based on influence factor, blend between original and optimal smoothed value. */
- ptb->strength = interpf(ptb->strength, total, inf);
- /* Clamp to maximum stroke strength to avoid weird results. */
- CLAMP_MAX(ptb->strength, max_strength);
+ r_gps->points[i].strength = pt->strength + strength * influence;
return true;
}
@@ -1136,74 +1158,55 @@ bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float
/** \name Stroke Smooth Thickness
* \{ */
-bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float influence)
+bool BKE_gpencil_stroke_smooth_thickness(
+ bGPDstroke *gps, int i, float influence, int iterations, bGPDstroke *r_gps)
{
- bGPDspoint *ptb = &gps->points[point_index];
- const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
-
- /* Do nothing if not enough points */
- if ((gps->totpoints <= 2) || (point_index < 1)) {
+ /* If nothing to do, return early */
+ if (gps->totpoints <= 2 || iterations <= 0) {
return false;
}
- /* Only affect endpoints by a fraction of the normal influence */
- float inf = influence;
- if (!is_cyclic && ELEM(point_index, 0, gps->totpoints - 1)) {
- inf *= 0.01f;
- }
- /* Limit max influence to reduce pop effect. */
- CLAMP_MAX(inf, 0.98f);
-
- float total = 0.0f;
- float max_pressure = 0.0f;
- const int steps = 4;
- const float average_fac = 1.0f / (float)(steps * 2 + 1);
- int step;
- /* add the point itself */
- total += ptb->pressure * average_fac;
- max_pressure = ptb->pressure;
+ /* See BKE_gpencil_stroke_smooth_point for details on the algorithm. */
- /* n-steps before/after current point */
- for (step = 1; step <= steps; step++) {
- bGPDspoint *pt1, *pt2;
- int before = point_index - step;
- int after = point_index + step;
+ const bGPDspoint *pt = &gps->points[i];
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
+ float pressure = 0.0f;
+ const int n_half = (iterations * iterations) / 4 + iterations;
+ double w = 1.0;
+ double total_w = 0.0;
+ for (int step = iterations; step > 0; step--) {
+ int before = i - step;
+ int after = i + step;
+ float w_before = (float)w;
+ float w_after = (float)w;
if (is_cyclic) {
- if (before < 0) {
- /* Sub to end point (before is already negative). */
- before = gps->totpoints + before;
- CLAMP(before, 0, gps->totpoints - 1);
- }
- if (after > gps->totpoints - 1) {
- /* Add to start point. */
- after = after - gps->totpoints;
- CLAMP(after, 0, gps->totpoints - 1);
- }
+ before = (before % gps->totpoints + gps->totpoints) % gps->totpoints;
+ after = after % gps->totpoints;
}
else {
CLAMP_MIN(before, 0);
CLAMP_MAX(after, gps->totpoints - 1);
}
- pt1 = &gps->points[before];
- pt2 = &gps->points[after];
- /* add both these points to the average-sum (s += p[i]/n) */
- total += pt1->pressure * average_fac;
- total += pt2->pressure * average_fac;
- /* Save max value. */
- if (max_pressure < pt1->pressure) {
- max_pressure = pt1->pressure;
- }
- if (max_pressure < pt2->pressure) {
- max_pressure = pt2->pressure;
- }
+ /* Add both these points in relative coordinates to the weighted average sum. */
+ pressure += w_before * (gps->points[before].pressure - pt->pressure);
+ pressure += w_after * (gps->points[after].pressure - pt->pressure);
+
+ total_w += w_before;
+ total_w += w_after;
+
+ w *= (n_half + step) / (double)(n_half + 1 - step);
}
+ total_w += w;
+ /* The accumulated weight total_w should be
+ * ~sqrt(M_PI * n_half) * exp((iterations * iterations) / n_half) < 100
+ * here, but sometimes not quite. */
+ pressure /= total_w;
/* Based on influence factor, blend between original and optimal smoothed value. */
- ptb->pressure = interpf(ptb->pressure, total, inf);
- /* Clamp to maximum stroke thickness to avoid weird results. */
- CLAMP_MAX(ptb->pressure, max_pressure);
+ r_gps->points[i].pressure = pt->pressure + pressure * influence;
+
return true;
}
@@ -1213,57 +1216,127 @@ bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float
/** \name Stroke Smooth UV
* \{ */
-bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influence)
+bool BKE_gpencil_stroke_smooth_uv(
+ struct bGPDstroke *gps, int i, float influence, int iterations, struct bGPDstroke *r_gps)
{
- bGPDspoint *ptb = &gps->points[point_index];
+ /* If nothing to do, return early */
+ if (gps->totpoints <= 2 || iterations <= 0) {
+ return false;
+ }
+
+ /* See BKE_gpencil_stroke_smooth_point for details on the algorithm. */
+
+ const bGPDspoint *pt = &gps->points[i];
const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
- /* Do nothing if not enough points */
- if (gps->totpoints <= 2) {
- return false;
+ /* If don't change the caps. */
+ if (!is_cyclic && ELEM(i, 0, gps->totpoints - 1)) {
+ r_gps->points[i].uv_rot = pt->uv_rot;
+ r_gps->points[i].uv_fac = pt->uv_fac;
+ return true;
}
- /* Compute theoretical optimal value */
- bGPDspoint *pta, *ptc;
- int before = point_index - 1;
- int after = point_index + 1;
+ float uv_rot = 0.0f;
+ float uv_fac = 0.0f;
+ const int n_half = iterations * iterations + iterations;
+ double w = 1.0;
+ double total_w = 0.0;
+ for (int step = iterations; step > 0; step--) {
+ int before = i - step;
+ int after = i + step;
+ float w_before = (float)w;
+ float w_after = (float)w;
- if (is_cyclic) {
- if (before < 0) {
- /* Sub to end point (before is already negative). */
- before = gps->totpoints + before;
- CLAMP(before, 0, gps->totpoints - 1);
+ if (is_cyclic) {
+ before = (before % gps->totpoints + gps->totpoints) % gps->totpoints;
+ after = after % gps->totpoints;
}
- if (after > gps->totpoints - 1) {
- /* Add to start point. */
- after = after - gps->totpoints;
- CLAMP(after, 0, gps->totpoints - 1);
+ else {
+ if (before < 0) {
+ w_before *= -before / (float)i;
+ before = 0;
+ }
+ if (after > gps->totpoints - 1) {
+ w_after *= (after - (gps->totpoints - 1)) / (float)(gps->totpoints - 1 - i);
+ after = gps->totpoints - 1;
+ }
}
- }
- else {
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
- }
- pta = &gps->points[before];
- ptc = &gps->points[after];
- /* the optimal value is the corresponding to the interpolation of the pressure
- * at the distance of point b
- */
- float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
- /* sometimes the factor can be wrong due stroke geometry, so use middle point */
- if ((fac < 0.0f) || (fac > 1.0f)) {
- fac = 0.5f;
+ /* Add both these points in relative coordinates to the weighted average sum. */
+ uv_rot += w_before * (gps->points[before].uv_rot - pt->uv_rot);
+ uv_rot += w_after * (gps->points[after].uv_rot - pt->uv_rot);
+ uv_fac += w_before * (gps->points[before].uv_fac - pt->uv_fac);
+ uv_fac += w_after * (gps->points[after].uv_fac - pt->uv_fac);
+
+ total_w += w_before;
+ total_w += w_after;
+
+ w *= (n_half + step) / (double)(n_half + 1 - step);
}
- float optimal = interpf(ptc->uv_rot, pta->uv_rot, fac);
+ total_w += w;
+ /* The accumulated weight total_w should be
+ * ~sqrt(M_PI * n_half) * exp((iterations * iterations) / n_half) < 100
+ * here, but sometimes not quite. */
+ uv_rot /= total_w;
+ uv_fac /= total_w;
- /* Based on influence factor, blend between original and optimal */
- ptb->uv_rot = interpf(optimal, ptb->uv_rot, influence);
- CLAMP(ptb->uv_rot, -M_PI_2, M_PI_2);
+ /* Based on influence factor, blend between original and optimal smoothed value. */
+ r_gps->points[i].uv_rot = pt->uv_rot + uv_rot * influence;
+ r_gps->points[i].uv_fac = pt->uv_fac + uv_fac * influence;
return true;
}
+void BKE_gpencil_stroke_smooth(bGPDstroke *gps,
+ const float influence,
+ const int iterations,
+ const bool smooth_position,
+ const bool smooth_strength,
+ const bool smooth_thickness,
+ const bool smooth_uv,
+ const bool keep_shape,
+ const float *weights)
+{
+ if (influence <= 0 || iterations <= 0) {
+ return;
+ }
+
+ /* Make a copy of the point data to avoid directionality of the smooth operation. */
+ bGPDstroke gps_old = *gps;
+ gps_old.points = (bGPDspoint *)MEM_dupallocN(gps->points);
+
+ /* Smooth stroke. */
+ for (int i = 0; i < gps->totpoints; i++) {
+ float val = influence;
+ if (weights != NULL) {
+ val *= weights[i];
+ if (val <= 0.0f) {
+ continue;
+ }
+ }
+
+ /* TODO: Currently the weights only control the influence, but is would be much better if they
+ * would control the distribution used in smooth, similar to how the ends are handled. */
+
+ /* Perform smoothing. */
+ if (smooth_position) {
+ BKE_gpencil_stroke_smooth_point(&gps_old, i, val, iterations, false, keep_shape, gps);
+ }
+ if (smooth_strength) {
+ BKE_gpencil_stroke_smooth_strength(&gps_old, i, val, iterations, gps);
+ }
+ if (smooth_thickness) {
+ BKE_gpencil_stroke_smooth_thickness(&gps_old, i, val, iterations, gps);
+ }
+ if (smooth_uv) {
+ BKE_gpencil_stroke_smooth_uv(&gps_old, i, val, iterations, gps);
+ }
+ }
+
+ /* Free the copied points array. */
+ MEM_freeN(gps_old.points);
+}
+
void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
int totpoints,
float (*points2d)[2],
@@ -3443,7 +3516,7 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a,
for (i = start; i < end; i++) {
pt = &gps_a->points[i];
pt->pressure += (avg_pressure - pt->pressure) * ratio;
- BKE_gpencil_stroke_smooth_point(gps_a, i, ratio * 0.6f, false);
+ BKE_gpencil_stroke_smooth_point(gps_a, i, ratio * 0.6f, 2, false, true, gps_a);
ratio += step;
/* In the center, reverse the ratio. */
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 51b5cab1f7c..adc6b990869 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -2415,6 +2415,24 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
+
+ /* Change grease pencil smooth iterations to match old results with new algorithm. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ if (md->type == eGpencilModifierType_Smooth) {
+ SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
+ if (gpmd->step == 1 && gpmd->factor <= 0.5f) {
+ gpmd->factor *= 2.0f;
+ }
+ else {
+ gpmd->step = 1 + (int)(gpmd->factor * max_ff(0.0f,
+ min_ff(5.1f * sqrtf(gpmd->step) - 3.0f,
+ gpmd->step + 2.0f)));
+ gpmd->factor = 1.0f;
+ }
+ }
+ }
+ }
}
/**
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 8506e90191f..a8fb344f366 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -3924,31 +3924,36 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
- for (int r = 0; r < repeat; r++) {
+ /* TODO use `BKE_gpencil_stroke_smooth` when the weights are better used. */
+ bGPDstroke gps_old = *gps;
+ gps_old.points = (bGPDspoint *)MEM_dupallocN(gps->points);
+ /* Here the iteration needs to be done outside the smooth functions,
+ * as there are points that don't get smoothed. */
+ for (int n = 0; n < repeat; n++) {
for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- if ((only_selected) && ((pt->flag & GP_SPOINT_SELECT) == 0)) {
+ if (only_selected && (gps->points[i].flag & GP_SPOINT_SELECT) == 0) {
continue;
}
- /* perform smoothing */
+ /* Perform smoothing. */
if (smooth_position) {
- BKE_gpencil_stroke_smooth_point(gps, i, factor, false);
+ BKE_gpencil_stroke_smooth_point(&gps_old, i, factor, 1, false, false, gps);
}
if (smooth_strength) {
- BKE_gpencil_stroke_smooth_strength(gps, i, factor);
+ BKE_gpencil_stroke_smooth_strength(&gps_old, i, factor, 1, gps);
}
if (smooth_thickness) {
- /* thickness need to repeat process several times */
- for (int r2 = 0; r2 < repeat * 2; r2++) {
- BKE_gpencil_stroke_smooth_thickness(gps, i, 1.0f - factor);
- }
+ BKE_gpencil_stroke_smooth_thickness(&gps_old, i, 1.0f - factor, 1, gps);
}
if (smooth_uv) {
- BKE_gpencil_stroke_smooth_uv(gps, i, factor);
+ BKE_gpencil_stroke_smooth_uv(&gps_old, i, factor, 1, gps);
}
}
+ if (n < repeat - 1) {
+ memcpy(gps_old.points, gps->points, sizeof(bGPDspoint) * gps->totpoints);
+ }
}
+ MEM_freeN(gps_old.points);
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
@@ -4926,10 +4931,10 @@ void GPENCIL_OT_stroke_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- prop = RNA_def_int(ot->srna, "repeat", 1, 1, 50, "Repeat", "", 1, 20);
+ prop = RNA_def_int(ot->srna, "repeat", 2, 1, 1000, "Repeat", "", 1, 1000);
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 2.0f, "Factor", "", 0.0f, 2.0f);
+ RNA_def_float(ot->srna, "factor", 1.0f, 0.0f, 2.0f, "Factor", "", 0.0f, 1.0f);
RNA_def_boolean(ot->srna,
"only_selected",
true,
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 45a2247c65e..8fc300412d9 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1638,14 +1638,9 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
}
}
- /* smooth stroke */
- float reduce = 0.0f;
- float smoothfac = 1.0f;
- for (int r = 0; r < 1; r++) {
- for (int i = 0; i < gps->totpoints; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, smoothfac - reduce, false);
- }
- reduce += 0.25f; /* reduce the factor */
+ /* Smooth stroke. No copy of the stroke since there only a minor improvement here. */
+ for (int i = 0; i < gps->totpoints; i++) {
+ BKE_gpencil_stroke_smooth_point(gps, i, 1.0f, 2, false, true, gps);
}
/* if axis locked, reproject to plane locked */
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 65060e1bab5..8630b7f23d4 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -310,23 +310,6 @@ static void gpencil_stroke_pair_table(bContext *C,
}
}
-static void gpencil_interpolate_smooth_stroke(bGPDstroke *gps,
- float smooth_factor,
- int smooth_steps)
-{
- if (smooth_factor == 0.0f) {
- return;
- }
-
- float reduce = 0.0f;
- for (int r = 0; r < smooth_steps; r++) {
- for (int i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, smooth_factor - reduce, false);
- BKE_gpencil_stroke_smooth_strength(gps, i, smooth_factor);
- }
- reduce += 0.25f; /* reduce the factor */
- }
-}
/* Perform interpolation */
static void gpencil_interpolate_update_points(const bGPDstroke *gps_from,
const bGPDstroke *gps_to,
@@ -553,7 +536,15 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
/* Update points position. */
gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
- gpencil_interpolate_smooth_stroke(new_stroke, tgpi->smooth_factor, tgpi->smooth_steps);
+ BKE_gpencil_stroke_smooth(new_stroke,
+ tgpi->smooth_factor,
+ tgpi->smooth_steps,
+ true,
+ true,
+ false,
+ false,
+ true,
+ NULL);
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gpd, new_stroke);
@@ -1385,7 +1376,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
/* Update points position. */
gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
- gpencil_interpolate_smooth_stroke(new_stroke, smooth_factor, smooth_steps);
+ BKE_gpencil_stroke_smooth(
+ new_stroke, smooth_factor, smooth_steps, true, true, false, false, true, NULL);
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gpd, new_stroke);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 18dc8d4bc72..93a4a784674 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1197,29 +1197,21 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
gpencil_subdivide_stroke(gpd, gps, subdivide);
}
- /* Smooth stroke after subdiv - only if there's something to do for each iteration,
- * the factor is reduced to get a better smoothing
- * without changing too much the original stroke. */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
- (brush->gpencil_settings->draw_smoothfac > 0.0f)) {
- float reduce = 0.0f;
- for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) {
- for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth_point(
- gps, i, brush->gpencil_settings->draw_smoothfac - reduce, false);
- BKE_gpencil_stroke_smooth_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
- }
- reduce += 0.25f; /* reduce the factor */
- }
+ /* Smooth stroke after subdiv - only if there's something to do for each iteration.
+ * Keep the original stroke shape as much as possible. */
+ const float smoothfac = brush->gpencil_settings->draw_smoothfac;
+ const int iterations = brush->gpencil_settings->draw_smoothlvl;
+ if (brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) {
+ BKE_gpencil_stroke_smooth(gps, smoothfac, iterations, true, true, false, false, true, NULL);
}
/* If reproject the stroke using Stroke mode, need to apply a smooth because
* the reprojection creates small jitter. */
if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) {
float ifac = (float)brush->gpencil_settings->input_samples / 10.0f;
float sfac = interpf(1.0f, 0.2f, ifac);
- for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth_point(gps, i, sfac, false);
- BKE_gpencil_stroke_smooth_strength(gps, i, sfac);
+ for (i = 0; i < gps->totpoints; i++) {
+ BKE_gpencil_stroke_smooth_point(gps, i, sfac, 2, false, true, gps);
+ BKE_gpencil_stroke_smooth_strength(gps, i, sfac, 2, gps);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 216971e514b..1e7159392e2 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -329,16 +329,16 @@ static bool gpencil_brush_smooth_apply(tGP_BrushEditData *gso,
/* perform smoothing */
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
- BKE_gpencil_stroke_smooth_point(gps, pt_index, inf, false);
+ BKE_gpencil_stroke_smooth_point(gps, pt_index, inf, 2, false, false, gps);
}
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
- BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf);
+ BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf, 2, gps);
}
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_THICKNESS) {
- BKE_gpencil_stroke_smooth_thickness(gps, pt_index, inf);
+ BKE_gpencil_stroke_smooth_thickness(gps, pt_index, inf, 2, gps);
}
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_UV) {
- BKE_gpencil_stroke_smooth_uv(gps, pt_index, inf);
+ BKE_gpencil_stroke_smooth_uv(gps, pt_index, inf, 2, gps);
}
return true;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
index 8eaed56dc58..d80224e6639 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
@@ -105,15 +105,15 @@ static void deformStroke(GpencilModifierData *md,
/* Apply deformed coordinates. */
pt = gps->points;
+ bGPDstroke gps_old = *gps;
+ gps_old.points = (bGPDspoint *)MEM_dupallocN(gps->points);
for (i = 0; i < gps->totpoints; i++, pt++) {
copy_v3_v3(&pt->x, vert_coords[i]);
/* Smooth stroke. */
- if (mmd->smooth_factor > 0.0f) {
- for (int r = 0; r < mmd->smooth_step; r++) {
- BKE_gpencil_stroke_smooth_point(gps, i, mmd->smooth_factor, true);
- }
- }
+ BKE_gpencil_stroke_smooth_point(
+ &gps_old, i, mmd->smooth_factor, mmd->smooth_step, true, false, gps);
}
+ MEM_freeN(gps_old.points);
MEM_freeN(vert_coords);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
index f8201eb6b4f..eb51a247d87 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c
@@ -34,10 +34,14 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "RNA_access.h"
+
#include "MOD_gpencil_modifiertypes.h"
#include "MOD_gpencil_ui_common.h"
#include "MOD_gpencil_util.h"
+#include "MEM_guardedalloc.h"
+
static void initData(GpencilModifierData *md)
{
SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
@@ -94,45 +98,40 @@ static void deformStroke(GpencilModifierData *md,
return;
}
- /* smooth stroke */
- if (mmd->factor > 0.0f) {
- for (int r = 0; r < mmd->step; r++) {
- for (int i = 0; i < gps->totpoints; i++) {
- MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
-
- /* verify vertex group */
- float weight = get_modifier_point_weight(
- dvert, (mmd->flag & GP_SMOOTH_INVERT_VGROUP) != 0, def_nr);
- if (weight < 0.0f) {
- continue;
- }
-
- /* Custom curve to modulate value. */
- if (use_curve) {
- float value = (float)i / (gps->totpoints - 1);
- weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value);
- }
-
- const float val = mmd->factor * weight;
- /* perform smoothing */
- if (mmd->flag & GP_SMOOTH_MOD_LOCATION) {
- BKE_gpencil_stroke_smooth_point(gps, i, val, false);
- }
- if (mmd->flag & GP_SMOOTH_MOD_STRENGTH) {
- BKE_gpencil_stroke_smooth_strength(gps, i, val);
- }
- if ((mmd->flag & GP_SMOOTH_MOD_THICKNESS) && (val > 0.0f)) {
- /* thickness need to repeat process several times */
- for (int r2 = 0; r2 < r * 10; r2++) {
- BKE_gpencil_stroke_smooth_thickness(gps, i, val);
- }
- }
- if (mmd->flag & GP_SMOOTH_MOD_UV) {
- BKE_gpencil_stroke_smooth_uv(gps, i, val);
- }
+ if (mmd->factor <= 0.0f || mmd->step <= 0) {
+ return;
+ }
+
+ float *weights = NULL;
+ if (def_nr != -1 || use_curve) {
+ weights = MEM_malloc_arrayN(gps->totpoints, sizeof(*weights), __func__);
+ /* Calculate weights. */
+ for (int i = 0; i < gps->totpoints; i++) {
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+
+ /* Verify vertex group. */
+ float weight = get_modifier_point_weight(
+ dvert, (mmd->flag & GP_SMOOTH_INVERT_VGROUP) != 0, def_nr);
+
+ /* Custom curve to modulate value. */
+ if (use_curve && weight > 0.0f) {
+ float value = (float)i / (gps->totpoints - 1);
+ weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value);
}
+
+ weights[i] = weight;
}
}
+ BKE_gpencil_stroke_smooth(gps,
+ mmd->factor,
+ mmd->step,
+ mmd->flag & GP_SMOOTH_MOD_LOCATION,
+ mmd->flag & GP_SMOOTH_MOD_STRENGTH,
+ mmd->flag & GP_SMOOTH_MOD_THICKNESS,
+ mmd->flag & GP_SMOOTH_MOD_UV,
+ mmd->flag & GP_SMOOTH_KEEP_SHAPE,
+ weights);
+ MEM_SAFE_FREE(weights);
}
static void bakeModifier(struct Main *UNUSED(bmain),
@@ -161,7 +160,7 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk,
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
- uiLayout *row;
+ uiLayout *row, *col;
uiLayout *layout = panel->layout;
PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
@@ -177,6 +176,10 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "factor", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "step", 0, IFACE_("Repeat"), ICON_NONE);
+ col = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_edit_position"));
+ uiItemR(col, ptr, "keep_shape", 0, NULL, ICON_NONE);
+
gpencil_modifier_panel_end(layout, ptr);
}
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index a87e7a7c397..9d14ca039ac 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -193,7 +193,7 @@
.vgname = "", \
.pass_index = 0, \
.flag = GP_SMOOTH_MOD_LOCATION, \
- .factor = 0.5f, \
+ .factor = 1.0f, \
.step = 1, \
.layer_pass = 0, \
.curve_intensity = NULL, \
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index 1054c309ee5..4f655e87a09 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -750,6 +750,7 @@ typedef enum eSmoothGpencil_Flag {
GP_SMOOTH_INVERT_LAYERPASS = (1 << 7),
GP_SMOOTH_INVERT_MATERIAL = (1 << 4),
GP_SMOOTH_CUSTOM_CURVE = (1 << 8),
+ GP_SMOOTH_KEEP_SHAPE = (1 << 9),
} eSmoothGpencil_Flag;
typedef struct ArmatureGpencilModifierData {
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index c86a852b0ea..b2b6bdbcffc 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -1355,7 +1355,8 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
/* Smoothing factor for new strokes */
prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac");
- RNA_def_property_range(prop, 0.0, 2.0f);
+ RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 3);
RNA_def_property_ui_text(
prop,
"Smooth",
@@ -1366,7 +1367,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
/* Iterations of the Smoothing factor */
prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl");
- RNA_def_property_range(prop, 1, 3);
+ RNA_def_property_range(prop, 0, 100);
RNA_def_property_ui_text(prop, "Iterations", "Number of times to smooth newly created strokes");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index edeb7443957..bf3f506251c 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -1026,11 +1026,16 @@ static void rna_def_modifier_gpencilsmooth(BlenderRNA *brna)
prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "step");
- RNA_def_property_range(prop, 1, 10);
+ RNA_def_property_range(prop, 1, 1000);
RNA_def_property_ui_text(
prop, "Step", "Number of times to apply smooth (high numbers can reduce fps)");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "keep_shape", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_KEEP_SHAPE);
+ RNA_def_property_ui_text(prop, "Keep Shape", "Smooth the details, but keep the overall shape");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_INVERT_LAYER);
RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");