Blender V5.0
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
8
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_deform.hh"
27#include "BKE_modifier.hh"
28#include "BKE_texture.h" /* Texture masking. */
29
30#include "UI_interface.hh"
32#include "UI_resources.hh"
33
34#include "RNA_access.hh"
35
37
38#include "MEM_guardedalloc.h"
39#include "MOD_ui_common.hh"
40#include "MOD_util.hh"
41#include "MOD_weightvg_util.hh"
42#include "RE_texture.h" /* Texture masking. */
43
45 int num, float *new_w, short falloff_type, const bool do_invert, CurveMapping *cmap, RNG *rng)
46{
47 int i;
48
49 /* Return immediately, if we have nothing to do! */
50 /* Also security checks... */
51 if (!do_invert && (((falloff_type == MOD_WVG_MAPPING_CURVE) && (cmap == nullptr)) ||
52 !ELEM(falloff_type,
60 {
61 return;
62 }
63
64 if (cmap && falloff_type == MOD_WVG_MAPPING_CURVE) {
66 }
67
68 /* Map each weight (vertex) to its new value, accordingly to the chosen mode. */
69 for (i = 0; i < num; i++) {
70 float fac = new_w[i];
71
72 /* Code borrowed from the warp modifier. */
73 /* Closely matches PROP_SMOOTH and similar. */
74 switch (falloff_type) {
76 fac = BKE_curvemapping_evaluateF(cmap, 0, fac);
77 break;
79 fac = fac * fac;
80 break;
82 fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
83 break;
85 fac = sqrtf(fac);
86 break;
88 fac = sqrtf(2 * fac - fac * fac);
89 break;
91 fac = BLI_rng_get_float(rng) * fac;
92 break;
94 fac = (fac >= 0.5f) ? 1.0f : 0.0f;
95 break;
97 BLI_assert(do_invert);
98 break;
99 default:
101 }
102
103 new_w[i] = do_invert ? 1.0f - fac : fac;
104 }
105}
106
108 const int num,
109 const int *indices,
110 float *org_w,
111 const float *new_w,
112 Object *ob,
113 Mesh *mesh,
114 const float fact,
115 const char defgrp_name[MAX_VGROUP_NAME],
116 Scene * /*scene*/,
117 Tex *texture,
118 const int tex_use_channel,
119 const int tex_mapping,
120 Object *tex_map_object,
121 const char *text_map_bone,
122 const char *tex_uvlayer_name,
123 const bool invert_vgroup_mask)
124{
125 int ref_didx;
126 int i;
127
128 /* If influence factor is null, nothing to do! */
129 if (fact == 0.0f) {
130 return;
131 }
132
133 /* If we want to mask vgroup weights from a texture. */
134 if (texture != nullptr) {
135 /* The texture coordinates. */
136 float (*tex_co)[3];
137 /* See mapping note below... */
139 const int verts_num = mesh->verts_num;
140
141 /* Use new generic get_texture_coords, but do not modify our DNA struct for it...
142 * XXX Why use a ModifierData stuff here ? Why not a simple, generic struct for parameters?
143 * What e.g. if a modifier wants to use several textures?
144 * Why use only v_co, and not mesh positions (or both)?
145 */
146 t_map.texture = texture;
147 t_map.map_object = tex_map_object;
148 STRNCPY(t_map.map_bone, text_map_bone);
149 STRNCPY(t_map.uvlayer_name, tex_uvlayer_name);
150 t_map.texmapping = tex_mapping;
151
152 tex_co = MEM_calloc_arrayN<float[3]>(verts_num, __func__);
153 MOD_get_texture_coords(&t_map, ctx, ob, mesh, nullptr, tex_co);
154
155 MOD_init_texture(&t_map, ctx);
156
157 /* For each weight (vertex), make the mix between org and new weights. */
158 for (i = 0; i < num; i++) {
159 int idx = indices ? indices[i] : i;
160 TexResult texres;
161 float hsv[3]; /* For HSV color space. */
162 bool do_color_manage = tex_use_channel != MOD_WVG_MASK_TEX_USE_INT;
163
164 BKE_texture_get_value(texture, tex_co[idx], &texres, do_color_manage);
165 /* Get the good channel value... */
166 switch (tex_use_channel) {
168 org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact)));
169 break;
171 org_w[i] = (new_w[i] * texres.trgba[0] * fact) +
172 (org_w[i] * (1.0f - (texres.trgba[0] * fact)));
173 break;
175 org_w[i] = (new_w[i] * texres.trgba[1] * fact) +
176 (org_w[i] * (1.0f - (texres.trgba[1] * fact)));
177 break;
179 org_w[i] = (new_w[i] * texres.trgba[2] * fact) +
180 (org_w[i] * (1.0f - (texres.trgba[2] * fact)));
181 break;
183 rgb_to_hsv_v(texres.trgba, hsv);
184 org_w[i] = (new_w[i] * hsv[0] * fact) + (org_w[i] * (1.0f - (hsv[0] * fact)));
185 break;
187 rgb_to_hsv_v(texres.trgba, hsv);
188 org_w[i] = (new_w[i] * hsv[1] * fact) + (org_w[i] * (1.0f - (hsv[1] * fact)));
189 break;
191 rgb_to_hsv_v(texres.trgba, hsv);
192 org_w[i] = (new_w[i] * hsv[2] * fact) + (org_w[i] * (1.0f - (hsv[2] * fact)));
193 break;
195 org_w[i] = (new_w[i] * texres.trgba[3] * fact) +
196 (org_w[i] * (1.0f - (texres.trgba[3] * fact)));
197 break;
198 default:
199 org_w[i] = (new_w[i] * texres.tin * fact) + (org_w[i] * (1.0f - (texres.tin * fact)));
200 break;
201 }
202 }
203
204 MEM_freeN(tex_co);
205 }
206 else if ((ref_didx = BKE_id_defgroup_name_index(&mesh->id, defgrp_name)) != -1) {
207 /* Check whether we want to set vgroup weights from a constant weight factor or a vertex
208 * group.
209 */
210 /* Get vgroup idx from its name. */
211
212 /* Proceed only if vgroup is valid, else use constant factor. */
213 /* Get actual deform-verts (ie vertex group data). */
214 const MDeformVert *dvert = mesh->deform_verts().data();
215 /* Proceed only if vgroup is valid, else assume factor = O. */
216 if (dvert == nullptr) {
217 return;
218 }
219
220 /* For each weight (vertex), make the mix between org and new weights. */
221 for (i = 0; i < num; i++) {
222 int idx = indices ? indices[i] : i;
223 const float f = (invert_vgroup_mask ?
224 (1.0f - BKE_defvert_find_weight(&dvert[idx], ref_didx)) :
225 BKE_defvert_find_weight(&dvert[idx], ref_didx)) *
226 fact;
227 org_w[i] = (new_w[i] * f) + (org_w[i] * (1.0f - f));
228 /* If that vertex is not in ref vgroup, assume null factor, and hence do nothing! */
229 }
230 }
231 else {
232 /* Default "influence" behavior. */
233 /* For each weight (vertex), make the mix between org and new weights. */
234 const float ifact = 1.0f - fact;
235 for (i = 0; i < num; i++) {
236 org_w[i] = (new_w[i] * fact) + (org_w[i] * ifact);
237 }
238 }
239}
240
242 int defgrp_idx,
243 MDeformWeight **dws,
244 int num,
245 const int *indices,
246 const float *weights,
247 const bool do_add,
248 const float add_thresh,
249 const bool do_rem,
250 const float rem_thresh,
251 const bool do_normalize)
252{
253 int i;
254
255 float min_w = weights[0];
256 float norm_fac = 1.0f;
257 if (do_normalize) {
258 float max_w = weights[0];
259 for (i = 1; i < num; i++) {
260 const float w = weights[i];
261
262 /* No need to clamp here, normalization will ensure we stay within [0.0, 1.0] range. */
263 if (w < min_w) {
264 min_w = w;
265 }
266 else if (w > max_w) {
267 max_w = w;
268 }
269 }
270
271 const float range = max_w - min_w;
272 if (fabsf(range) > FLT_EPSILON) {
273 norm_fac = 1.0f / range;
274 }
275 else {
276 min_w = 0.0f;
277 }
278 }
279
280 for (i = 0; i < num; i++) {
281 float w = weights[i];
282 MDeformVert *dv = &dvert[indices ? indices[i] : i];
283 MDeformWeight *dw = dws ?
284 dws[i] :
285 ((defgrp_idx >= 0) ? BKE_defvert_find_index(dv, defgrp_idx) : nullptr);
286
287 if (do_normalize) {
288 w = (w - min_w) * norm_fac;
289 }
290 /* Never allow weights out of [0.0, 1.0] range. */
291 CLAMP(w, 0.0f, 1.0f);
292
293 /* If the vertex is in this vgroup, remove it if needed, or just update it. */
294 if (dw != nullptr) {
295 if (do_rem && w <= rem_thresh) {
297 }
298 else {
299 dw->weight = w;
300 }
301 }
302 /* Else, add it if needed! */
303 else if (do_add && w >= add_thresh) {
304 BKE_defvert_add_index_notest(dv, defgrp_idx, w);
305 }
306 }
307}
308
310{
311 PointerRNA mask_texture_ptr = RNA_pointer_get(ptr, "mask_texture");
312 bool has_mask_texture = !RNA_pointer_is_null(&mask_texture_ptr);
313 bool has_mask_vertex_group = RNA_string_length(ptr, "mask_vertex_group") != 0;
314 int mask_tex_mapping = RNA_enum_get(ptr, "mask_tex_mapping");
315
316 layout->use_property_split_set(true);
317
318 layout->prop(ptr, "mask_constant", UI_ITEM_R_SLIDER, IFACE_("Global Influence:"), ICON_NONE);
319
320 if (!has_mask_texture) {
322 layout, ptr, ob_ptr, "mask_vertex_group", "invert_mask_vertex_group", std::nullopt);
323 }
324
325 if (!has_mask_vertex_group) {
326 uiTemplateID(layout,
327 C,
328 ptr,
329 "mask_texture",
330 "texture.new",
331 nullptr,
332 nullptr,
334 false,
335 IFACE_("Mask Texture"));
336
337 if (has_mask_texture) {
338 layout->prop(ptr, "mask_tex_use_channel", UI_ITEM_NONE, IFACE_("Channel"), ICON_NONE);
339 layout->prop(ptr, "mask_tex_mapping", UI_ITEM_NONE, std::nullopt, ICON_NONE);
340
341 if (mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
342 layout->prop(ptr, "mask_tex_map_object", UI_ITEM_NONE, IFACE_("Object"), ICON_NONE);
343 }
344 else if (mask_tex_mapping == MOD_DISP_MAP_UV && RNA_enum_get(ob_ptr, "type") == OB_MESH) {
345 PointerRNA obj_data_ptr = RNA_pointer_get(ob_ptr, "data");
346 layout->prop_search(
347 ptr, "mask_tex_uv_layer", &obj_data_ptr, "uv_layers", std::nullopt, ICON_NONE);
348 }
349 }
350 }
351}
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
void BKE_curvemapping_init(CurveMapping *cumap)
support for deformation groups and hooks.
void BKE_defvert_add_index_notest(MDeformVert *dv, int defgroup, float weight)
Definition deform.cc:856
MDeformWeight * BKE_defvert_find_index(const MDeformVert *dv, int defgroup)
Definition deform.cc:806
int BKE_id_defgroup_name_index(const ID *id, blender::StringRef name)
Definition deform.cc:549
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:774
void BKE_defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
Definition deform.cc:880
void BKE_texture_get_value(struct Tex *texture, const float *tex_co, struct TexResult *texres, bool use_color_management)
Definition texture.cc:638
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
ATTR_WARN_UNUSED_RESULT const size_t num
Random number functions.
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition rand.cc:88
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define CLAMP(a, b, c)
#define ELEM(...)
#define IFACE_(msgid)
@ 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_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
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 StringRefNull vgroup_prop, const std::optional< StringRefNull > invert_vgroup_prop, const std::optional< StringRefNull > text)
void MOD_init_texture(MappingInfoModifierData *dmd, const ModifierEvalContext *ctx)
Definition MOD_util.cc:36
void MOD_get_texture_coords(MappingInfoModifierData *dmd, const ModifierEvalContext *, Object *ob, Mesh *mesh, float(*cos)[3], float(*r_texco)[3])
Definition MOD_util.cc:49
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)
#define C
Definition RandGen.cpp:29
@ UI_TEMPLATE_ID_FILTER_ALL
void uiTemplateID(uiLayout *layout, const bContext *C, PointerRNA *ptr, blender::StringRefNull propname, const char *newop, const char *openop, const char *unlinkop, int filter=UI_TEMPLATE_ID_FILTER_ALL, bool live_icon=false, std::optional< blender::StringRef > text=std::nullopt)
@ UI_ITEM_R_SLIDER
#define UI_ITEM_NONE
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
nullptr float
static ushort indices[]
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define fabsf
#define sqrtf
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)
int verts_num
Definition rand.cc:33
float tin
Definition RE_texture.h:59
float trgba[4]
Definition RE_texture.h:60
void prop_search(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop, PropertyRNA *item_searchpropname, std::optional< blender::StringRefNull > name, int icon, bool results_are_suggestions)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238