GPencil: Improve interpolation of strokes with unequal lengths

Use the BKE_gpencil_stroke_uniform_subdivide function to subdivide strokes
before interpolation. When the target/source stroke is smaller than the other
stroke, it is subdivided until the lengths match. This improves the overall quality
of the interpolation of different sized strokes.

Before/After video:
{F9511779}

Reviewed By: #grease_pencil, antoniov, pepeland, mendio

Differential Revision: https://developer.blender.org/D9839
This commit is contained in:
Falk David 2020-12-15 22:28:28 +01:00 committed by Falk David
parent 5535b0b887
commit 151e847b87
1 changed files with 34 additions and 35 deletions

View File

@ -283,8 +283,8 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
tgpil->gpl = gpl;
tgpil->prevFrame = gpl->actframe;
tgpil->nextFrame = gpl->actframe->next;
tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe);
tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next);
BLI_addtail(&tgpi->ilayers, tgpil);
@ -326,24 +326,25 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
valid = false;
}
/* create new stroke */
new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
if (valid) {
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
new_stroke->points = MEM_recallocN(new_stroke->points,
sizeof(*new_stroke->points) * gps_to->totpoints);
if (new_stroke->dvert != NULL) {
new_stroke->dvert = MEM_recallocN(new_stroke->dvert,
sizeof(*new_stroke->dvert) * gps_to->totpoints);
}
new_stroke->totpoints = gps_to->totpoints;
BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true);
}
/* update points position */
if (gps_to->totpoints > gps_from->totpoints) {
BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true);
}
/* Create new stroke. */
new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
/* Update points position. */
gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
}
else {
/* Create new stroke. */
new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
/* need an empty stroke to keep index correct for lookup, but resize to smallest size */
new_stroke->totpoints = 0;
new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
@ -443,12 +444,16 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
/* finally, free memory used by temp data */
LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) {
BKE_gpencil_free_strokes(tgpil->prevFrame);
BKE_gpencil_free_strokes(tgpil->nextFrame);
BKE_gpencil_free_strokes(tgpil->interFrame);
MEM_freeN(tgpil->interFrame);
MEM_SAFE_FREE(tgpil->prevFrame);
MEM_SAFE_FREE(tgpil->nextFrame);
MEM_SAFE_FREE(tgpil->interFrame);
}
BLI_freelistN(&tgpi->ilayers);
MEM_freeN(tgpi);
MEM_SAFE_FREE(tgpi);
}
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
@ -992,8 +997,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
}
/* store extremes */
prevFrame = gpl->actframe;
nextFrame = gpl->actframe->next;
prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe);
nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next);
/* Loop over intermediary frames and create the interpolation */
for (cframe = prevFrame->framenum + step; cframe < nextFrame->framenum; cframe += step) {
@ -1049,27 +1054,16 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
}
/* create new stroke */
bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
/* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
if (gps_from->totpoints > gps_to->totpoints) {
/* free weights of removed points */
if (new_stroke->dvert != NULL) {
BKE_defvert_array_free_elems(new_stroke->dvert + gps_to->totpoints,
gps_from->totpoints - gps_to->totpoints);
}
new_stroke->points = MEM_recallocN(new_stroke->points,
sizeof(*new_stroke->points) * gps_to->totpoints);
if (new_stroke->dvert != NULL) {
new_stroke->dvert = MEM_recallocN(new_stroke->dvert,
sizeof(*new_stroke->dvert) * gps_to->totpoints);
}
new_stroke->totpoints = gps_to->totpoints;
BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true);
}
if (gps_to->totpoints > gps_from->totpoints) {
BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true);
}
/* create new stroke */
bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
/* update points position */
gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
@ -1081,6 +1075,11 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
BLI_addtail(&interFrame->strokes, new_stroke);
}
}
BKE_gpencil_free_strokes(prevFrame);
BKE_gpencil_free_strokes(nextFrame);
MEM_SAFE_FREE(prevFrame);
MEM_SAFE_FREE(nextFrame);
}
/* notifiers */