Blender  V2.93
MOD_weightvg_util.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) 2011 by Bastien Montagne.
17  * All rights reserved.
18  */
19 
24 #include "BLI_utildefines.h"
25 
26 #include "BLI_math.h"
27 #include "BLI_rand.h"
28 #include "BLI_string.h"
29 
30 #include "BLT_translation.h"
31 
32 #include "DNA_color_types.h" /* CurveMapping. */
33 #include "DNA_mesh_types.h"
34 #include "DNA_meshdata_types.h"
35 #include "DNA_modifier_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38 
39 #include "BKE_colortools.h" /* CurveMapping. */
40 #include "BKE_context.h"
41 #include "BKE_customdata.h"
42 #include "BKE_deform.h"
43 #include "BKE_modifier.h"
44 #include "BKE_texture.h" /* Texture masking. */
45 
46 #include "UI_interface.h"
47 #include "UI_resources.h"
48 
49 #include "RNA_access.h"
50 
51 #include "DEG_depsgraph.h"
52 #include "DEG_depsgraph_query.h"
53 
54 #include "MEM_guardedalloc.h"
55 #include "MOD_ui_common.h"
56 #include "MOD_util.h"
57 #include "MOD_weightvg_util.h"
58 #include "RE_texture.h" /* Texture masking. */
59 
60 /* Maps new_w weights in place, using either one of the predefined functions, or a custom curve.
61  * Return values are in new_w.
62  * If indices is not NULL, it must be a table of same length as org_w and new_w,
63  * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
64  * cmap might be NULL, in which case curve mapping mode will return unmodified data.
65  */
67  int num, float *new_w, short falloff_type, const bool do_invert, CurveMapping *cmap, RNG *rng)
68 {
69  int i;
70 
71  /* Return immediately, if we have nothing to do! */
72  /* Also security checks... */
73  if (!do_invert && (((falloff_type == MOD_WVG_MAPPING_CURVE) && (cmap == NULL)) ||
74  !ELEM(falloff_type,
82  return;
83  }
84 
85  if (cmap && falloff_type == MOD_WVG_MAPPING_CURVE) {
87  }
88 
89  /* Map each weight (vertex) to its new value, accordingly to the chosen mode. */
90  for (i = 0; i < num; i++) {
91  float fac = new_w[i];
92 
93  /* Code borrowed from the warp modifier. */
94  /* Closely matches PROP_SMOOTH and similar. */
95  switch (falloff_type) {
97  fac = BKE_curvemapping_evaluateF(cmap, 0, fac);
98  break;
100  fac = fac * fac;
101  break;
103  fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
104  break;
106  fac = sqrtf(fac);
107  break;
109  fac = sqrtf(2 * fac - fac * fac);
110  break;
112  fac = BLI_rng_get_float(rng) * fac;
113  break;
115  fac = (fac >= 0.5f) ? 1.0f : 0.0f;
116  break;
118  BLI_assert(do_invert);
119  break;
120  default:
121  BLI_assert(0);
122  }
123 
124  new_w[i] = do_invert ? 1.0f - fac : fac;
125  }
126 }
127 
128 /* Applies new_w weights to org_w ones, using either a texture, vgroup or constant value as factor.
129  * Return values are in org_w.
130  * If indices is not NULL, it must be a table of same length as org_w and new_w,
131  * mapping to the real vertex index (in case the weight tables do not cover the whole vertices...).
132  * XXX The standard "factor" value is assumed in [0.0, 1.0] range.
133  * Else, weird results might appear.
134  */
136  const int num,
137  const int *indices,
138  float *org_w,
139  const float *new_w,
140  Object *ob,
141  Mesh *mesh,
142  const float fact,
143  const char defgrp_name[MAX_VGROUP_NAME],
144  Scene *scene,
145  Tex *texture,
146  const int tex_use_channel,
147  const int tex_mapping,
148  Object *tex_map_object,
149  const char *text_map_bone,
150  const char *tex_uvlayer_name,
151  const bool invert_vgroup_mask)
152 {
153  int ref_didx;
154  int i;
155 
156  /* If influence factor is null, nothing to do! */
157  if (fact == 0.0f) {
158  return;
159  }
160 
161  /* If we want to mask vgroup weights from a texture. */
162  if (texture != NULL) {
163  /* The texture coordinates. */
164  float(*tex_co)[3];
165  /* See mapping note below... */
167  const int numVerts = mesh->totvert;
168 
169  /* Use new generic get_texture_coords, but do not modify our DNA struct for it...
170  * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters ?
171  * What e.g. if a modifier wants to use several textures ?
172  * Why use only v_co, and not MVert (or both) ?
173  */
174  t_map.texture = texture;
175  t_map.map_object = tex_map_object;
176  BLI_strncpy(t_map.map_bone, text_map_bone, sizeof(t_map.map_bone));
177  BLI_strncpy(t_map.uvlayer_name, tex_uvlayer_name, sizeof(t_map.uvlayer_name));
178  t_map.texmapping = tex_mapping;
179 
180  tex_co = MEM_calloc_arrayN(numVerts, sizeof(*tex_co), "WeightVG Modifier, TEX mode, tex_co");
181  MOD_get_texture_coords(&t_map, ctx, ob, mesh, NULL, tex_co);
182 
183  MOD_init_texture(&t_map, ctx);
184 
185  /* For each weight (vertex), make the mix between org and new weights. */
186  for (i = 0; i < num; i++) {
187  int idx = indices ? indices[i] : i;
188  TexResult texres;
189  float hsv[3]; /* For HSV color space. */
190  bool do_color_manage;
191 
192  do_color_manage = tex_use_channel != MOD_WVG_MASK_TEX_USE_INT;
193 
194  texres.nor = NULL;
195  BKE_texture_get_value(scene, texture, tex_co[idx], &texres, do_color_manage);
196  /* Get the good channel value... */
197  switch (tex_use_channel) {
199  org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact)));
200  break;
202  org_w[i] = (new_w[i] * texres.tr * fact) + (org_w[i] * (1.0f - (texres.tr * fact)));
203  break;
205  org_w[i] = (new_w[i] * texres.tg * fact) + (org_w[i] * (1.0f - (texres.tg * fact)));
206  break;
208  org_w[i] = (new_w[i] * texres.tb * fact) + (org_w[i] * (1.0f - (texres.tb * fact)));
209  break;
211  rgb_to_hsv_v(&texres.tr, hsv);
212  org_w[i] = (new_w[i] * hsv[0] * fact) + (org_w[i] * (1.0f - (hsv[0] * fact)));
213  break;
215  rgb_to_hsv_v(&texres.tr, hsv);
216  org_w[i] = (new_w[i] * hsv[1] * fact) + (org_w[i] * (1.0f - (hsv[1] * fact)));
217  break;
219  rgb_to_hsv_v(&texres.tr, hsv);
220  org_w[i] = (new_w[i] * hsv[2] * fact) + (org_w[i] * (1.0f - (hsv[2] * fact)));
221  break;
223  org_w[i] = (new_w[i] * texres.ta * fact) + (org_w[i] * (1.0f - (texres.ta * fact)));
224  break;
225  default:
226  org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact)));
227  break;
228  }
229  }
230 
231  MEM_freeN(tex_co);
232  }
233  else if ((ref_didx = BKE_object_defgroup_name_index(ob, defgrp_name)) != -1) {
234  MDeformVert *dvert = NULL;
235 
236  /* Check whether we want to set vgroup weights from a constant weight factor or a vertex
237  * group.
238  */
239  /* Get vgroup idx from its name. */
240 
241  /* Proceed only if vgroup is valid, else use constant factor. */
242  /* Get actual dverts (ie vertex group data). */
243  dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
244  /* Proceed only if vgroup is valid, else assume factor = O. */
245  if (dvert == NULL) {
246  return;
247  }
248 
249  /* For each weight (vertex), make the mix between org and new weights. */
250  for (i = 0; i < num; i++) {
251  int idx = indices ? indices[i] : i;
252  const float f = (invert_vgroup_mask ?
253  (1.0f - BKE_defvert_find_weight(&dvert[idx], ref_didx)) :
254  BKE_defvert_find_weight(&dvert[idx], ref_didx)) *
255  fact;
256  org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0f - f));
257  /* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */
258  }
259  }
260  else {
261  /* Default "influence" behavior. */
262  /* For each weight (vertex), make the mix between org and new weights. */
263  const float ifact = 1.0f - fact;
264  for (i = 0; i < num; i++) {
265  org_w[i] = (new_w[i] * fact) + (org_w[i] * ifact);
266  }
267  }
268 }
269 
270 /* Applies weights to given vgroup (defgroup), and optionally add/remove vertices from the group.
271  * If dws is not NULL, it must be an array of MDeformWeight pointers of same length as weights (and
272  * defgrp_idx can then have any value).
273  * If indices is not NULL, it must be an array of same length as weights, mapping to the real
274  * vertex index (in case the weight array does not cover the whole vertices...).
275  */
277  int defgrp_idx,
278  MDeformWeight **dws,
279  int num,
280  const int *indices,
281  const float *weights,
282  const bool do_add,
283  const float add_thresh,
284  const bool do_rem,
285  const float rem_thresh,
286  const bool do_normalize)
287 {
288  int i;
289 
290  float min_w = weights[0];
291  float norm_fac = 1.0f;
292  if (do_normalize) {
293  float max_w = weights[0];
294  for (i = 1; i < num; i++) {
295  const float w = weights[i];
296 
297  /* No need to clamp here, normalization will ensure we stay within [0.0, 1.0] range. */
298  if (w < min_w) {
299  min_w = w;
300  }
301  else if (w > max_w) {
302  max_w = w;
303  }
304  }
305 
306  const float range = max_w - min_w;
307  if (fabsf(range) > FLT_EPSILON) {
308  norm_fac = 1.0f / range;
309  }
310  else {
311  min_w = 0.0f;
312  }
313  }
314 
315  for (i = 0; i < num; i++) {
316  float w = weights[i];
317  MDeformVert *dv = &dvert[indices ? indices[i] : i];
318  MDeformWeight *dw = dws ? dws[i] :
319  ((defgrp_idx >= 0) ? BKE_defvert_find_index(dv, defgrp_idx) : NULL);
320 
321  if (do_normalize) {
322  w = (w - min_w) * norm_fac;
323  }
324  /* Never allow weights out of [0.0, 1.0] range. */
325  CLAMP(w, 0.0f, 1.0f);
326 
327  /* If the vertex is in this vgroup, remove it if needed, or just update it. */
328  if (dw != NULL) {
329  if (do_rem && w < rem_thresh) {
330  BKE_defvert_remove_group(dv, dw);
331  }
332  else {
333  dw->weight = w;
334  }
335  }
336  /* Else, add it if needed! */
337  else if (do_add && w > add_thresh) {
338  BKE_defvert_add_index_notest(dv, defgrp_idx, w);
339  }
340  }
341 }
342 
343 /* Common vertex weight mask interface elements for the modifier panels.
344  */
346 {
347  PointerRNA mask_texture_ptr = RNA_pointer_get(ptr, "mask_texture");
348  bool has_mask_texture = !RNA_pointer_is_null(&mask_texture_ptr);
349  bool has_mask_vertex_group = RNA_string_length(ptr, "mask_vertex_group") != 0;
350  int mask_tex_mapping = RNA_enum_get(ptr, "mask_tex_mapping");
351 
352  uiLayoutSetPropSep(layout, true);
353 
354  uiItemR(layout, ptr, "mask_constant", UI_ITEM_R_SLIDER, IFACE_("Global Influence:"), ICON_NONE);
355 
356  if (!has_mask_texture) {
357  modifier_vgroup_ui(layout, ptr, ob_ptr, "mask_vertex_group", "invert_mask_vertex_group", NULL);
358  }
359 
360  if (!has_mask_vertex_group) {
361  uiTemplateID(layout,
362  C,
363  ptr,
364  "mask_texture",
365  "texture.new",
366  NULL,
367  NULL,
368  0,
369  ICON_NONE,
370  IFACE_("Mask Texture"));
371 
372  if (has_mask_texture) {
373  uiItemR(layout, ptr, "mask_tex_use_channel", 0, IFACE_("Channel"), ICON_NONE);
374  uiItemR(layout, ptr, "mask_tex_mapping", 0, NULL, ICON_NONE);
375 
376  if (mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
377  uiItemR(layout, ptr, "mask_tex_map_object", 0, IFACE_("Object"), ICON_NONE);
378  }
379  else if (mask_tex_mapping == MOD_DISP_MAP_UV && RNA_enum_get(ob_ptr, "type") == OB_MESH) {
380  PointerRNA obj_data_ptr = RNA_pointer_get(ob_ptr, "data");
382  layout, ptr, "mask_tex_uv_layer", &obj_data_ptr, "uv_layers", NULL, ICON_NONE);
383  }
384  }
385  }
386 }
typedef float(TangentPoint)[2]
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1200
float BKE_curvemapping_evaluateF(const struct CurveMapping *cumap, int cur, float value)
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_get_layer(const struct CustomData *data, int type)
support for deformation groups and hooks.
int BKE_object_defgroup_name_index(const struct Object *ob, const char *name)
struct MDeformWeight * BKE_defvert_find_index(const struct MDeformVert *dv, const int defgroup)
float BKE_defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
Definition: deform.c:632
void BKE_defvert_remove_group(struct MDeformVert *dvert, struct MDeformWeight *dw)
Definition: deform.c:754
void BKE_defvert_add_index_notest(struct MDeformVert *dv, int defgroup, const float weight)
Definition: deform.c:726
void BKE_texture_get_value(const struct Scene *scene, struct Tex *texture, const float *tex_co, struct TexResult *texres, bool use_color_management)
#define BLI_assert(a)
Definition: BLI_assert.h:58
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
Definition: math_color.c:254
Random number functions.
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: rand.cc:120
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define ELEM(...)
#define IFACE_(msgid)
@ CD_MDEFORMVERT
@ MOD_DISP_MAP_OBJECT
@ MOD_DISP_MAP_UV
@ MOD_WVG_MAPPING_SHARP
@ MOD_WVG_MAPPING_SPHERE
@ MOD_WVG_MAPPING_STEP
@ MOD_WVG_MAPPING_NONE
@ MOD_WVG_MAPPING_ROOT
@ MOD_WVG_MAPPING_CURVE
@ MOD_WVG_MAPPING_RANDOM
@ MOD_WVG_MAPPING_SMOOTH
@ MOD_WVG_MASK_TEX_USE_SAT
@ MOD_WVG_MASK_TEX_USE_BLUE
@ MOD_WVG_MASK_TEX_USE_INT
@ MOD_WVG_MASK_TEX_USE_ALPHA
@ MOD_WVG_MASK_TEX_USE_RED
@ MOD_WVG_MASK_TEX_USE_HUE
@ MOD_WVG_MASK_TEX_USE_VAL
@ MOD_WVG_MASK_TEX_USE_GREEN
Object is a sort of wrapper for general info.
#define MAX_VGROUP_NAME
@ OB_MESH
Read Guarded memory(de)allocation.
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const char *vgroup_prop, const char *invert_vgroup_prop, const char *text)
void MOD_init_texture(MappingInfoModifierData *dmd, const ModifierEvalContext *ctx)
Definition: MOD_util.c:61
void MOD_get_texture_coords(MappingInfoModifierData *dmd, const ModifierEvalContext *UNUSED(ctx), Object *ob, Mesh *mesh, float(*cos)[3], float(*r_texco)[3])
Definition: MOD_util.c:76
void weightvg_do_map(int num, float *new_w, short falloff_type, const bool do_invert, CurveMapping *cmap, RNG *rng)
void weightvg_update_vg(MDeformVert *dvert, int defgrp_idx, MDeformWeight **dws, int num, const int *indices, const float *weights, const bool do_add, const float add_thresh, const bool do_rem, const float rem_thresh, const bool do_normalize)
void weightvg_do_mask(const ModifierEvalContext *ctx, const int num, const int *indices, float *org_w, const float *new_w, Object *ob, Mesh *mesh, const float fact, const char defgrp_name[MAX_VGROUP_NAME], Scene *scene, Tex *texture, const int tex_use_channel, const int tex_mapping, Object *tex_map_object, const char *text_map_bone, const char *tex_uvlayer_name, const bool invert_vgroup_mask)
void weightvg_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiLayout *layout)
Group RGB to Bright Vector Camera CLAMP
#define C
Definition: RandGen.cpp:39
@ UI_ITEM_R_SLIDER
void uiTemplateID(uiLayout *layout, const struct bContext *C, struct PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int filter, const bool live_icon, const char *text)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
Scene scene
static ushort indices[]
#define fabsf(x)
#define sqrtf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:46
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6562
int RNA_string_length(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6539
bool RNA_pointer_is_null(const PointerRNA *ptr)
Definition: rna_access.c:174
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
int totvert
Definition: rand.cc:48
float tb
Definition: RE_texture.h:84
float * nor
Definition: RE_texture.h:86
float tin
Definition: RE_texture.h:84
float ta
Definition: RE_texture.h:84
float tr
Definition: RE_texture.h:84
float tg
Definition: RE_texture.h:84
PointerRNA * ptr
Definition: wm_files.c:3157