Blender V4.5
armature_skinning.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "DNA_armature_types.h"
12#include "DNA_mesh_types.h"
13#include "DNA_object_types.h"
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_math_matrix.h"
18#include "BLI_math_vector.h"
19#include "BLI_string_utils.hh"
20
21#include "BKE_action.hh"
22#include "BKE_armature.hh"
23#include "BKE_attribute.hh"
24#include "BKE_deform.hh"
25#include "BKE_mesh_iterators.hh"
26#include "BKE_modifier.hh"
27#include "BKE_object.hh"
28#include "BKE_object_deform.h"
29#include "BKE_report.hh"
30#include "BKE_subsurf.hh"
31
32#include "DEG_depsgraph.hh"
34
35#include "ED_armature.hh"
36#include "ED_mesh.hh"
37#include "ED_object_vgroup.hh"
38
40
41#include "armature_intern.hh"
42#include "meshlaplacian.h"
43
44/* ******************************* Bone Skinning *********************************************** */
45
46static int bone_skinnable_cb(Object * /*ob*/, Bone *bone, void *datap)
47{
48 /* Bones that are deforming
49 * are regarded to be "skinnable" and are eligible for
50 * auto-skinning.
51 *
52 * This function performs 2 functions:
53 *
54 * a) It returns 1 if the bone is skinnable.
55 * If we loop over all bones with this
56 * function, we can count the number of
57 * skinnable bones.
58 * b) If the pointer data is non null,
59 * it is treated like a handle to a
60 * bone pointer -- the bone pointer
61 * is set to point at this bone, and
62 * the pointer the handle points to
63 * is incremented to point to the
64 * next member of an array of pointers
65 * to bones. This way we can loop using
66 * this function to construct an array of
67 * pointers to bones that point to all
68 * skinnable bones.
69 */
70 Bone ***hbone;
71 int a, segments;
72 struct Arg {
73 Object *armob;
74 void *list;
75 int heat;
76 bool is_weight_paint;
77 } *data = static_cast<Arg *>(datap);
78
79 if (!(data->is_weight_paint) || !(bone->flag & BONE_HIDDEN_P)) {
80 if (!(bone->flag & BONE_NO_DEFORM)) {
81 if (data->heat && data->armob->pose &&
82 BKE_pose_channel_find_name(data->armob->pose, bone->name))
83 {
84 segments = bone->segments;
85 }
86 else {
87 segments = 1;
88 }
89
90 if (data->list != nullptr) {
91 hbone = (Bone ***)&data->list;
92
93 for (a = 0; a < segments; a++) {
94 **hbone = bone;
95 (*hbone)++;
96 }
97 }
98 return segments;
99 }
100 }
101 return 0;
102}
103
104static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void * /*ptr*/)
105{
106 /* This group creates a vertex group to ob that has the
107 * same name as bone (provided the bone is skinnable).
108 * If such a vertex group already exist the routine exits.
109 */
110 if (!(bone->flag & BONE_NO_DEFORM)) {
111 if (!BKE_object_defgroup_find_name(ob, bone->name)) {
113 return 1;
114 }
115 }
116 return 0;
117}
118
119static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
120{
121 /* Bones that are deforming
122 * are regarded to be "skinnable" and are eligible for
123 * auto-skinning.
124 *
125 * This function performs 2 functions:
126 *
127 * a) If the bone is skinnable, it creates
128 * a vertex group for ob that has
129 * the name of the skinnable bone
130 * (if one doesn't exist already).
131 * b) If the pointer data is non null,
132 * it is treated like a handle to a
133 * bDeformGroup pointer -- the
134 * bDeformGroup pointer is set to point
135 * to the deform group with the bone's
136 * name, and the pointer the handle
137 * points to is incremented to point to the
138 * next member of an array of pointers
139 * to bDeformGroups. This way we can loop using
140 * this function to construct an array of
141 * pointers to bDeformGroups, all with names
142 * of skinnable bones.
143 */
144 bDeformGroup ***hgroup, *defgroup = nullptr;
145 int a, segments;
146 struct Arg {
147 Object *armob;
148 void *list;
149 int heat;
150 bool is_weight_paint;
151 } *data = static_cast<Arg *>(datap);
152 bArmature *arm = static_cast<bArmature *>(data->armob->data);
153
154 if (!data->is_weight_paint || !(bone->flag & BONE_HIDDEN_P)) {
155 if (!(bone->flag & BONE_NO_DEFORM)) {
156 if (data->heat && data->armob->pose &&
157 BKE_pose_channel_find_name(data->armob->pose, bone->name))
158 {
159 segments = bone->segments;
160 }
161 else {
162 segments = 1;
163 }
164
165 if (!data->is_weight_paint ||
166 (ANIM_bone_in_visible_collection(arm, bone) && (bone->flag & BONE_SELECTED)))
167 {
168 if (!(defgroup = BKE_object_defgroup_find_name(ob, bone->name))) {
169 defgroup = BKE_object_defgroup_add_name(ob, bone->name);
170 }
171 else if (defgroup->flag & DG_LOCK_WEIGHT) {
172 /* In case vgroup already exists and is locked, do not modify it here. See #43814. */
173 defgroup = nullptr;
174 }
175 }
176
177 if (data->list != nullptr) {
178 hgroup = (bDeformGroup ***)&data->list;
179
180 for (a = 0; a < segments; a++) {
181 **hgroup = defgroup;
182 (*hgroup)++;
183 }
184 }
185 return segments;
186 }
187 }
188 return 0;
189}
190
192 Mesh *mesh,
193 float (*verts)[3],
194 int numbones,
195 Bone **bonelist,
196 bDeformGroup **dgrouplist,
197 bDeformGroup **dgroupflip,
198 float (*root)[3],
199 float (*tip)[3],
200 const bool *selected,
201 float scale)
202{
203 using namespace blender;
204 /* Create vertex group weights from envelopes */
205
206 bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
207 bool use_mask = false;
208
209 if ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
211 {
212 use_mask = true;
213 }
214
215 const bke::AttributeAccessor attributes = mesh->attributes();
216 const VArray select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
217
218 /* for each vertex in the mesh */
219 for (int i = 0; i < mesh->verts_num; i++) {
220
221 if (use_mask && !(select_vert && select_vert[i])) {
222 continue;
223 }
224
225 int iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, nullptr, i, use_topology) : -1;
226
227 /* for each skinnable bone */
228 for (int j = 0; j < numbones; j++) {
229 if (selected[j] == false) {
230 continue;
231 }
232
233 Bone *bone = bonelist[j];
234 bDeformGroup *dgroup = dgrouplist[j];
235
236 /* store the distance-factor from the vertex to the bone */
238 root[j],
239 tip[j],
240 bone->rad_head * scale,
241 bone->rad_tail * scale,
242 bone->dist * scale);
243
244 /* add the vert to the deform group if (weight != 0.0) */
245 if (distance != 0.0f) {
247 }
248 else {
250 }
251
252 /* do same for mirror */
253 if (dgroupflip && dgroupflip[j] && iflip != -1) {
254 if (distance != 0.0f) {
256 }
257 else {
258 blender::ed::object::vgroup_vert_remove(ob, dgroupflip[j], iflip);
259 }
260 }
261 }
262 }
263}
264
266 Depsgraph *depsgraph,
267 Scene * /*scene*/,
268 Object *ob,
269 Object *par,
270 int heat,
271 const bool mirror)
272{
273 /* This functions implements the automatic computation of vertex group
274 * weights, either through envelopes or using a heat equilibrium.
275 *
276 * This function can be called both when parenting a mesh to an armature,
277 * or in weight-paint + pose-mode. In the latter case selection is taken
278 * into account and vertex weights can be mirrored.
279 *
280 * The mesh vertex positions used are either the final deformed coords
281 * from the evaluated mesh in weight-paint mode, the final sub-surface coords
282 * when parenting, or simply the original mesh coords.
283 */
284
285 bArmature *arm = static_cast<bArmature *>(par->data);
286 Bone **bonelist, *bone;
287 bDeformGroup **dgrouplist, **dgroupflip;
288 bDeformGroup *dgroup;
289 bPoseChannel *pchan;
290 Mesh *mesh;
291 Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = nullptr;
292 float(*root)[3], (*tip)[3], (*verts)[3];
293 bool *selected;
294 int numbones, vertsfilled = 0, segments = 0;
295 const bool wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
296 struct {
297 Object *armob;
298 void *list;
299 int heat;
300 bool is_weight_paint;
301 } looper_data;
302
303 looper_data.armob = par;
304 looper_data.heat = heat;
305 looper_data.list = nullptr;
306 looper_data.is_weight_paint = wpmode;
307
308 /* count the number of skinnable bones */
309 numbones = bone_looper(
310 ob, static_cast<Bone *>(arm->bonebase.first), &looper_data, bone_skinnable_cb);
311
312 if (numbones == 0) {
313 return;
314 }
315
316 if (BKE_object_defgroup_data_create(static_cast<ID *>(ob->data)) == nullptr) {
317 return;
318 }
319
320 /* create an array of pointer to bones that are skinnable
321 * and fill it with all of the skinnable bones */
322 bonelist = MEM_calloc_arrayN<Bone *>(numbones, "bonelist");
323 looper_data.list = bonelist;
324 bone_looper(ob, static_cast<Bone *>(arm->bonebase.first), &looper_data, bone_skinnable_cb);
325
326 /* create an array of pointers to the deform groups that
327 * correspond to the skinnable bones (creating them
328 * as necessary. */
329 dgrouplist = MEM_calloc_arrayN<bDeformGroup *>(numbones, "dgrouplist");
330 dgroupflip = MEM_calloc_arrayN<bDeformGroup *>(numbones, "dgroupflip");
331
332 looper_data.list = dgrouplist;
333 bone_looper(ob, static_cast<Bone *>(arm->bonebase.first), &looper_data, dgroup_skinnable_cb);
334
335 /* create an array of root and tip positions transformed into
336 * global coords */
337 root = MEM_calloc_arrayN<float[3]>(numbones, "root");
338 tip = MEM_calloc_arrayN<float[3]>(numbones, "tip");
339 selected = MEM_calloc_arrayN<bool>(numbones, "selected");
340
341 for (int j = 0; j < numbones; j++) {
342 bone = bonelist[j];
343 dgroup = dgrouplist[j];
344
345 /* handle bbone */
346 if (heat) {
347 if (segments == 0) {
348 segments = 1;
349 bbone = nullptr;
350
351 if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) {
352 if (bone->segments > 1) {
353 segments = bone->segments;
354 BKE_pchan_bbone_spline_setup(pchan, true, false, bbone_array);
355 bbone = bbone_array;
356 }
357 }
358 }
359
360 segments--;
361 }
362
363 /* compute root and tip */
364 if (bbone) {
365 mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
366 if ((segments + 1) < bone->segments) {
367 mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
368 }
369 else {
370 copy_v3_v3(tip[j], bone->arm_tail);
371 }
372 }
373 else {
374 copy_v3_v3(root[j], bone->arm_head);
375 copy_v3_v3(tip[j], bone->arm_tail);
376 }
377
378 mul_m4_v3(par->object_to_world().ptr(), root[j]);
379 mul_m4_v3(par->object_to_world().ptr(), tip[j]);
380
381 /* set selected */
382 if (wpmode) {
383 if (ANIM_bone_in_visible_collection(arm, bone) && (bone->flag & BONE_SELECTED)) {
384 selected[j] = true;
385 }
386 }
387 else {
388 selected[j] = true;
389 }
390
391 /* find flipped group */
392 if (dgroup && mirror) {
393 char name_flip[MAXBONENAME];
394
395 BLI_string_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip));
396 dgroupflip[j] = BKE_object_defgroup_find_name(ob, name_flip);
397 }
398 }
399
400 /* create verts */
401 mesh = static_cast<Mesh *>(ob->data);
402 verts = static_cast<float(*)[3]>(
403 MEM_callocN(mesh->verts_num * sizeof(*verts), "closestboneverts"));
404
405 if (wpmode) {
406 /* if in weight paint mode, use final verts from evaluated mesh */
407 const Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
408 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
409 if (mesh_eval) {
411 vertsfilled = 1;
412 }
413 }
415 /* Is subdivision-surface on? Lets use the verts on the limit surface then.
416 * = same amount of vertices as mesh, but vertices moved to the
417 * subdivision-surfaced position, like for 'optimal'. */
419 vertsfilled = 1;
420 }
421
422 /* transform verts to global space */
423 const blender::Span<blender::float3> positions = mesh->vert_positions();
424 for (int i = 0; i < mesh->verts_num; i++) {
425 if (!vertsfilled) {
426 copy_v3_v3(verts[i], positions[i]);
427 }
428 mul_m4_v3(ob->object_to_world().ptr(), verts[i]);
429 }
430
431 /* compute the weights based on gathered vertices and bones */
432 if (heat) {
433 const char *error = nullptr;
434
436 ob, mesh, verts, numbones, dgrouplist, dgroupflip, root, tip, selected, &error);
437 if (error) {
439 }
440 }
441 else {
443 mesh,
444 verts,
445 numbones,
446 bonelist,
447 dgrouplist,
448 dgroupflip,
449 root,
450 tip,
451 selected,
452 mat4_to_scale(par->object_to_world().ptr()));
453 }
454
455 /* only generated in some cases but can call anyway */
457
458 /* free the memory allocated */
459 MEM_freeN(bonelist);
460 MEM_freeN(dgrouplist);
461 MEM_freeN(dgroupflip);
462 MEM_freeN(root);
463 MEM_freeN(tip);
464 MEM_freeN(selected);
466}
467
469 Depsgraph *depsgraph,
470 Scene *scene,
471 Object *ob,
472 Object *par,
473 const int mode,
474 const bool mirror)
475{
476 /* Lets try to create some vertex groups
477 * based on the bones of the parent armature.
478 */
479 bArmature *arm = static_cast<bArmature *>(par->data);
480
481 if (mode == ARM_GROUPS_NAME) {
482 const int defbase_tot = BKE_object_defgroup_count(ob);
483 int defbase_add;
484 /* Traverse the bone list, trying to create empty vertex
485 * groups corresponding to the bone.
486 */
487 defbase_add = bone_looper(
488 ob, static_cast<Bone *>(arm->bonebase.first), nullptr, vgroup_add_unique_bone_cb);
489
490 if (defbase_add) {
491 /* It's possible there are DWeights outside the range of the current
492 * object's deform groups. In this case the new groups won't be empty #33889. */
493 blender::ed::object::vgroup_data_clamp_range(static_cast<ID *>(ob->data), defbase_tot);
494 }
495 }
496 else if (ELEM(mode, ARM_GROUPS_ENVELOPE, ARM_GROUPS_AUTO)) {
497 /* Traverse the bone list, trying to create vertex groups
498 * that are populated with the vertices for which the
499 * bone is closest.
500 */
501 add_verts_to_dgroups(reports, depsgraph, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
502 }
503}
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
bool ANIM_bone_in_visible_collection(const bArmature *armature, const Bone *bone)
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
void BKE_pchan_bbone_spline_setup(bPoseChannel *pchan, bool rest, bool for_deform, Mat4 *result_array)
Definition armature.cc:1365
#define MAX_BBONE_SUBDIV
float distfactor_to_bone(const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist)
support for deformation groups and hooks.
int BKE_object_defgroup_count(const Object *ob)
Definition deform.cc:591
bDeformGroup * BKE_object_defgroup_find_name(const Object *ob, blender::StringRef name)
Definition deform.cc:515
void BKE_mesh_foreach_mapped_vert_coords_get(const Mesh *mesh_eval, float(*r_cos)[3], int totcos)
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
Functions for dealing with objects and deform verts, used by painting and tools.
struct bDeformGroup * BKE_object_defgroup_add_name(struct Object *ob, const char *name)
struct MDeformVert * BKE_object_defgroup_data_create(struct ID *id)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
void subsurf_calculate_limit_positions(Mesh *mesh, float(*r_positions)[3])
float mat4_to_scale(const float mat[4][4])
void mul_m4_v3(const float M[4][4], float r[3])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
size_t BLI_string_flip_side_name(char *name_dst, const char *name_src, bool strip_number, size_t name_dst_maxncpy) ATTR_NONNULL(1
#define ELEM(...)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
#define MAXBONENAME
@ BONE_SELECTED
@ BONE_HIDDEN_P
@ BONE_NO_DEFORM
@ ME_EDIT_PAINT_VERT_SEL
@ ME_EDIT_PAINT_FACE_SEL
@ ME_EDIT_MIRROR_TOPO
@ eModifierType_Subsurf
@ OB_MODE_WEIGHT_PAINT
Object is a sort of wrapper for general info.
@ DG_LOCK_WEIGHT
#define ARM_GROUPS_ENVELOPE
#define ARM_GROUPS_NAME
#define ARM_GROUPS_AUTO
int mesh_get_x_mirror_vert(Object *ob, Mesh *mesh_eval, int index, bool use_topology)
Definition meshtools.cc:911
void ED_mesh_mirror_spatial_table_end(Object *ob)
#define WEIGHT_REPLACE
Read Guarded memory(de)allocation.
ReportList * reports
Definition WM_types.hh:1025
int bone_looper(Object *ob, Bone *bone, void *data, int(*bone_func)(Object *, Bone *, void *))
static void envelope_bone_weighting(Object *ob, Mesh *mesh, float(*verts)[3], int numbones, Bone **bonelist, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float(*root)[3], float(*tip)[3], const bool *selected, float scale)
static int bone_skinnable_cb(Object *, Bone *bone, void *datap)
void ED_object_vgroup_calc_from_armature(ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par, const int mode, const bool mirror)
static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *)
static void add_verts_to_dgroups(ReportList *reports, Depsgraph *depsgraph, Scene *, Object *ob, Object *par, int heat, const bool mirror)
BMesh const char void * data
BPy_StructRNA * depsgraph
AttributeSet attributes
GAttributeReader lookup(const StringRef attribute_id) const
static float verts[][3]
float distance(VecOp< float, D >, VecOp< float, D >) RET
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void heat_bone_weighting(Object *ob, Mesh *mesh, float(*verts)[3], int numbones, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float(*root)[3], float(*tip)[3], const bool *selected, const char **r_error_str)
static void error(const char *str)
void vgroup_data_clamp_range(ID *id, int total)
void vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
void vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum)
float arm_head[3]
char name[64]
float arm_tail[3]
float arm_mat[4][4]
Definition DNA_ID.h:404
void * first
float mat[4][4]
char editflag
int verts_num
struct bPose * pose
i
Definition text_draw.cc:230