Blender  V2.93
MOD_gpencilnoise.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2017, Blender Foundation
17  * This is a new part of Blender
18  */
19 
24 #include <stdio.h>
25 
26 #include "BLI_listbase.h"
27 #include "BLI_utildefines.h"
28 
29 #include "BLI_hash.h"
30 #include "BLI_math_vector.h"
31 
32 #include "BLT_translation.h"
33 
34 #include "MEM_guardedalloc.h"
35 
36 #include "DNA_defaults.h"
38 #include "DNA_gpencil_types.h"
39 #include "DNA_meshdata_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_screen_types.h"
42 
43 #include "BKE_colortools.h"
44 #include "BKE_context.h"
45 #include "BKE_deform.h"
46 #include "BKE_gpencil.h"
47 #include "BKE_gpencil_geom.h"
48 #include "BKE_gpencil_modifier.h"
49 #include "BKE_lib_query.h"
50 #include "BKE_modifier.h"
51 #include "BKE_screen.h"
52 
53 #include "DEG_depsgraph.h"
54 #include "DEG_depsgraph_query.h"
55 
56 #include "UI_interface.h"
57 #include "UI_resources.h"
58 
59 #include "RNA_access.h"
60 
62 #include "MOD_gpencil_ui_common.h"
63 #include "MOD_gpencil_util.h"
64 
65 static void initData(GpencilModifierData *md)
66 {
68 
69  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
70 
72 
73  gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
77 }
78 
79 static void freeData(GpencilModifierData *md)
80 {
82 
83  if (gpmd->curve_intensity) {
85  }
86 }
87 
88 static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
89 {
92 
93  if (tgmd->curve_intensity != NULL) {
95  tgmd->curve_intensity = NULL;
96  }
97 
99 
101 }
102 
104 {
106  return (mmd->flag & GP_NOISE_USE_RANDOM) != 0;
107 }
108 
109 static float *noise_table(int len, int offset, int seed)
110 {
111  float *table = MEM_callocN(sizeof(float) * len, __func__);
112  for (int i = 0; i < len; i++) {
113  table[i] = BLI_hash_int_01(BLI_hash_int_2d(seed, i + offset + 1));
114  }
115  return table;
116 }
117 
118 BLI_INLINE float table_sample(float *table, float x)
119 {
120  return interpf(table[(int)ceilf(x)], table[(int)floor(x)], fractf(x));
121 }
122 
128  Object *ob,
129  bGPDlayer *gpl,
130  bGPDframe *gpf,
131  bGPDstroke *gps)
132 {
134  MDeformVert *dvert = NULL;
135  /* Noise value in range [-1..1] */
136  float normal[3];
137  float vec1[3], vec2[3];
138  const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
139  const bool invert_group = (mmd->flag & GP_NOISE_INVERT_VGROUP) != 0;
140  const bool use_curve = (mmd->flag & GP_NOISE_CUSTOM_CURVE) != 0 && mmd->curve_intensity;
141 
143  mmd->layername,
144  mmd->material,
145  mmd->pass_index,
146  mmd->layer_pass,
147  1,
148  gpl,
149  gps,
151  mmd->flag & GP_NOISE_INVERT_PASS,
153  mmd->flag & GP_NOISE_INVERT_MATERIAL)) {
154  return;
155  }
156 
157  int seed = mmd->seed;
158  /* FIXME(fclem): This is really slow. We should get the stroke index in another way. */
159  int stroke_seed = BLI_findindex(&gpf->strokes, gps);
160  seed += stroke_seed;
161 
162  /* Make sure different modifiers get different seeds. */
163  seed += BLI_hash_string(ob->id.name + 2);
164  seed += BLI_hash_string(md->name);
165 
166  if (mmd->flag & GP_NOISE_USE_RANDOM) {
167  seed += ((int)DEG_get_ctime(depsgraph)) / mmd->step;
168  }
169 
170  /* Sanitize as it can create out of bound reads. */
171  float noise_scale = clamp_f(mmd->noise_scale, 0.0f, 1.0f);
172 
173  int len = ceilf(gps->totpoints * noise_scale) + 2;
174  float *noise_table_position = (mmd->factor > 0.0f) ?
175  noise_table(len, (int)floor(mmd->noise_offset), seed + 2) :
176  NULL;
177  float *noise_table_strength = (mmd->factor_strength > 0.0f) ?
178  noise_table(len, (int)floor(mmd->noise_offset), seed + 3) :
179  NULL;
180  float *noise_table_thickness = (mmd->factor_thickness > 0.0f) ?
181  noise_table(len, (int)floor(mmd->noise_offset), seed) :
182  NULL;
183  float *noise_table_uvs = (mmd->factor_uvs > 0.0f) ?
184  noise_table(len, (int)floor(mmd->noise_offset), seed + 4) :
185  NULL;
186 
187  /* Calculate stroke normal. */
188  if (gps->totpoints > 2) {
190  if (is_zero_v3(normal)) {
191  copy_v3_fl(normal, 1.0f);
192  }
193  }
194  else {
195  copy_v3_fl(normal, 1.0f);
196  }
197 
198  /* move points */
199  for (int i = 0; i < gps->totpoints; i++) {
200  bGPDspoint *pt = &gps->points[i];
201  /* verify vertex group */
202  dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
203  float weight = get_modifier_point_weight(dvert, invert_group, def_nr);
204  if (weight < 0.0f) {
205  continue;
206  }
207 
208  if (use_curve) {
209  float value = (float)i / (gps->totpoints - 1);
210  weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value);
211  }
212 
213  if (mmd->factor > 0.0f) {
214  /* Offset point randomly around the bi-normal vector. */
215  if (gps->totpoints == 1) {
216  copy_v3_fl3(vec1, 1.0f, 0.0f, 0.0f);
217  }
218  else if (i != gps->totpoints - 1) {
219  /* Initial vector (p1 -> p0). */
220  sub_v3_v3v3(vec1, &gps->points[i].x, &gps->points[i + 1].x);
221  /* if vec2 is zero, set to something */
222  if (len_squared_v3(vec1) < 1e-8f) {
223  copy_v3_fl3(vec1, 1.0f, 0.0f, 0.0f);
224  }
225  }
226  else {
227  /* Last point reuse the penultimate normal (still stored in vec1)
228  * because the previous point is already modified. */
229  }
230  /* Vector orthogonal to normal. */
231  cross_v3_v3v3(vec2, vec1, normal);
232  normalize_v3(vec2);
233 
234  float noise = table_sample(noise_table_position,
235  i * noise_scale + fractf(mmd->noise_offset));
236  madd_v3_v3fl(&pt->x, vec2, (noise * 2.0f - 1.0f) * weight * mmd->factor * 0.1f);
237  }
238 
239  if (mmd->factor_thickness > 0.0f) {
240  float noise = table_sample(noise_table_thickness,
241  i * noise_scale + fractf(mmd->noise_offset));
242  pt->pressure *= max_ff(1.0f + (noise * 2.0f - 1.0f) * weight * mmd->factor_thickness, 0.0f);
244  }
245 
246  if (mmd->factor_strength > 0.0f) {
247  float noise = table_sample(noise_table_strength,
248  i * noise_scale + fractf(mmd->noise_offset));
249  pt->strength *= max_ff(1.0f - noise * weight * mmd->factor_strength, 0.0f);
250  CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
251  }
252 
253  if (mmd->factor_uvs > 0.0f) {
254  float noise = table_sample(noise_table_uvs, i * noise_scale + fractf(mmd->noise_offset));
255  pt->uv_rot += (noise * 2.0f - 1.0f) * weight * mmd->factor_uvs * M_PI_2;
256  CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
257  }
258  }
259 
260  MEM_SAFE_FREE(noise_table_position);
261  MEM_SAFE_FREE(noise_table_strength);
262  MEM_SAFE_FREE(noise_table_thickness);
263  MEM_SAFE_FREE(noise_table_uvs);
264 }
265 
266 static void bakeModifier(struct Main *UNUSED(bmain),
269  Object *ob)
270 {
271  bGPdata *gpd = ob->data;
272 
273  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
274  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
275  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
276  deformStroke(md, depsgraph, ob, gpl, gpf, gps);
277  }
278  }
279  }
280 }
281 
282 static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
283 {
285 
286  walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
287 }
288 
289 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
290 {
291  uiLayout *col;
292  uiLayout *layout = panel->layout;
293 
295 
296  uiLayoutSetPropSep(layout, true);
297 
298  col = uiLayoutColumn(layout, false);
299  uiItemR(col, ptr, "factor", 0, IFACE_("Position"), ICON_NONE);
300  uiItemR(col, ptr, "factor_strength", 0, IFACE_("Strength"), ICON_NONE);
301  uiItemR(col, ptr, "factor_thickness", 0, IFACE_("Thickness"), ICON_NONE);
302  uiItemR(col, ptr, "factor_uvs", 0, IFACE_("UV"), ICON_NONE);
303  uiItemR(col, ptr, "noise_scale", 0, NULL, ICON_NONE);
304  uiItemR(col, ptr, "noise_offset", 0, NULL, ICON_NONE);
305  uiItemR(col, ptr, "seed", 0, NULL, ICON_NONE);
306 
308 }
309 
310 static void random_header_draw(const bContext *UNUSED(C), Panel *panel)
311 {
312  uiLayout *layout = panel->layout;
313 
315 
316  uiItemR(layout, ptr, "random", 0, IFACE_("Randomize"), ICON_NONE);
317 }
318 
319 static void random_panel_draw(const bContext *UNUSED(C), Panel *panel)
320 {
321  uiLayout *layout = panel->layout;
322 
324 
325  uiLayoutSetPropSep(layout, true);
326 
327  uiLayoutSetActive(layout, RNA_boolean_get(ptr, "random"));
328 
329  uiItemR(layout, ptr, "step", 0, NULL, ICON_NONE);
330 }
331 
332 static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
333 {
334  gpencil_modifier_masking_panel_draw(panel, true, true);
335 }
336 
337 static void panelRegister(ARegionType *region_type)
338 {
340  region_type, eGpencilModifierType_Noise, panel_draw);
342  region_type, "randomize", "", random_header_draw, random_panel_draw, panel_type);
344  region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
346  "curve",
347  "",
350  mask_panel_type);
351 }
352 
354  /* name */ "Noise",
355  /* structName */ "NoiseGpencilModifierData",
356  /* structSize */ sizeof(NoiseGpencilModifierData),
359 
360  /* copyData */ copyData,
361 
362  /* deformStroke */ deformStroke,
363  /* generateStrokes */ NULL,
364  /* bakeModifier */ bakeModifier,
365  /* remapTime */ NULL,
366 
367  /* initData */ initData,
368  /* freeData */ freeData,
369  /* isDisabled */ NULL,
370  /* updateDepsgraph */ NULL,
371  /* dependsOnTime */ dependsOnTime,
372  /* foreachIDLink */ foreachIDLink,
373  /* foreachTexLink */ NULL,
374  /* panelRegister */ panelRegister,
375 };
typedef float(TangentPoint)[2]
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1200
struct CurveMapping * BKE_curvemapping_copy(const struct CurveMapping *cumap)
float BKE_curvemapping_evaluateF(const struct CurveMapping *cumap, int cur, float value)
void BKE_curvemap_reset(struct CurveMap *cuma, const struct rctf *clipr, int preset, int slope)
void BKE_curvemapping_free(struct CurveMapping *cumap)
Definition: colortools.c:119
@ CURVEMAP_SLOPE_POSITIVE
struct CurveMapping * BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
Definition: colortools.c:88
support for deformation groups and hooks.
int BKE_object_defgroup_name_index(const struct Object *ob, const char *name)
#define GPENCIL_STRENGTH_MIN
Definition: BKE_gpencil.h:178
void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3])
void BKE_gpencil_modifier_copydata_generic(const struct GpencilModifierData *md_src, struct GpencilModifierData *md_dst)
@ eGpencilModifierTypeFlag_SupportsEditmode
@ eGpencilModifierTypeType_Gpencil
@ IDWALK_CB_USER
Definition: BKE_lib_query.h:87
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:120
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
BLI_INLINE float BLI_hash_int_01(unsigned int k)
Definition: BLI_hash.h:108
BLI_INLINE unsigned int BLI_hash_string(const char *str)
Definition: BLI_hash.h:83
BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
Definition: BLI_hash.h:67
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
MINLINE float clamp_f(float value, float min, float max)
#define M_PI_2
Definition: BLI_math_base.h:41
MINLINE float interpf(float a, float b, float t)
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z)
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_fl(float r[3], float f)
#define UNUSED(x)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define CLAMP_MIN(a, b)
#define IFACE_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
float DEG_get_ctime(const Depsgraph *graph)
@ CURVE_PRESET_BELL
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:44
@ eGpencilModifierType_Noise
@ GP_NOISE_INVERT_VGROUP
@ GP_NOISE_INVERT_MATERIAL
@ GP_NOISE_INVERT_LAYERPASS
struct NoiseGpencilModifierData NoiseGpencilModifierData
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
PointerRNA * gpencil_modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void gpencil_modifier_masking_panel_draw(Panel *panel, bool use_material, bool use_vertex)
void gpencil_modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * gpencil_modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
PanelType * gpencil_modifier_panel_register(ARegionType *region_type, GpencilModifierType type, PanelDrawFn draw)
void gpencil_modifier_curve_header_draw(const bContext *UNUSED(C), Panel *panel)
void gpencil_modifier_curve_panel_draw(const bContext *UNUSED(C), Panel *panel)
float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr)
bool is_stroke_affected_by_modifier(Object *ob, char *mlayername, Material *material, const int mpassindex, const int gpl_passindex, const int minpoints, bGPDlayer *gpl, bGPDstroke *gps, const bool inv1, const bool inv2, const bool inv3, const bool inv4)
static float * noise_table(int len, int offset, int seed)
BLI_INLINE float table_sample(float *table, float x)
static void freeData(GpencilModifierData *md)
static void random_header_draw(const bContext *UNUSED(C), Panel *panel)
static void bakeModifier(struct Main *UNUSED(bmain), Depsgraph *depsgraph, GpencilModifierData *md, Object *ob)
static void random_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
static bool dependsOnTime(GpencilModifierData *md)
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
static void deformStroke(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps)
static void panelRegister(ARegionType *region_type)
GpencilModifierTypeInfo modifierType_Gpencil_Noise
static void initData(GpencilModifierData *md)
Group RGB to Bright Vector Camera CLAMP
#define C
Definition: RandGen.cpp:39
void uiLayoutSetActive(uiLayout *layout, bool active)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
static unsigned long seed
Definition: btSoftBody.h:39
Curve curve
const Depsgraph * depsgraph
uint col
IconTextureDrawCall normal
#define ceilf(x)
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
MINLINE float fractf(float a)
static float noise(int n)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
Definition: BKE_main.h:116
struct CurveMapping * curve_intensity
void * data
struct uiLayout * layout
ListBase strokes
bGPDspoint * points
struct MDeformVert * dvert
ListBase layers
ccl_device_inline float2 floor(const float2 &a)
uint len
PointerRNA * ptr
Definition: wm_files.c:3157