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
This commit is contained in:
parent
0e0977f3e6
commit
c4e4924096
|
@ -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);
|
||||
|
@ -635,10 +848,31 @@ static void panelRegister(ARegionType *region_type)
|
|||
region_type, eGpencilModifierType_Build, panel_draw);
|
||||
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,
|
||||
};
|
||||
|
|
|
@ -392,9 +392,20 @@ typedef struct BuildGpencilModifierData {
|
|||
* For the "Concurrent" mode, when should "shorter" strips start/end.
|
||||
*/
|
||||
short time_alignment;
|
||||
|
||||
/** Build origin control object. */
|
||||
struct Object *object;
|
||||
|
||||
/** Factor of the stroke (used instead of frame evaluation. */
|
||||
float percentage_fac;
|
||||
char _pad[4];
|
||||
|
||||
/** Weight fading at the end of the stroke. */
|
||||
float fade_fac;
|
||||
/** Target vertexgroup name, MAX_VGROUP_NAME. */
|
||||
char target_vgname[64];
|
||||
/** Fading strength of opacity and thickness */
|
||||
float fade_opacity_strength;
|
||||
float fade_thickness_strength;
|
||||
} BuildGpencilModifierData;
|
||||
|
||||
typedef enum eBuildGpencil_Mode {
|
||||
|
@ -412,7 +423,7 @@ typedef enum eBuildGpencil_Transition {
|
|||
/* Hide in reverse order */
|
||||
GP_BUILD_TRANSITION_SHRINK = 1,
|
||||
/* Hide in forward order */
|
||||
GP_BUILD_TRANSITION_FADE = 2,
|
||||
GP_BUILD_TRANSITION_VANISH = 2,
|
||||
} eBuildGpencil_Transition;
|
||||
|
||||
typedef enum eBuildGpencil_TimeAlignment {
|
||||
|
@ -435,6 +446,7 @@ typedef enum eBuildGpencil_Flag {
|
|||
|
||||
/* Use a percentage instead of frame number to evaluate strokes. */
|
||||
GP_BUILD_PERCENTAGE = (1 << 4),
|
||||
GP_BUILD_USE_FADING = (1 << 5),
|
||||
} eBuildGpencil_Flag;
|
||||
|
||||
typedef struct LatticeGpencilModifierData {
|
||||
|
|
|
@ -382,6 +382,7 @@ RNA_GP_MOD_VGROUP_NAME_SET(WeightAngle, vgname);
|
|||
RNA_GP_MOD_VGROUP_NAME_SET(Lineart, vgname);
|
||||
RNA_GP_MOD_VGROUP_NAME_SET(Shrinkwrap, vgname);
|
||||
RNA_GP_MOD_VGROUP_NAME_SET(Envelope, vgname);
|
||||
RNA_GP_MOD_VGROUP_NAME_SET(Build, target_vgname);
|
||||
|
||||
# undef RNA_GP_MOD_VGROUP_NAME_SET
|
||||
|
||||
|
@ -416,6 +417,7 @@ RNA_GP_MOD_OBJECT_SET(Mirror, object, OB_EMPTY);
|
|||
RNA_GP_MOD_OBJECT_SET(WeightProx, object, OB_EMPTY);
|
||||
RNA_GP_MOD_OBJECT_SET(Shrinkwrap, target, OB_MESH);
|
||||
RNA_GP_MOD_OBJECT_SET(Shrinkwrap, aux_target, OB_MESH);
|
||||
RNA_GP_MOD_OBJECT_SET(Build, object, OB_EMPTY);
|
||||
|
||||
# undef RNA_GP_MOD_OBJECT_SET
|
||||
|
||||
|
@ -2133,10 +2135,10 @@ static void rna_def_modifier_gpencilbuild(BlenderRNA *brna)
|
|||
"Shrink",
|
||||
"Hide points from the end of each stroke to the start "
|
||||
"(e.g. for animating lines being erased)"},
|
||||
{GP_BUILD_TRANSITION_FADE,
|
||||
"FADE",
|
||||
{GP_BUILD_TRANSITION_VANISH,
|
||||
"FADE", /* "Fade" is the original id string kept for compatibility purpose. */
|
||||
0,
|
||||
"Fade",
|
||||
"Vanish",
|
||||
"Hide points in the order they occur in each stroke "
|
||||
"(e.g. for animating ink fading or vanishing after getting drawn)"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
|
@ -2242,6 +2244,44 @@ static void rna_def_modifier_gpencilbuild(BlenderRNA *brna)
|
|||
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_fading", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BUILD_USE_FADING);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Use Fading", "Fade out strokes instead of directly cutting off.");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "fade_factor", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "fade_fac");
|
||||
RNA_def_property_ui_text(prop, "Fade Factor", "Defines how much of the stroke is fading in/out");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "target_vertex_group", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "target_vgname");
|
||||
RNA_def_property_ui_text(prop, "Vertex Group", "Output Vertex group");
|
||||
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_BuildGpencilModifier_target_vgname_set");
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "fade_opacity_strength", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "fade_opacity_strength");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Opacity Strength", "How much strength fading applies on top of stroke opacity");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "fade_thickness_strength", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, NULL, "fade_thickness_strength");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Thickness Strength", "How much strength fading applies on top of stroke thickness");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Object", "Object used as build starting position");
|
||||
RNA_def_property_pointer_funcs(prop, NULL, "rna_BuildGpencilModifier_object_set", NULL, NULL);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
|
||||
RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
|
||||
|
||||
/* Filters - Layer */
|
||||
prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, NULL, "layername");
|
||||
|
|
Loading…
Reference in New Issue