Blender  V3.3
MOD_gpencilnoise.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2017 Blender Foundation. */
3 
8 #include <stdio.h>
9 
10 #include "BLI_hash.h"
11 #include "BLI_listbase.h"
12 #include "BLI_math_vector.h"
13 #include "BLI_utildefines.h"
14 
15 #include "BLT_translation.h"
16 
17 #include "MEM_guardedalloc.h"
18 
19 #include "DNA_defaults.h"
21 #include "DNA_gpencil_types.h"
22 #include "DNA_meshdata_types.h"
23 #include "DNA_object_types.h"
24 #include "DNA_screen_types.h"
25 
26 #include "BKE_colortools.h"
27 #include "BKE_context.h"
28 #include "BKE_deform.h"
29 #include "BKE_gpencil.h"
30 #include "BKE_gpencil_geom.h"
31 #include "BKE_gpencil_modifier.h"
32 #include "BKE_lib_query.h"
33 #include "BKE_modifier.h"
34 #include "BKE_screen.h"
35 
36 #include "DEG_depsgraph.h"
37 #include "DEG_depsgraph_query.h"
38 
39 #include "UI_interface.h"
40 #include "UI_resources.h"
41 
42 #include "RNA_access.h"
43 
45 #include "MOD_gpencil_ui_common.h"
46 #include "MOD_gpencil_util.h"
47 
48 static void initData(GpencilModifierData *md)
49 {
51 
52  BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
53 
55 
56  gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
60 }
61 
62 static void freeData(GpencilModifierData *md)
63 {
65 
66  if (gpmd->curve_intensity) {
68  }
69 }
70 
71 static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
72 {
75 
76  if (tgmd->curve_intensity != NULL) {
78  tgmd->curve_intensity = NULL;
79  }
80 
82 
84 }
85 
87 {
89  return (mmd->flag & GP_NOISE_USE_RANDOM) != 0;
90 }
91 
92 static float *noise_table(int len, int offset, int seed)
93 {
94  float *table = MEM_callocN(sizeof(float) * len, __func__);
95  for (int i = 0; i < len; i++) {
96  table[i] = BLI_hash_int_01(BLI_hash_int_2d(seed, i + offset + 1));
97  }
98  return table;
99 }
100 
101 BLI_INLINE float table_sample(float *table, float x)
102 {
103  return interpf(table[(int)ceilf(x)], table[(int)floor(x)], fractf(x));
104 }
105 
111  Object *ob,
112  bGPDlayer *gpl,
113  bGPDframe *gpf,
114  bGPDstroke *gps)
115 {
117  MDeformVert *dvert = NULL;
118  /* Noise value in range [-1..1] */
119  float normal[3];
120  float vec1[3], vec2[3];
121  const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname);
122  const bool invert_group = (mmd->flag & GP_NOISE_INVERT_VGROUP) != 0;
123  const bool use_curve = (mmd->flag & GP_NOISE_CUSTOM_CURVE) != 0 && mmd->curve_intensity;
124  const int cfra = (int)DEG_get_ctime(depsgraph);
125  const bool is_keyframe = (mmd->noise_mode == GP_NOISE_RANDOM_KEYFRAME);
126 
128  mmd->layername,
129  mmd->material,
130  mmd->pass_index,
131  mmd->layer_pass,
132  1,
133  gpl,
134  gps,
136  mmd->flag & GP_NOISE_INVERT_PASS,
138  mmd->flag & GP_NOISE_INVERT_MATERIAL)) {
139  return;
140  }
141 
142  int seed = mmd->seed;
143  /* FIXME(fclem): This is really slow. We should get the stroke index in another way. */
144  int stroke_seed = BLI_findindex(&gpf->strokes, gps);
145  seed += stroke_seed;
146 
147  /* Make sure different modifiers get different seeds. */
148  seed += BLI_hash_string(ob->id.name + 2);
149  seed += BLI_hash_string(md->name);
150 
151  if (mmd->flag & GP_NOISE_USE_RANDOM) {
152  if (!is_keyframe) {
153  seed += cfra / mmd->step;
154  }
155  else {
156  /* If change every keyframe, use the last keyframe. */
157  seed += gpf->framenum;
158  }
159  }
160 
161  /* Sanitize as it can create out of bound reads. */
162  float noise_scale = clamp_f(mmd->noise_scale, 0.0f, 1.0f);
163 
164  int len = ceilf(gps->totpoints * noise_scale) + 2;
165  float *noise_table_position = (mmd->factor > 0.0f) ?
166  noise_table(len, (int)floor(mmd->noise_offset), seed + 2) :
167  NULL;
168  float *noise_table_strength = (mmd->factor_strength > 0.0f) ?
169  noise_table(len, (int)floor(mmd->noise_offset), seed + 3) :
170  NULL;
171  float *noise_table_thickness = (mmd->factor_thickness > 0.0f) ?
172  noise_table(len, (int)floor(mmd->noise_offset), seed) :
173  NULL;
174  float *noise_table_uvs = (mmd->factor_uvs > 0.0f) ?
175  noise_table(len, (int)floor(mmd->noise_offset), seed + 4) :
176  NULL;
177 
178  /* Calculate stroke normal. */
179  if (gps->totpoints > 2) {
181  if (is_zero_v3(normal)) {
182  copy_v3_fl(normal, 1.0f);
183  }
184  }
185  else {
186  copy_v3_fl(normal, 1.0f);
187  }
188 
189  /* move points */
190  for (int i = 0; i < gps->totpoints; i++) {
191  bGPDspoint *pt = &gps->points[i];
192  /* verify vertex group */
193  dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
194  float weight = get_modifier_point_weight(dvert, invert_group, def_nr);
195  if (weight < 0.0f) {
196  continue;
197  }
198 
199  if (use_curve) {
200  float value = (float)i / (gps->totpoints - 1);
201  weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value);
202  }
203 
204  if (mmd->factor > 0.0f) {
205  /* Offset point randomly around the bi-normal vector. */
206  if (gps->totpoints == 1) {
207  copy_v3_fl3(vec1, 1.0f, 0.0f, 0.0f);
208  }
209  else if (i != gps->totpoints - 1) {
210  /* Initial vector (p1 -> p0). */
211  sub_v3_v3v3(vec1, &gps->points[i].x, &gps->points[i + 1].x);
212  /* if vec2 is zero, set to something */
213  if (len_squared_v3(vec1) < 1e-8f) {
214  copy_v3_fl3(vec1, 1.0f, 0.0f, 0.0f);
215  }
216  }
217  else {
218  /* Last point reuse the penultimate normal (still stored in vec1)
219  * because the previous point is already modified. */
220  }
221  /* Vector orthogonal to normal. */
222  cross_v3_v3v3(vec2, vec1, normal);
223  normalize_v3(vec2);
224 
225  float noise = table_sample(noise_table_position,
226  i * noise_scale + fractf(mmd->noise_offset));
227  madd_v3_v3fl(&pt->x, vec2, (noise * 2.0f - 1.0f) * weight * mmd->factor * 0.1f);
228  }
229 
230  if (mmd->factor_thickness > 0.0f) {
231  float noise = table_sample(noise_table_thickness,
232  i * noise_scale + fractf(mmd->noise_offset));
233  pt->pressure *= max_ff(1.0f + (noise * 2.0f - 1.0f) * weight * mmd->factor_thickness, 0.0f);
235  }
236 
237  if (mmd->factor_strength > 0.0f) {
238  float noise = table_sample(noise_table_strength,
239  i * noise_scale + fractf(mmd->noise_offset));
240  pt->strength *= max_ff(1.0f - noise * weight * mmd->factor_strength, 0.0f);
241  CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
242  }
243 
244  if (mmd->factor_uvs > 0.0f) {
245  float noise = table_sample(noise_table_uvs, i * noise_scale + fractf(mmd->noise_offset));
246  pt->uv_rot += (noise * 2.0f - 1.0f) * weight * mmd->factor_uvs * M_PI_2;
247  CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
248  }
249  }
250 
251  MEM_SAFE_FREE(noise_table_position);
252  MEM_SAFE_FREE(noise_table_strength);
253  MEM_SAFE_FREE(noise_table_thickness);
254  MEM_SAFE_FREE(noise_table_uvs);
255 }
256 
257 static void bakeModifier(struct Main *UNUSED(bmain),
260  Object *ob)
261 {
263 }
264 
265 static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
266 {
268 
269  walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
270 }
271 
272 static void panel_draw(const bContext *UNUSED(C), Panel *panel)
273 {
274  uiLayout *col;
275  uiLayout *layout = panel->layout;
276 
278 
279  uiLayoutSetPropSep(layout, true);
280 
281  col = uiLayoutColumn(layout, false);
282  uiItemR(col, ptr, "factor", 0, IFACE_("Position"), ICON_NONE);
283  uiItemR(col, ptr, "factor_strength", 0, IFACE_("Strength"), ICON_NONE);
284  uiItemR(col, ptr, "factor_thickness", 0, IFACE_("Thickness"), ICON_NONE);
285  uiItemR(col, ptr, "factor_uvs", 0, IFACE_("UV"), ICON_NONE);
286  uiItemR(col, ptr, "noise_scale", 0, NULL, ICON_NONE);
287  uiItemR(col, ptr, "noise_offset", 0, NULL, ICON_NONE);
288  uiItemR(col, ptr, "seed", 0, NULL, ICON_NONE);
289 
291 }
292 
293 static void random_header_draw(const bContext *UNUSED(C), Panel *panel)
294 {
295  uiLayout *layout = panel->layout;
296 
298 
299  uiItemR(layout, ptr, "use_random", 0, IFACE_("Randomize"), ICON_NONE);
300 }
301 
302 static void random_panel_draw(const bContext *UNUSED(C), Panel *panel)
303 {
304  uiLayout *layout = panel->layout;
305 
307 
308  uiLayoutSetPropSep(layout, true);
309 
310  uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_random"));
311 
312  uiItemR(layout, ptr, "random_mode", 0, NULL, ICON_NONE);
313 
314  const int mode = RNA_enum_get(ptr, "random_mode");
315  if (mode != GP_NOISE_RANDOM_KEYFRAME) {
316  uiItemR(layout, ptr, "step", 0, NULL, ICON_NONE);
317  }
318 }
319 
320 static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
321 {
322  gpencil_modifier_masking_panel_draw(panel, true, true);
323 }
324 
325 static void panelRegister(ARegionType *region_type)
326 {
328  region_type, eGpencilModifierType_Noise, panel_draw);
330  region_type, "randomize", "", random_header_draw, random_panel_draw, panel_type);
332  region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
334  "curve",
335  "",
338  mask_panel_type);
339 }
340 
342  /* name */ N_("Noise"),
343  /* structName */ "NoiseGpencilModifierData",
344  /* structSize */ sizeof(NoiseGpencilModifierData),
347 
348  /* copyData */ copyData,
349 
350  /* deformStroke */ deformStroke,
351  /* generateStrokes */ NULL,
352  /* bakeModifier */ bakeModifier,
353  /* remapTime */ NULL,
354 
355  /* initData */ initData,
356  /* freeData */ freeData,
357  /* isDisabled */ NULL,
358  /* updateDepsgraph */ NULL,
359  /* dependsOnTime */ dependsOnTime,
360  /* foreachIDLink */ foreachIDLink,
361  /* foreachTexLink */ NULL,
362  /* panelRegister */ panelRegister,
363 };
typedef float(TangentPoint)[2]
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1235
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:103
@ CURVEMAP_SLOPE_POSITIVE
struct CurveMapping * BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
Definition: colortools.c:72
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:324
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:73
void(* IDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag)
Definition: BKE_modifier.h:107
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
BLI_INLINE float BLI_hash_int_01(unsigned int k)
Definition: BLI_hash.h:94
BLI_INLINE unsigned int BLI_hash_string(const char *str)
Definition: BLI_hash.h:69
BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky)
Definition: BLI_hash.h:53
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:23
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:35
float DEG_get_ctime(const Depsgraph *graph)
@ CURVE_PRESET_BELL
#define DNA_struct_default_get(struct_name)
Definition: DNA_defaults.h:29
@ GP_NOISE_RANDOM_KEYFRAME
@ 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)
void generic_bake_deform_stroke(Depsgraph *depsgraph, GpencilModifierData *md, Object *ob, const bool retime, gpBakeCb bake_cb)
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 Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
#define C
Definition: RandGen.cpp:25
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
int len
Definition: draw_manager.c:108
uint col
IconTextureDrawCall normal
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
MINLINE float fractf(float a)
#define ceilf(x)
Definition: metal/compat.h:225
T floor(const T &a)
static float noise(int n)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
Definition: BKE_main.h:121
struct CurveMapping * curve_intensity
struct uiLayout * layout
ListBase strokes
bGPDspoint * points
struct MDeformVert * dvert
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480