Blender V4.3
MOD_weightvg_util.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 by Bastien Montagne. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_utildefines.h"
10
11#include "BLI_math_color.h"
12#include "BLI_rand.h"
13#include "BLI_string.h"
14
15#include "BLT_translation.hh"
16
17#include "DNA_color_types.h" /* CurveMapping. */
18#include "DNA_mesh_types.h"
19#include "DNA_meshdata_types.h"
20#include "DNA_modifier_types.h"
21#include "DNA_object_types.h"
22#include "DNA_scene_types.h"
23
24#include "BKE_colortools.hh" /* CurveMapping. */
25#include "BKE_context.hh"
26#include "BKE_customdata.hh"
27#include "BKE_deform.hh"
28#include "BKE_modifier.hh"
29#include "BKE_scene.hh"
30#include "BKE_texture.h" /* Texture masking. */
31
32#include "UI_interface.hh"
33#include "UI_resources.hh"
34
35#include "RNA_access.hh"
36
37#include "DEG_depsgraph.hh"
39
40#include "MEM_guardedalloc.h"
41#include "MOD_ui_common.hh"
42#include "MOD_util.hh"
43#include "MOD_weightvg_util.hh"
44#include "RE_texture.h" /* Texture masking. */
45
47 int num, float *new_w, short falloff_type, const bool do_invert, CurveMapping *cmap, RNG *rng)
48{
49 int i;
50
51 /* Return immediately, if we have nothing to do! */
52 /* Also security checks... */
53 if (!do_invert && (((falloff_type == MOD_WVG_MAPPING_CURVE) && (cmap == nullptr)) ||
54 !ELEM(falloff_type,
62 {
63 return;
64 }
65
66 if (cmap && falloff_type == MOD_WVG_MAPPING_CURVE) {
68 }
69
70 /* Map each weight (vertex) to its new value, accordingly to the chosen mode. */
71 for (i = 0; i < num; i++) {
72 float fac = new_w[i];
73
74 /* Code borrowed from the warp modifier. */
75 /* Closely matches PROP_SMOOTH and similar. */
76 switch (falloff_type) {
78 fac = BKE_curvemapping_evaluateF(cmap, 0, fac);
79 break;
81 fac = fac * fac;
82 break;
84 fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
85 break;
87 fac = sqrtf(fac);
88 break;
90 fac = sqrtf(2 * fac - fac * fac);
91 break;
93 fac = BLI_rng_get_float(rng) * fac;
94 break;
96 fac = (fac >= 0.5f) ? 1.0f : 0.0f;
97 break;
99 BLI_assert(do_invert);
100 break;
101 default:
103 }
104
105 new_w[i] = do_invert ? 1.0f - fac : fac;
106 }
107}
108
110 const int num,
111 const int *indices,
112 float *org_w,
113 const float *new_w,
114 Object *ob,
115 Mesh *mesh,
116 const float fact,
117 const char defgrp_name[MAX_VGROUP_NAME],
118 Scene * /*scene*/,
119 Tex *texture,
120 const int tex_use_channel,
121 const int tex_mapping,
122 Object *tex_map_object,
123 const char *text_map_bone,
124 const char *tex_uvlayer_name,
125 const bool invert_vgroup_mask)
126{
127 int ref_didx;
128 int i;
129
130 /* If influence factor is null, nothing to do! */
131 if (fact == 0.0f) {
132 return;
133 }
134
135 /* If we want to mask vgroup weights from a texture. */
136 if (texture != nullptr) {
137 /* The texture coordinates. */
138 float(*tex_co)[3];
139 /* See mapping note below... */
141 const int verts_num = mesh->verts_num;
142
143 /* Use new generic get_texture_coords, but do not modify our DNA struct for it...
144 * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters?
145 * What e.g. if a modifier wants to use several textures?
146 * Why use only v_co, and not mesh positions (or both)?
147 */
148 t_map.texture = texture;
149 t_map.map_object = tex_map_object;
150 STRNCPY(t_map.map_bone, text_map_bone);
151 STRNCPY(t_map.uvlayer_name, tex_uvlayer_name);
152 t_map.texmapping = tex_mapping;
153
154 tex_co = static_cast<float(*)[3]>(MEM_calloc_arrayN(verts_num, sizeof(*tex_co), __func__));
155 MOD_get_texture_coords(&t_map, ctx, ob, mesh, nullptr, tex_co);
156
157 MOD_init_texture(&t_map, ctx);
158
159 /* For each weight (vertex), make the mix between org and new weights. */
160 for (i = 0; i < num; i++) {
161 int idx = indices ? indices[i] : i;
162 TexResult texres;
163 float hsv[3]; /* For HSV color space. */
164 bool do_color_manage = tex_use_channel != MOD_WVG_MASK_TEX_USE_INT;
165
166 BKE_texture_get_value(texture, tex_co[idx], &texres, do_color_manage);
167 /* Get the good channel value... */
168 switch (tex_use_channel) {
170 org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact)));
171 break;
173 org_w[i] = (new_w[i] * texres.trgba[0] * fact) +
174 (org_w[i] * (1.0f - (texres.trgba[0] * fact)));
175 break;
177 org_w[i] = (new_w[i] * texres.trgba[1] * fact) +
178 (org_w[i] * (1.0f - (texres.trgba[1] * fact)));
179 break;
181 org_w[i] = (new_w[i] * texres.trgba[2] * fact) +
182 (org_w[i] * (1.0f - (texres.trgba[2] * fact)));
183 break;
185 rgb_to_hsv_v(texres.trgba, hsv);
186 org_w[i] = (new_w[i] * hsv[0] * fact) + (org_w[i] * (1.0f - (hsv[0] * fact)));
187 break;
189 rgb_to_hsv_v(texres.trgba, hsv);
190 org_w[i] = (new_w[i] * hsv[1] * fact) + (org_w[i] * (1.0f - (hsv[1] * fact)));
191 break;
193 rgb_to_hsv_v(texres.trgba, hsv);
194 org_w[i] = (new_w[i] * hsv[2] * fact) + (org_w[i] * (1.0f - (hsv[2] * fact)));
195 break;
197 org_w[i] = (new_w[i] * texres.trgba[3] * fact) +
198 (org_w[i] * (1.0f - (texres.trgba[3] * fact)));
199 break;
200 default:
201 org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact)));
202 break;
203 }
204 }
205
206 MEM_freeN(tex_co);
207 }
208 else if ((ref_didx = BKE_id_defgroup_name_index(&mesh->id, defgrp_name)) != -1) {
209 /* Check whether we want to set vgroup weights from a constant weight factor or a vertex
210 * group.
211 */
212 /* Get vgroup idx from its name. */
213
214 /* Proceed only if vgroup is valid, else use constant factor. */
215 /* Get actual deform-verts (ie vertex group data). */
216 const MDeformVert *dvert = static_cast<const MDeformVert *>(
217 CustomData_get_layer(&mesh->vert_data, CD_MDEFORMVERT));
218 /* Proceed only if vgroup is valid, else assume factor = O. */
219 if (dvert == nullptr) {
220 return;
221 }
222
223 /* For each weight (vertex), make the mix between org and new weights. */
224 for (i = 0; i < num; i++) {
225 int idx = indices ? indices[i] : i;
226 const float f = (invert_vgroup_mask ?
227 (1.0f - BKE_defvert_find_weight(&dvert[idx], ref_didx)) :
228 BKE_defvert_find_weight(&dvert[idx], ref_didx)) *
229 fact;
230 org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0f - f));
231 /* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */
232 }
233 }
234 else {
235 /* Default "influence" behavior. */
236 /* For each weight (vertex), make the mix between org and new weights. */
237 const float ifact = 1.0f - fact;
238 for (i = 0; i < num; i++) {
239 org_w[i] = (new_w[i] * fact) + (org_w[i] * ifact);
240 }
241 }
242}
243
245 int defgrp_idx,
246 MDeformWeight **dws,
247 int num,
248 const int *indices,
249 const float *weights,
250 const bool do_add,
251 const float add_thresh,
252 const bool do_rem,
253 const float rem_thresh,
254 const bool do_normalize)
255{
256 int i;
257
258 float min_w = weights[0];
259 float norm_fac = 1.0f;
260 if (do_normalize) {
261 float max_w = weights[0];
262 for (i = 1; i < num; i++) {
263 const float w = weights[i];
264
265 /* No need to clamp here, normalization will ensure we stay within [0.0, 1.0] range. */
266 if (w < min_w) {
267 min_w = w;
268 }
269 else if (w > max_w) {
270 max_w = w;
271 }
272 }
273
274 const float range = max_w - min_w;
275 if (fabsf(range) > FLT_EPSILON) {
276 norm_fac = 1.0f / range;
277 }
278 else {
279 min_w = 0.0f;
280 }
281 }
282
283 for (i = 0; i < num; i++) {
284 float w = weights[i];
285 MDeformVert *dv = &dvert[indices ? indices[i] : i];
286 MDeformWeight *dw = dws ?
287 dws[i] :
288 ((defgrp_idx >= 0) ? BKE_defvert_find_index(dv, defgrp_idx) : nullptr);
289
290 if (do_normalize) {
291 w = (w - min_w) * norm_fac;
292 }
293 /* Never allow weights out of [0.0, 1.0] range. */
294 CLAMP(w, 0.0f, 1.0f);
295
296 /* If the vertex is in this vgroup, remove it if needed, or just update it. */
297 if (dw != nullptr) {
298 if (do_rem && w <= rem_thresh) {
300 }
301 else {
302 dw->weight = w;
303 }
304 }
305 /* Else, add it if needed! */
306 else if (do_add && w >= add_thresh) {
307 BKE_defvert_add_index_notest(dv, defgrp_idx, w);
308 }
309 }
310}
311
313{
314 PointerRNA mask_texture_ptr = RNA_pointer_get(ptr, "mask_texture");
315 bool has_mask_texture = !RNA_pointer_is_null(&mask_texture_ptr);
316 bool has_mask_vertex_group = RNA_string_length(ptr, "mask_vertex_group") != 0;
317 int mask_tex_mapping = RNA_enum_get(ptr, "mask_tex_mapping");
318
319 uiLayoutSetPropSep(layout, true);
320
321 uiItemR(layout, ptr, "mask_constant", UI_ITEM_R_SLIDER, IFACE_("Global Influence:"), ICON_NONE);
322
323 if (!has_mask_texture) {
325 layout, ptr, ob_ptr, "mask_vertex_group", "invert_mask_vertex_group", nullptr);
326 }
327
328 if (!has_mask_vertex_group) {
329 uiTemplateID(layout,
330 C,
331 ptr,
332 "mask_texture",
333 "texture.new",
334 nullptr,
335 nullptr,
337 false,
338 IFACE_("Mask Texture"));
339
340 if (has_mask_texture) {
341 uiItemR(layout, ptr, "mask_tex_use_channel", UI_ITEM_NONE, IFACE_("Channel"), ICON_NONE);
342 uiItemR(layout, ptr, "mask_tex_mapping", UI_ITEM_NONE, nullptr, ICON_NONE);
343
344 if (mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
345 uiItemR(layout, ptr, "mask_tex_map_object", UI_ITEM_NONE, IFACE_("Object"), ICON_NONE);
346 }
347 else if (mask_tex_mapping == MOD_DISP_MAP_UV && RNA_enum_get(ob_ptr, "type") == OB_MESH) {
348 PointerRNA obj_data_ptr = RNA_pointer_get(ob_ptr, "data");
350 layout, ptr, "mask_tex_uv_layer", &obj_data_ptr, "uv_layers", nullptr, ICON_NONE);
351 }
352 }
353 }
354}
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
void BKE_curvemapping_init(CurveMapping *cumap)
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
support for deformation groups and hooks.
void BKE_defvert_add_index_notest(MDeformVert *dv, int defgroup, float weight)
Definition deform.cc:846
MDeformWeight * BKE_defvert_find_index(const MDeformVert *dv, int defgroup)
Definition deform.cc:795
int BKE_id_defgroup_name_index(const ID *id, blender::StringRef name)
Definition deform.cc:543
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:770
void BKE_defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
Definition deform.cc:871
void BKE_texture_get_value(struct Tex *texture, const float *tex_co, struct TexResult *texres, bool use_color_management)
Definition texture.cc:722
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
Random number functions.
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition rand.cc:93
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define CLAMP(a, b, c)
#define ELEM(...)
#define IFACE_(msgid)
@ CD_MDEFORMVERT
@ MOD_DISP_MAP_OBJECT
@ MOD_DISP_MAP_UV
@ 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
@ 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
Object is a sort of wrapper for general info.
@ OB_MESH
#define MAX_VGROUP_NAME
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.cc:39
void MOD_get_texture_coords(MappingInfoModifierData *dmd, const ModifierEvalContext *, Object *ob, Mesh *mesh, float(*cos)[3], float(*r_texco)[3])
Definition MOD_util.cc:52
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_ui_common(const bContext *C, PointerRNA *ob_ptr, PointerRNA *ptr, uiLayout *layout)
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 *, 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 uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiItemPointerR(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
void uiTemplateID(uiLayout *layout, const bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int filter=UI_TEMPLATE_ID_FILTER_ALL, bool live_icon=false, const char *text=nullptr)
@ UI_TEMPLATE_ID_FILTER_ALL
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_SLIDER
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
local_group_size(16, 16) .push_constant(Type texture
#define fabsf(x)
#define sqrtf(x)
draw_view in_light_buf[] float
IndexRange range
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
int RNA_string_length(PointerRNA *ptr, const char *name)
bool RNA_pointer_is_null(const PointerRNA *ptr)
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition rand.cc:33
float tin
Definition RE_texture.h:87
float trgba[4]
Definition RE_texture.h:88
PointerRNA * ptr
Definition wm_files.cc:4126