[Bf-blender-cvs] [250eda36b8f] master: GPencil: Build modifier add "natural drawing" time
Marc Chehab
noreply at git.blender.org
Tue Jan 10 15:38:58 CET 2023
Commit: 250eda36b8f91a2f89b202d5eb79108260e1b1e3
Author: Marc Chehab
Date: Tue Jan 10 15:37:02 2023 +0100
Branches: master
https://developer.blender.org/rB250eda36b8f91a2f89b202d5eb79108260e1b1e3
GPencil: Build modifier add "natural drawing" time
This patch uses the recorded drawing speed to rebuild the strokes. This results in a way more
natural feel of the animation.
Here's a short summary of existing data used:
- gps->points->time: This is a timestamp in seconds of when the point was created
since the creation of the stroke. It's quite often 0 (I added a sanitization routine).
- gpf->inittime: This is a timestamp in seconds when a stroke was drawn measured
since some unknown point in time. I only ever use the difference between two strokes,
so the absolute value is not relevant.
Reviewed By: frogstomp, antoniov, mendio
Differential Revision: https://developer.blender.org/D16759
===================================================================
M source/blender/blenloader/intern/versioning_300.cc
M source/blender/editors/include/ED_gpencil.h
M source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
M source/blender/makesdna/DNA_gpencil_modifier_defaults.h
M source/blender/makesdna/DNA_gpencil_modifier_types.h
M source/blender/makesrna/intern/rna_gpencil_modifier.c
===================================================================
diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc
index 38ecfaf41ea..6b4f374bf0e 100644
--- a/source/blender/blenloader/intern/versioning_300.cc
+++ b/source/blender/blenloader/intern/versioning_300.cc
@@ -3842,6 +3842,20 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
LISTBASE_FOREACH (Light *, light, &bmain->lights) {
light->radius = light->area_size;
}
+ /* Grease Pencil Build modifier: Set default value for new natural drawspeed factor and maximum
+ * gap. */
+ if (!DNA_struct_elem_find(fd->filesdna, "BuildGpencilModifierData", "float", "speed_fac") ||
+ !DNA_struct_elem_find(fd->filesdna, "BuildGpencilModifierData", "float", "speed_maxgap")) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
+ if (md->type == eGpencilModifierType_Build) {
+ BuildGpencilModifierData *mmd = (BuildGpencilModifierData *)md;
+ mmd->speed_fac = 1.2f;
+ mmd->speed_maxgap = 0.5f;
+ }
+ }
+ }
+ }
}
/**
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 9dd2ba5d1d3..c95e58f9559 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -83,7 +83,7 @@ typedef struct tGPspoint {
float pressure;
/** Pressure of tablet at this point for alpha factor. */
float strength;
- /** Time relative to stroke start (used when converting to path). */
+ /** Time relative to stroke start (used when converting to path & in build modifier). */
float time;
/** Factor of uv along the stroke. */
float uv_fac;
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
index 49ac3275c82..e4320a7b5a8 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -47,6 +47,13 @@
#include "MOD_gpencil_modifiertypes.h"
#include "MOD_gpencil_ui_common.h"
+/* Two hard-coded values for GP_BUILD_MODE_ADDITIVE with GP_BUILD_TIMEMODE_DRAWSPEED. */
+
+/* The minimum time gap we should worry about points with no time. */
+#define GP_BUILD_CORRECTGAP 0.001
+/* The time for geometric strokes */
+#define GP_BUILD_TIME_GEOSTROKES 1.0
+
static void initData(GpencilModifierData *md)
{
BuildGpencilModifierData *gpmd = (BuildGpencilModifierData *)md;
@@ -252,53 +259,55 @@ static int cmp_stroke_build_details(const void *ps1, const void *ps2)
return p1->distance > p2->distance ? 1 : (p1->distance == p2->distance ? 0 : -1);
}
-/* Sequential and additive - Show strokes one after the other. */
+/* Sequential - Show strokes one after the other (includes additive mode). */
static void build_sequential(Object *ob,
BuildGpencilModifierData *mmd,
+ Depsgraph *depsgraph,
bGPdata *gpd,
bGPDframe *gpf,
- const int target_def_nr,
+ int target_def_nr,
float fac,
- bool additive)
+ const float *ctime)
{
+ /* Total number of strokes in this run. */
size_t tot_strokes = BLI_listbase_count(&gpf->strokes);
- size_t start_stroke;
+ /* First stroke to build. */
+ size_t start_stroke = 0;
+ /* Pointer to current stroke. */
bGPDstroke *gps;
+ /* Recycled counter. */
size_t i;
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ /* Framerate of scene. */
+ const float fps = (((float)scene->r.frs_sec) / scene->r.frs_sec_base);
- /* 1) Determine which strokes to start with & total strokes to build. */
-
- if (additive) {
+ /* 1) Determine which strokes to start with (& adapt total number of strokes to build). */
+ if (mmd->mode == GP_BUILD_MODE_ADDITIVE) {
if (gpf->prev) {
- start_stroke = BLI_listbase_count(&gpf->prev->strokes);
- }
- else {
- start_stroke = 0;
+ start_stroke = BLI_listbase_count(&gpf->runtime.gpf_orig->prev->strokes);
}
if (start_stroke <= tot_strokes) {
tot_strokes = tot_strokes - start_stroke;
}
- else {
- start_stroke = 0;
- }
- }
- else {
- start_stroke = 0;
}
- /* 2) Compute proportion of time each stroke should occupy */
+ /* 2) Compute proportion of time each stroke should occupy. */
/* NOTE: This assumes that the total number of points won't overflow! */
tStrokeBuildDetails *table = MEM_callocN(sizeof(tStrokeBuildDetails) * tot_strokes, __func__);
- size_t totpoints = 0;
-
- /* 2.1) First pass - Tally up points */
+ /* Pointer to cache table of times for each point. */
+ float *idx_times;
+ /* Running overall time sum incrementing per point. */
+ float sumtime = 0;
+ /* Running overall point sum. */
+ size_t sumpoints = 0;
+
+ /* 2.1) Pass to initially tally up points. */
for (gps = BLI_findlink(&gpf->strokes, start_stroke), i = 0; gps; gps = gps->next, i++) {
tStrokeBuildDetails *cell = &table[i];
cell->gps = gps;
cell->totpoints = gps->totpoints;
-
- totpoints += cell->totpoints;
+ sumpoints += cell->totpoints;
/* Compute distance to control object if set, and build according to that order. */
if (mmd->object) {
@@ -321,7 +330,104 @@ static void build_sequential(Object *ob,
qsort(table, tot_strokes, sizeof(tStrokeBuildDetails), cmp_stroke_build_details);
}
- /* 2.2) Second pass - Compute the overall indices for points */
+ /* 2.2) If GP_BUILD_TIMEMODE_DRAWSPEED: Tally up point timestamps & delays to idx_times. */
+ if (mmd->time_mode == GP_BUILD_TIMEMODE_DRAWSPEED) {
+ idx_times = MEM_callocN(sizeof(float) * sumpoints, __func__);
+ /* Maximum time gap between strokes in seconds. */
+ const float GP_BUILD_MAXGAP = mmd->speed_maxgap;
+ /* Running reference to overall current point. */
+ size_t curpoint = 0;
+ /* Running timestamp of last point that had data. */
+ float last_pointtime = 0;
+
+ for (i = 0; i < tot_strokes; i++) {
+ tStrokeBuildDetails *cell = &table[i];
+ /* Adding delay between strokes to sumtime. */
+ if (mmd->object == NULL) {
+ /* Normal case: Delay to last stroke. */
+ if (i != 0 && 0 < cell->gps->inittime && 0 < (cell - 1)->gps->inittime) {
+ float curgps_delay = fabs(cell->gps->inittime - (cell - 1)->gps->inittime) -
+ last_pointtime;
+ if (0 < curgps_delay) {
+ sumtime += MIN2(curgps_delay, GP_BUILD_MAXGAP);
+ }
+ }
+ }
+
+ /* Going through the points of the current stroke
+ * and filling in "zeropoints" where "time" = 0. */
+
+ /* Count of consecutive points where "time" is 0. */
+ int zeropoints = 0;
+ for (int j = 0; j < cell->totpoints; j++) {
+ /* Defining time for first point in stroke. */
+ if (j == 0) {
+ idx_times[curpoint] = sumtime;
+ last_pointtime = cell->gps->points[0].time;
+ }
+ /* Entering subsequent points */
+ else {
+ if (cell->gps->points[j].time == 0) {
+ idx_times[curpoint] = sumtime;
+ zeropoints++;
+ }
+ /* From here current point has time data */
+ else {
+ float deltatime = fabs(cell->gps->points[j].time - last_pointtime);
+ /* Do we need to sanitize previous points? */
+ if (0 < zeropoints) {
+ /* Only correct if timegap bigger than MIN_CORRECTGAP. */
+ if (GP_BUILD_CORRECTGAP < deltatime) {
+ /* Cycling backwards through zeropoints to fix them. */
+ for (int k = 0; k < zeropoints; k++) {
+ float linear_fill = interpf(
+ deltatime, 0, ((float)k + 1) / (zeropoints + 1)); /* Factor = Proportion. */
+ idx_times[curpoint - k - 1] = sumtime + linear_fill;
+ }
+ }
+ else {
+ zeropoints = 0;
+ }
+ }
+
+ /* Normal behaviour with time data */
+ idx_times[curpoint] = sumtime + deltatime;
+ sumtime = idx_times[curpoint];
+ last_pointtime = cell->gps->points[j].time;
+ zeropoints = 0;
+ }
+ }
+ curpoint += 1;
+ }
+
+ /* If stroke had no time data at all, use mmd->time_geostrokes. */
+ if (zeropoints + 1 == cell->totpoints) {
+ for (int j = 0; j < cell->totpoints; j++) {
+ idx_times[(int)curpoint - j - 1] = (float)(cell->totpoints - j) *
+ GP_BUILD_TIME_GEOSTROKES /
+ (float)cell->totpoints +
+ sumtime;
+ }
+ last_pointtime = GP_BUILD_TIME_GEOSTROKES;
+ sumtime += GP_BUILD_TIME_GEOSTROKES;
+ }
+ }
+
+ float gp_build_speedfactor = mmd->speed_fac;
+ /* If current frame can't be built before next frame, adjust gp_build_speedfactor. */
+ if (gpf->next &&
+ (gpf->framenum + sumtime * fps / gp_build_speedfactor) > gpf->next->framenum) {
+ gp_build_speedfactor = sumtime * fps / (gpf->next->framenum - gpf->framenum);
+ }
+ /* Apply gp_build_speedfactor to all points & to sumtime. */
+ for (i = 0; i < sumpoints; i++) {
+ float *idx_time = &idx_times[i];
+ *idx_time /= gp_build_speedfactor;
+ }
+ sumtime /= gp_build_speedfactor;
+ }
+
+ /* 2.3) Pass to compute overall indices for points (per stroke). */
for (i = 0; i < tot_strokes; i++) {
tStrokeBuildDetails *cell = &table[i];
@@ -329,12 +435,12 @@ static void build_sequential(Object *ob,
cell->start_idx = 0;
}
else {
- cell->start_idx = (cell - 1)->end_idx;
+ cell->start_idx = (cell - 1)->end_idx + 1;
}
cell->end_idx = cell->start_idx + cell->totpoints - 1;
}
- /* 3) Determine the
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list