Blender V5.0
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_subdiv_mesh.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 bPoseChannel *pose_bone = BKE_pose_channel_find_name(data->armob->pose, bone->name);
80 if (!pose_bone) {
81 return 0;
82 }
83
84 if (!(data->is_weight_paint) || !(pose_bone->drawflag & PCHAN_DRAW_HIDDEN)) {
85 if (!(bone->flag & BONE_NO_DEFORM)) {
86 if (data->heat && data->armob->pose && pose_bone) {
87 segments = bone->segments;
88 }
89 else {
90 segments = 1;
91 }
92
93 if (data->list != nullptr) {
94 hbone = (Bone ***)&data->list;
95
96 for (a = 0; a < segments; a++) {
97 **hbone = bone;
98 (*hbone)++;
99 }
100 }
101 return segments;
102 }
103 }
104 return 0;
105}
106
107static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void * /*ptr*/)
108{
109 /* This group creates a vertex group to ob that has the
110 * same name as bone (provided the bone is skinnable).
111 * If such a vertex group already exist the routine exits.
112 */
113 if (!(bone->flag & BONE_NO_DEFORM)) {
114 if (!BKE_object_defgroup_find_name(ob, bone->name)) {
116 return 1;
117 }
118 }
119 return 0;
120}
121
122static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
123{
124 /* Bones that are deforming
125 * are regarded to be "skinnable" and are eligible for
126 * auto-skinning.
127 *
128 * This function performs 2 functions:
129 *
130 * a) If the bone is skinnable, it creates
131 * a vertex group for ob that has
132 * the name of the skinnable bone
133 * (if one doesn't exist already).
134 * b) If the pointer data is non null,
135 * it is treated like a handle to a
136 * bDeformGroup pointer -- the
137 * bDeformGroup pointer is set to point
138 * to the deform group with the bone's
139 * name, and the pointer the handle
140 * points to is incremented to point to the
141 * next member of an array of pointers
142 * to bDeformGroups. This way we can loop using
143 * this function to construct an array of
144 * pointers to bDeformGroups, all with names
145 * of skinnable bones.
146 */
147 bDeformGroup ***hgroup, *defgroup = nullptr;
148 int a, segments;
149 struct Arg {
150 Object *armob;
151 void *list;
152 int heat;
153 bool is_weight_paint;
154 } *data = static_cast<Arg *>(datap);
155
156 if (bone->flag & BONE_NO_DEFORM) {
157 return 0;
158 }
159
160 bArmature *arm = static_cast<bArmature *>(data->armob->data);
161 const bPoseChannel *pose_bone = BKE_pose_channel_find_name(data->armob->pose, bone->name);
162 if (!pose_bone) {
163 return 0;
164 }
165
166 if (data->is_weight_paint && (pose_bone->drawflag & PCHAN_DRAW_HIDDEN)) {
167 return 0;
168 }
169
170 if (data->heat) {
171 segments = bone->segments;
172 }
173 else {
174 segments = 1;
175 }
176
177 if (!data->is_weight_paint ||
178 (ANIM_bone_in_visible_collection(arm, bone) && (pose_bone->flag & POSE_SELECTED)))
179 {
180 if (!(defgroup = BKE_object_defgroup_find_name(ob, bone->name))) {
181 defgroup = BKE_object_defgroup_add_name(ob, bone->name);
182 }
183 else if (defgroup->flag & DG_LOCK_WEIGHT) {
184 /* In case vgroup already exists and is locked, do not modify it here. See #43814. */
185 defgroup = nullptr;
186 }
187 }
188
189 if (data->list != nullptr) {
190 hgroup = (bDeformGroup ***)&data->list;
191
192 for (a = 0; a < segments; a++) {
193 **hgroup = defgroup;
194 (*hgroup)++;
195 }
196 }
197 return segments;
198}
199
201 Mesh *mesh,
203 int numbones,
204 Bone **bonelist,
205 bDeformGroup **dgrouplist,
206 bDeformGroup **dgroupflip,
207 float (*root)[3],
208 float (*tip)[3],
209 const bool *selected,
210 float scale)
211{
212 using namespace blender;
213 /* Create vertex group weights from envelopes */
214
215 bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
216 bool use_mask = false;
217
218 if ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
220 {
221 use_mask = true;
222 }
223
224 const bke::AttributeAccessor attributes = mesh->attributes();
225 const VArray select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
226
227 /* for each vertex in the mesh */
228 for (int i = 0; i < mesh->verts_num; i++) {
229
230 if (use_mask && !(select_vert && select_vert[i])) {
231 continue;
232 }
233
234 int iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, nullptr, i, use_topology) : -1;
235
236 /* for each skinnable bone */
237 for (int j = 0; j < numbones; j++) {
238 if (selected[j] == false) {
239 continue;
240 }
241
242 Bone *bone = bonelist[j];
243 bDeformGroup *dgroup = dgrouplist[j];
244
245 /* store the distance-factor from the vertex to the bone */
247 root[j],
248 tip[j],
249 bone->rad_head * scale,
250 bone->rad_tail * scale,
251 bone->dist * scale);
252
253 /* add the vert to the deform group if (weight != 0.0) */
254 if (distance != 0.0f) {
256 }
257 else {
259 }
260
261 /* do same for mirror */
262 if (dgroupflip && dgroupflip[j] && iflip != -1) {
263 if (distance != 0.0f) {
265 }
266 else {
267 blender::ed::object::vgroup_vert_remove(ob, dgroupflip[j], iflip);
268 }
269 }
270 }
271 }
272}
273
274static void add_verts_to_dgroups(ReportList *reports,
275 Depsgraph *depsgraph,
276 Scene * /*scene*/,
277 Object *ob,
278 Object *par,
279 int heat,
280 const bool mirror)
281{
282 /* This functions implements the automatic computation of vertex group
283 * weights, either through envelopes or using a heat equilibrium.
284 *
285 * This function can be called both when parenting a mesh to an armature,
286 * or in weight-paint + pose-mode. In the latter case selection is taken
287 * into account and vertex weights can be mirrored.
288 *
289 * The mesh vertex positions used are either the final deformed coords
290 * from the evaluated mesh in weight-paint mode, the final sub-surface coords
291 * when parenting, or simply the original mesh coords.
292 */
293
294 bArmature *arm = static_cast<bArmature *>(par->data);
295 Bone **bonelist, *bone;
296 bDeformGroup **dgrouplist, **dgroupflip;
297 bDeformGroup *dgroup;
298 bPoseChannel *pchan;
299 Mesh *mesh;
300 Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = nullptr;
301 float (*root)[3], (*tip)[3];
303 bool *selected;
304 int numbones, vertsfilled = 0, segments = 0;
305 const bool wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
306 struct {
307 Object *armob;
308 void *list;
309 int heat;
310 bool is_weight_paint;
311 } looper_data;
312
313 looper_data.armob = par;
314 looper_data.heat = heat;
315 looper_data.list = nullptr;
316 looper_data.is_weight_paint = wpmode;
317
318 if (!par->pose) {
319 BKE_pose_rebuild(nullptr, par, arm, false);
320 }
322 /* count the number of skinnable bones */
323 numbones = bone_looper(
324 ob, static_cast<Bone *>(arm->bonebase.first), &looper_data, bone_skinnable_cb);
325
326 if (numbones == 0) {
327 return;
328 }
329
330 if (BKE_object_defgroup_data_create(static_cast<ID *>(ob->data)) == nullptr) {
331 return;
332 }
333
334 /* create an array of pointer to bones that are skinnable
335 * and fill it with all of the skinnable bones */
336 bonelist = MEM_calloc_arrayN<Bone *>(numbones, "bonelist");
337 looper_data.list = bonelist;
338 bone_looper(ob, static_cast<Bone *>(arm->bonebase.first), &looper_data, bone_skinnable_cb);
339
340 /* create an array of pointers to the deform groups that
341 * correspond to the skinnable bones (creating them
342 * as necessary. */
343 dgrouplist = MEM_calloc_arrayN<bDeformGroup *>(numbones, "dgrouplist");
344 dgroupflip = MEM_calloc_arrayN<bDeformGroup *>(numbones, "dgroupflip");
345
346 looper_data.list = dgrouplist;
347 bone_looper(ob, static_cast<Bone *>(arm->bonebase.first), &looper_data, dgroup_skinnable_cb);
348
349 /* create an array of root and tip positions transformed into
350 * global coords */
351 root = MEM_calloc_arrayN<float[3]>(numbones, "root");
352 tip = MEM_calloc_arrayN<float[3]>(numbones, "tip");
353 selected = MEM_calloc_arrayN<bool>(numbones, "selected");
354
355 for (int j = 0; j < numbones; j++) {
356 bone = bonelist[j];
357 dgroup = dgrouplist[j];
358
359 /* handle bbone */
360 if (heat) {
361 if (segments == 0) {
362 segments = 1;
363 bbone = nullptr;
364
365 if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) {
366 if (bone->segments > 1) {
367 segments = bone->segments;
368 BKE_pchan_bbone_spline_setup(pchan, true, false, bbone_array);
369 bbone = bbone_array;
370 }
371 }
372 }
373
374 segments--;
375 }
376
377 /* compute root and tip */
378 if (bbone) {
379 mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
380 if ((segments + 1) < bone->segments) {
381 mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
382 }
383 else {
384 copy_v3_v3(tip[j], bone->arm_tail);
385 }
386 }
387 else {
388 copy_v3_v3(root[j], bone->arm_head);
389 copy_v3_v3(tip[j], bone->arm_tail);
390 }
391
392 mul_m4_v3(par->object_to_world().ptr(), root[j]);
393 mul_m4_v3(par->object_to_world().ptr(), tip[j]);
394
395 /* set selected */
396 if (wpmode) {
397 if (ANIM_bone_in_visible_collection(arm, bone) && (bone->flag & BONE_SELECTED)) {
398 selected[j] = true;
399 }
400 }
401 else {
402 selected[j] = true;
403 }
404
405 /* find flipped group */
406 if (dgroup && mirror) {
407 char name_flip[MAXBONENAME];
408
409 BLI_string_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip));
410 dgroupflip[j] = BKE_object_defgroup_find_name(ob, name_flip);
411 }
412 }
413
414 /* create verts */
415 mesh = static_cast<Mesh *>(ob->data);
416 verts.reinitialize(mesh->verts_num);
417
418 if (wpmode) {
419 /* if in weight paint mode, use final verts from evaluated mesh */
420 const Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
421 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
422 if (mesh_eval) {
424 mesh_eval, reinterpret_cast<float (*)[3]>(verts.data()), mesh->verts_num);
425 vertsfilled = 1;
426 }
427 }
429 /* Is subdivision-surface on? Lets use the verts on the limit surface then.
430 * = same amount of vertices as mesh, but vertices moved to the
431 * subdivision-surfaced position, like for 'optimal'. */
433 vertsfilled = 1;
434 }
435
436 /* transform verts to global space */
437 const blender::Span<blender::float3> positions = mesh->vert_positions();
438 for (int i = 0; i < mesh->verts_num; i++) {
439 if (!vertsfilled) {
440 copy_v3_v3(verts[i], positions[i]);
441 }
442 mul_m4_v3(ob->object_to_world().ptr(), verts[i]);
443 }
444
445 /* compute the weights based on gathered vertices and bones */
446 if (heat) {
447 const char *error = nullptr;
448
450 mesh,
451 reinterpret_cast<float (*)[3]>(verts.data()),
452 numbones,
453 dgrouplist,
454 dgroupflip,
455 root,
456 tip,
457 selected,
458 &error);
459 if (error) {
460 BKE_report(reports, RPT_WARNING, error);
461 }
462 }
463 else {
465 mesh,
466 verts,
467 numbones,
468 bonelist,
469 dgrouplist,
470 dgroupflip,
471 root,
472 tip,
473 selected,
474 mat4_to_scale(par->object_to_world().ptr()));
475 }
476
477 /* only generated in some cases but can call anyway */
479
480 /* free the memory allocated */
481 MEM_freeN(bonelist);
482 MEM_freeN(dgrouplist);
483 MEM_freeN(dgroupflip);
484 MEM_freeN(root);
485 MEM_freeN(tip);
486 MEM_freeN(selected);
487}
488
490 Depsgraph *depsgraph,
491 Scene *scene,
492 Object *ob,
493 Object *par,
494 const int mode,
495 const bool mirror)
496{
497 /* Lets try to create some vertex groups
498 * based on the bones of the parent armature.
499 */
500 bArmature *arm = static_cast<bArmature *>(par->data);
501
502 if (mode == ARM_GROUPS_NAME) {
503 const int defbase_tot = BKE_object_defgroup_count(ob);
504 int defbase_add;
505 /* Traverse the bone list, trying to create empty vertex
506 * groups corresponding to the bone.
507 */
508 defbase_add = bone_looper(
509 ob, static_cast<Bone *>(arm->bonebase.first), nullptr, vgroup_add_unique_bone_cb);
510
511 if (defbase_add) {
512 /* It's possible there are DWeights outside the range of the current
513 * object's deform groups. In this case the new groups won't be empty #33889. */
514 blender::ed::object::vgroup_data_clamp_range(static_cast<ID *>(ob->data), defbase_tot);
515 }
516 }
517 else if (ELEM(mode, ARM_GROUPS_ENVELOPE, ARM_GROUPS_AUTO)) {
518 /* Traverse the bone list, trying to create vertex groups
519 * that are populated with the vertices for which the
520 * bone is closest.
521 */
522 add_verts_to_dgroups(reports, depsgraph, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
523 }
524}
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.
void BKE_pose_channels_hash_ensure(bPose *pose) ATTR_NONNULL(1)
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)
void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, bool do_id_user)
float distfactor_to_bone(const blender::float3 &position, const blender::float3 &head, const blender::float3 &tail, float radius_head, float radius_tail, float falloff_distance)
#define MAX_BBONE_SUBDIV
support for deformation groups and hooks.
int BKE_object_defgroup_count(const Object *ob)
Definition deform.cc:602
bDeformGroup * BKE_object_defgroup_find_name(const Object *ob, blender::StringRef name)
Definition deform.cc:526
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)
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
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)
@ PCHAN_DRAW_HIDDEN
@ POSE_SELECTED
#define MAXBONENAME
@ BONE_SELECTED
@ 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:302
void ED_mesh_mirror_spatial_table_end(Object *ob)
#define WEIGHT_REPLACE
Read Guarded memory(de)allocation.
int bone_looper(Object *ob, Bone *bone, void *data, int(*bone_func)(Object *, Bone *, void *))
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)
static void envelope_bone_weighting(Object *ob, Mesh *mesh, const blender::Span< blender::float3 > verts, int numbones, Bone **bonelist, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float(*root)[3], float(*tip)[3], const bool *selected, float scale)
BMesh const char void * data
BPy_StructRNA * depsgraph
AttributeSet attributes
GAttributeReader lookup(const StringRef attribute_id) const
nullptr float
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_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 calculate_limit_positions(Mesh *mesh, MutableSpan< float3 > limit_positions)
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:414
void * first
float mat[4][4]
char editflag
int verts_num
struct bPose * pose
i
Definition text_draw.cc:230