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:
authorYimingWu <xp8110@outlook.com>2022-03-29 17:46:30 +0300
committerYimingWu <xp8110@outlook.com>2022-03-29 17:46:56 +0300
commitc4e4924096d1dcfd971aafbbf82d848a774b57db (patch)
treedb2deb2dc65e25ae31076abb0de58192195f22a0 /source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
parent0e0977f3e68b2ac1fd021b5dc6ca10e5b9a25da1 (diff)
GPencil: Fading for build modifier.
Adds fading support for build modifier so it's not a hard cut off Reviewed By: Antonio Vazquez (antoniov), Matias Mendiola (mendio) Differential Revision: https://developer.blender.org/D14309
Diffstat (limited to 'source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c')
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c340
1 files changed, 287 insertions, 53 deletions
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
index 1a69a6a8a38..18ce9a12f7b 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -6,6 +6,7 @@
*/
#include <stdio.h>
+#include <stdlib.h>
#include "MEM_guardedalloc.h"
@@ -13,6 +14,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_sort.h"
#include "BLT_translation.h"
@@ -25,9 +27,12 @@
#include "DNA_screen_types.h"
#include "BKE_context.h"
+#include "BKE_deform.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_modifier.h"
#include "BKE_screen.h"
#include "UI_interface.h"
@@ -99,17 +104,22 @@ static void gpf_clear_all_strokes(bGPDframe *gpf)
* NOTE: This won't be called if all points are present/removed
*/
static void reduce_stroke_points(bGPdata *gpd,
+ bGPDframe *gpf,
bGPDstroke *gps,
const int num_points,
const eBuildGpencil_Transition transition)
{
+ if (num_points == 0) {
+ clear_stroke(gpf, gps);
+ return;
+ }
bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * num_points, __func__);
MDeformVert *new_dvert = NULL;
if ((gps->dvert != NULL) && (num_points > 0)) {
new_dvert = MEM_callocN(sizeof(MDeformVert) * num_points, __func__);
}
- /* Which end should points be removed from */
+ /* Which end should points be removed from. */
switch (transition) {
case GP_BUILD_TRANSITION_GROW: /* Show in forward order =
* Remove ungrown-points from end of stroke. */
@@ -131,7 +141,7 @@ static void reduce_stroke_points(bGPdata *gpd,
}
/* Hide in forward order = Remove points from start of stroke */
- case GP_BUILD_TRANSITION_FADE: {
+ case GP_BUILD_TRANSITION_VANISH: {
/* num_points is the number of points left after reducing.
* We need to know how many to remove
*/
@@ -167,6 +177,57 @@ static void reduce_stroke_points(bGPdata *gpd,
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
+static void fade_stroke_points(bGPDstroke *gps,
+ const int starting_index,
+ const int ending_index,
+ const float starting_weight,
+ const float ending_weight,
+ const int target_def_nr,
+ const eBuildGpencil_Transition transition,
+ const float thickness_strength,
+ const float opacity_strength)
+{
+ MDeformVert *dvert;
+
+ int range = ending_index - starting_index;
+ if (!range) {
+ range = 1;
+ }
+
+ /* Which end should points be removed from */
+ switch (transition) {
+ /* Because starting_weight and ending_weight are set in correct order before calling this
+ * function, those three modes can use the same interpolation code. */
+ case GP_BUILD_TRANSITION_GROW:
+ case GP_BUILD_TRANSITION_SHRINK:
+ case GP_BUILD_TRANSITION_VANISH: {
+ for (int i = starting_index; i <= ending_index; i++) {
+ float weight = interpf(
+ ending_weight, starting_weight, (float)(i - starting_index) / range);
+ if (target_def_nr >= 0) {
+ dvert = &gps->dvert[i];
+ MDeformWeight *dw = BKE_defvert_ensure_index(dvert, target_def_nr);
+ if (dw) {
+ dw->weight = weight;
+ CLAMP(dw->weight, 0.0f, 1.0f);
+ }
+ }
+ if (thickness_strength > 1e-5) {
+ gps->points[i].pressure *= interpf(weight, 1.0f, thickness_strength);
+ }
+ if (opacity_strength > 1e-5) {
+ gps->points[i].strength *= interpf(weight, 1.0f, opacity_strength);
+ }
+ }
+ break;
+ }
+
+ default:
+ printf("ERROR: Unknown transition %d in %s()\n", (int)transition, __func__);
+ break;
+ }
+}
+
/* --------------------------------------------- */
/* Stroke Data Table Entry - This represents one stroke being generated */
@@ -178,11 +239,26 @@ typedef struct tStrokeBuildDetails {
/* Number of points - Cache for more convenient access */
int totpoints;
+
+ /* Distance to control object, used to sort the strokes if set. */
+ float distance;
} tStrokeBuildDetails;
+static int cmp_stroke_build_details(const void *ps1, const void *ps2)
+{
+ tStrokeBuildDetails *p1 = (tStrokeBuildDetails *)ps1;
+ tStrokeBuildDetails *p2 = (tStrokeBuildDetails *)ps2;
+ return p1->distance > p2->distance ? 1 : (p1->distance == p2->distance ? 0 : -1);
+}
+
/* Sequential and additive - Show strokes one after the other. */
-static void build_sequential(
- BuildGpencilModifierData *mmd, bGPdata *gpd, bGPDframe *gpf, float fac, bool additive)
+static void build_sequential(Object *ob,
+ BuildGpencilModifierData *mmd,
+ bGPdata *gpd,
+ bGPDframe *gpf,
+ const int target_def_nr,
+ float fac,
+ bool additive)
{
size_t tot_strokes = BLI_listbase_count(&gpf->strokes);
size_t start_stroke;
@@ -222,6 +298,26 @@ static void build_sequential(
cell->totpoints = gps->totpoints;
totpoints += cell->totpoints;
+
+ /* Compute distance to control object if set, and build according to that order. */
+ if (mmd->object) {
+ float sv1[3], sv2[3];
+ mul_v3_m4v3(sv1, ob->obmat, &gps->points[0].x);
+ mul_v3_m4v3(sv2, ob->obmat, &gps->points[gps->totpoints - 1].x);
+ float dist_l = len_v3v3(sv1, mmd->object->loc);
+ float dist_r = len_v3v3(sv2, mmd->object->loc);
+ if (dist_r < dist_l) {
+ BKE_gpencil_stroke_flip(gps);
+ cell->distance = dist_r;
+ }
+ else {
+ cell->distance = dist_l;
+ }
+ }
+ }
+
+ if (mmd->object) {
+ qsort(table, tot_strokes, sizeof(tStrokeBuildDetails), cmp_stroke_build_details);
}
/* 2.2) Second pass - Compute the overall indices for points */
@@ -240,6 +336,17 @@ static void build_sequential(
/* 3) Determine the global indices for points that should be visible */
size_t first_visible = 0;
size_t last_visible = 0;
+ /* Need signed numbers because the representation of fading offset would exceed the beginning and
+ * the end of offsets. */
+ int fade_start = 0;
+ int fade_end = 0;
+
+ bool fading_enabled = (mmd->flag & GP_BUILD_USE_FADING);
+
+ float set_fade_fac = fading_enabled ? mmd->fade_fac : 0.0f;
+ float use_fac = interpf(1 + set_fade_fac, 0, fac);
+ float use_fade_fac = use_fac - set_fade_fac;
+ CLAMP(use_fade_fac, 0.0f, 1.0f);
switch (mmd->transition) {
/* Show in forward order
@@ -247,7 +354,9 @@ static void build_sequential(
*/
case GP_BUILD_TRANSITION_GROW:
first_visible = 0; /* always visible */
- last_visible = (size_t)roundf(totpoints * fac);
+ last_visible = (size_t)roundf(totpoints * use_fac);
+ fade_start = (int)roundf(totpoints * use_fade_fac);
+ fade_end = last_visible;
break;
/* Hide in reverse order
@@ -255,15 +364,19 @@ static void build_sequential(
*/
case GP_BUILD_TRANSITION_SHRINK:
first_visible = 0; /* always visible (until last point removed) */
- last_visible = (size_t)(totpoints * (1.0f - fac));
+ last_visible = (size_t)(totpoints * (1.0f + set_fade_fac - use_fac));
+ fade_start = (int)roundf(totpoints * (1.0f - use_fade_fac - set_fade_fac));
+ fade_end = last_visible;
break;
/* Hide in forward order
* - As fac increases, the early points start getting hidden
*/
- case GP_BUILD_TRANSITION_FADE:
- first_visible = (size_t)(totpoints * fac);
+ case GP_BUILD_TRANSITION_VANISH:
+ first_visible = (size_t)(totpoints * use_fade_fac);
last_visible = totpoints; /* i.e. visible until the end, unless first overlaps this */
+ fade_start = first_visible;
+ fade_end = (int)roundf(totpoints * use_fac);
break;
}
@@ -277,6 +390,30 @@ static void build_sequential(
clear_stroke(gpf, cell->gps);
}
else {
+ if (fade_start != fade_end && (int)cell->start_idx < fade_end &&
+ (int)cell->end_idx > fade_start) {
+ int start_index = fade_start - cell->start_idx;
+ int end_index = cell->totpoints + fade_end - cell->end_idx - 1;
+ CLAMP(start_index, 0, cell->totpoints - 1);
+ CLAMP(end_index, 0, cell->totpoints - 1);
+ float start_weight = ratiof(fade_start, fade_end, cell->start_idx + start_index);
+ float end_weight = ratiof(fade_start, fade_end, cell->start_idx + end_index);
+ if (mmd->transition != GP_BUILD_TRANSITION_VANISH) {
+ start_weight = 1.0f - start_weight;
+ end_weight = 1.0f - end_weight;
+ }
+ fade_stroke_points(cell->gps,
+ start_index,
+ end_index,
+ start_weight,
+ end_weight,
+ target_def_nr,
+ mmd->transition,
+ mmd->fade_thickness_strength,
+ mmd->fade_opacity_strength);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, cell->gps);
+ }
/* Some proportion of stroke is visible */
if ((first_visible <= cell->start_idx) && (last_visible >= cell->end_idx)) {
/* Do nothing - whole stroke is visible */
@@ -284,12 +421,12 @@ static void build_sequential(
else if (first_visible > cell->start_idx) {
/* Starts partway through this stroke */
int num_points = cell->end_idx - first_visible;
- reduce_stroke_points(gpd, cell->gps, num_points, mmd->transition);
+ reduce_stroke_points(gpd, gpf, cell->gps, num_points, mmd->transition);
}
else {
/* Ends partway through this stroke */
int num_points = last_visible - cell->start_idx;
- reduce_stroke_points(gpd, cell->gps, num_points, mmd->transition);
+ reduce_stroke_points(gpd, gpf, cell->gps, num_points, mmd->transition);
}
}
}
@@ -304,6 +441,7 @@ static void build_sequential(
static void build_concurrent(BuildGpencilModifierData *mmd,
bGPdata *gpd,
bGPDframe *gpf,
+ const int target_def_nr,
float fac)
{
bGPDstroke *gps, *gps_next;
@@ -323,6 +461,12 @@ static void build_concurrent(BuildGpencilModifierData *mmd,
return;
}
+ bool fading_enabled = (mmd->flag & GP_BUILD_USE_FADING);
+ float set_fade_fac = fading_enabled ? mmd->fade_fac : 0.0f;
+ float use_fac = interpf(1 + set_fade_fac, 0, fac);
+ use_fac = reverse ? use_fac - set_fade_fac : use_fac;
+ int fade_points = set_fade_fac * max_points;
+
/* 2) For each stroke, determine how it should be handled */
for (gps = gpf->strokes.first; gps; gps = gps_next) {
gps_next = gps->next;
@@ -338,26 +482,14 @@ static void build_concurrent(BuildGpencilModifierData *mmd,
switch (mmd->time_alignment) {
case GP_BUILD_TIMEALIGN_START: /* all start on frame 1 */
{
- /* Build effect occurs over when fac = 0, to fac = relative_len */
- if (fac <= relative_len) {
- /* Scale fac to fit relative_len */
- const float scaled_fac = fac / MAX2(relative_len, PSEUDOINVERSE_EPSILON);
+ /* Scale fac to fit relative_len */
+ const float scaled_fac = use_fac / MAX2(relative_len, PSEUDOINVERSE_EPSILON);
- if (reverse) {
- num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
- }
- else {
- num_points = (int)roundf(scaled_fac * gps->totpoints);
- }
+ if (reverse) {
+ num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
}
else {
- /* Build effect has ended */
- if (reverse) {
- num_points = 0;
- }
- else {
- num_points = gps->totpoints;
- }
+ num_points = (int)roundf(scaled_fac * gps->totpoints);
}
break;
@@ -368,24 +500,13 @@ static void build_concurrent(BuildGpencilModifierData *mmd,
*/
const float start_fac = 1.0f - relative_len;
- if (fac >= start_fac) {
- const float scaled_fac = (fac - start_fac) / MAX2(relative_len, PSEUDOINVERSE_EPSILON);
+ const float scaled_fac = (use_fac - start_fac) / MAX2(relative_len, PSEUDOINVERSE_EPSILON);
- if (reverse) {
- num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
- }
- else {
- num_points = (int)roundf(scaled_fac * gps->totpoints);
- }
+ if (reverse) {
+ num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints);
}
else {
- /* Build effect hasn't started */
- if (reverse) {
- num_points = gps->totpoints;
- }
- else {
- num_points = 0;
- }
+ num_points = (int)roundf(scaled_fac * gps->totpoints);
}
break;
@@ -397,17 +518,50 @@ static void build_concurrent(BuildGpencilModifierData *mmd,
/* Nothing Left - Delete the stroke */
clear_stroke(gpf, gps);
}
- else if (num_points < gps->totpoints) {
- /* Remove some points */
- reduce_stroke_points(gpd, gps, num_points, mmd->transition);
+ else {
+ int more_points = num_points - gps->totpoints;
+ CLAMP(more_points, 0, fade_points + 1);
+ float max_weight = (float)(num_points + more_points) / fade_points;
+ CLAMP(max_weight, 0.0f, 1.0f);
+ int starting_index = mmd->transition == GP_BUILD_TRANSITION_VANISH ?
+ gps->totpoints - num_points - more_points :
+ num_points - 1 - fade_points + more_points;
+ int ending_index = mmd->transition == GP_BUILD_TRANSITION_VANISH ?
+ gps->totpoints - num_points + fade_points - more_points :
+ num_points - 1 + more_points;
+ float starting_weight = mmd->transition == GP_BUILD_TRANSITION_VANISH ?
+ ((float)more_points / fade_points) :
+ max_weight;
+ float ending_weight = mmd->transition == GP_BUILD_TRANSITION_VANISH ?
+ max_weight :
+ ((float)more_points / fade_points);
+ CLAMP(starting_index, 0, gps->totpoints - 1);
+ CLAMP(ending_index, 0, gps->totpoints - 1);
+ fade_stroke_points(gps,
+ starting_index,
+ ending_index,
+ starting_weight,
+ ending_weight,
+ target_def_nr,
+ mmd->transition,
+ mmd->fade_thickness_strength,
+ mmd->fade_opacity_strength);
+ if (num_points < gps->totpoints) {
+ /* Remove some points */
+ reduce_stroke_points(gpd, gpf, gps, num_points, mmd->transition);
+ }
}
}
}
/* --------------------------------------------- */
-static void generate_geometry(
- GpencilModifierData *md, Depsgraph *depsgraph, bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf)
+static void generate_geometry(GpencilModifierData *md,
+ Depsgraph *depsgraph,
+ Object *ob,
+ bGPdata *gpd,
+ bGPDlayer *gpl,
+ bGPDframe *gpf)
{
BuildGpencilModifierData *mmd = (BuildGpencilModifierData *)md;
if (mmd->mode == GP_BUILD_MODE_ADDITIVE) {
@@ -450,6 +604,25 @@ static void generate_geometry(
}
}
+ int target_def_nr = -1;
+ if (mmd->flag & GP_BUILD_USE_FADING) {
+ /* If there are weight output, initialize it with a default weight of 1. */
+ target_def_nr = BKE_object_defgroup_name_index(ob, mmd->target_vgname);
+ if (target_def_nr >= 0) {
+ LISTBASE_FOREACH (bGPDstroke *, fgps, &gpf->strokes) {
+ BKE_gpencil_dvert_ensure(fgps);
+ /* Assign a initial weight of 1, and only process those who needs additional fading. */
+ for (int j = 0; j < fgps->totpoints; j++) {
+ MDeformVert *dvert = &fgps->dvert[j];
+ MDeformWeight *dw = BKE_defvert_ensure_index(dvert, target_def_nr);
+ if (dw) {
+ dw->weight = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
/* Early exit if outside of the frame range for this modifier
* (e.g. to have one forward, and one backwards modifier)
*/
@@ -517,15 +690,15 @@ static void generate_geometry(
/* Time management mode */
switch (mmd->mode) {
case GP_BUILD_MODE_SEQUENTIAL:
- build_sequential(mmd, gpd, gpf, fac, false);
+ build_sequential(ob, mmd, gpd, gpf, target_def_nr, fac, false);
break;
case GP_BUILD_MODE_CONCURRENT:
- build_concurrent(mmd, gpd, gpf, fac);
+ build_concurrent(mmd, gpd, gpf, target_def_nr, fac);
break;
case GP_BUILD_MODE_ADDITIVE:
- build_sequential(mmd, gpd, gpf, fac, true);
+ build_sequential(ob, mmd, gpd, gpf, target_def_nr, fac, true);
break;
default:
@@ -547,7 +720,7 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
if (gpf == NULL) {
continue;
}
- generate_geometry(md, depsgraph, gpd, gpl, gpf);
+ generate_geometry(md, depsgraph, ob, gpd, gpl, gpf);
}
}
@@ -591,6 +764,12 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(sub, ptr, "percentage_factor", 0, "", ICON_NONE);
uiItemDecoratorR(row, ptr, "percentage_factor", 0);
+ uiItemS(layout);
+
+ if (ELEM(mode, GP_BUILD_MODE_SEQUENTIAL, GP_BUILD_MODE_ADDITIVE)) {
+ uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
+ }
+
/* Check for incompatible time modifier. */
Object *ob = ob_ptr.data;
GpencilModifierData *md = ptr->data;
@@ -624,6 +803,40 @@ static void frame_range_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
}
+static void fading_header_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
+
+ uiItemR(layout, ptr, "use_fading", 0, IFACE_("Fading"), ICON_NONE);
+}
+
+static void fading_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *col;
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ uiLayoutSetPropSep(layout, true);
+
+ uiItemR(layout, ptr, "fade_factor", 0, IFACE_("Factor"), ICON_NONE);
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "fade_thickness_strength", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "fade_opacity_strength", 0, NULL, ICON_NONE);
+
+ uiItemPointerR(layout,
+ ptr,
+ "target_vertex_group",
+ &ob_ptr,
+ "vertex_groups",
+ IFACE_("Weight Output"),
+ ICON_NONE);
+}
+
static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
gpencil_modifier_masking_panel_draw(panel, false, false);
@@ -636,9 +849,30 @@ static void panelRegister(ARegionType *region_type)
gpencil_modifier_subpanel_register(
region_type, "frame_range", "", frame_range_header_draw, frame_range_panel_draw, panel_type);
gpencil_modifier_subpanel_register(
+ region_type, "fading", "", fading_header_draw, fading_panel_draw, panel_type);
+ gpencil_modifier_subpanel_register(
region_type, "_mask", "Influence", NULL, mask_panel_draw, panel_type);
}
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ BuildGpencilModifierData *mmd = (BuildGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->object, IDWALK_CB_NOP);
+}
+
+static void updateDepsgraph(GpencilModifierData *md,
+ const ModifierUpdateDepsgraphContext *ctx,
+ const int UNUSED(mode))
+{
+ BuildGpencilModifierData *lmd = (BuildGpencilModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Build Modifier");
+ DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Build Modifier");
+ }
+ DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Build Modifier");
+}
+
/* ******************************************** */
GpencilModifierTypeInfo modifierType_Gpencil_Build = {
@@ -658,9 +892,9 @@ GpencilModifierTypeInfo modifierType_Gpencil_Build = {
/* initData */ initData,
/* freeData */ NULL,
/* isDisabled */ NULL,
- /* updateDepsgraph */ NULL,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
- /* foreachIDLink */ NULL,
+ /* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
/* panelRegister */ panelRegister,
};