Blender V4.3
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
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) &&
210 (mesh->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)))
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 */
237 float distance = distfactor_to_bone(verts[i],
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) {
255 blender::ed::object::vgroup_vert_add(ob, dgroupflip[j], iflip, distance, WEIGHT_REPLACE);
256 }
257 else {
258 blender::ed::object::vgroup_vert_remove(ob, dgroupflip[j], iflip);
259 }
260 }
261 }
262 }
263}
264
265static void add_verts_to_dgroups(ReportList *reports,
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 = static_cast<Bone **>(MEM_callocN(numbones * sizeof(Bone *), "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 = static_cast<bDeformGroup **>(
330 MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist"));
331 dgroupflip = static_cast<bDeformGroup **>(
332 MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip"));
333
334 looper_data.list = dgrouplist;
335 bone_looper(ob, static_cast<Bone *>(arm->bonebase.first), &looper_data, dgroup_skinnable_cb);
336
337 /* create an array of root and tip positions transformed into
338 * global coords */
339 root = static_cast<float(*)[3]>(MEM_callocN(sizeof(float[3]) * numbones, "root"));
340 tip = static_cast<float(*)[3]>(MEM_callocN(sizeof(float[3]) * numbones, "tip"));
341 selected = static_cast<bool *>(MEM_callocN(sizeof(bool) * numbones, "selected"));
342
343 for (int j = 0; j < numbones; j++) {
344 bone = bonelist[j];
345 dgroup = dgrouplist[j];
346
347 /* handle bbone */
348 if (heat) {
349 if (segments == 0) {
350 segments = 1;
351 bbone = nullptr;
352
353 if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) {
354 if (bone->segments > 1) {
355 segments = bone->segments;
356 BKE_pchan_bbone_spline_setup(pchan, true, false, bbone_array);
357 bbone = bbone_array;
358 }
359 }
360 }
361
362 segments--;
363 }
364
365 /* compute root and tip */
366 if (bbone) {
367 mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
368 if ((segments + 1) < bone->segments) {
369 mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
370 }
371 else {
372 copy_v3_v3(tip[j], bone->arm_tail);
373 }
374 }
375 else {
376 copy_v3_v3(root[j], bone->arm_head);
377 copy_v3_v3(tip[j], bone->arm_tail);
378 }
379
380 mul_m4_v3(par->object_to_world().ptr(), root[j]);
381 mul_m4_v3(par->object_to_world().ptr(), tip[j]);
382
383 /* set selected */
384 if (wpmode) {
385 if (ANIM_bone_in_visible_collection(arm, bone) && (bone->flag & BONE_SELECTED)) {
386 selected[j] = true;
387 }
388 }
389 else {
390 selected[j] = true;
391 }
392
393 /* find flipped group */
394 if (dgroup && mirror) {
395 char name_flip[MAXBONENAME];
396
397 BLI_string_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip));
398 dgroupflip[j] = BKE_object_defgroup_find_name(ob, name_flip);
399 }
400 }
401
402 /* create verts */
403 mesh = (Mesh *)ob->data;
404 verts = static_cast<float(*)[3]>(
405 MEM_callocN(mesh->verts_num * sizeof(*verts), "closestboneverts"));
406
407 if (wpmode) {
408 /* if in weight paint mode, use final verts from evaluated mesh */
409 const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
410 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
411 if (mesh_eval) {
413 vertsfilled = 1;
414 }
415 }
417 /* Is subdivision-surface on? Lets use the verts on the limit surface then.
418 * = same amount of vertices as mesh, but vertices moved to the
419 * subdivision-surfaced position, like for 'optimal'. */
421 vertsfilled = 1;
422 }
423
424 /* transform verts to global space */
425 const blender::Span<blender::float3> positions = mesh->vert_positions();
426 for (int i = 0; i < mesh->verts_num; i++) {
427 if (!vertsfilled) {
428 copy_v3_v3(verts[i], positions[i]);
429 }
430 mul_m4_v3(ob->object_to_world().ptr(), verts[i]);
431 }
432
433 /* compute the weights based on gathered vertices and bones */
434 if (heat) {
435 const char *error = nullptr;
436
438 ob, mesh, verts, numbones, dgrouplist, dgroupflip, root, tip, selected, &error);
439 if (error) {
440 BKE_report(reports, RPT_WARNING, error);
441 }
442 }
443 else {
445 mesh,
446 verts,
447 numbones,
448 bonelist,
449 dgrouplist,
450 dgroupflip,
451 root,
452 tip,
453 selected,
454 mat4_to_scale(par->object_to_world().ptr()));
455 }
456
457 /* only generated in some cases but can call anyway */
459
460 /* free the memory allocated */
461 MEM_freeN(bonelist);
462 MEM_freeN(dgrouplist);
463 MEM_freeN(dgroupflip);
464 MEM_freeN(root);
465 MEM_freeN(tip);
466 MEM_freeN(selected);
468}
469
471 Depsgraph *depsgraph,
472 Scene *scene,
473 Object *ob,
474 Object *par,
475 const int mode,
476 const bool mirror)
477{
478 /* Lets try to create some vertex groups
479 * based on the bones of the parent armature.
480 */
481 bArmature *arm = static_cast<bArmature *>(par->data);
482
483 if (mode == ARM_GROUPS_NAME) {
484 const int defbase_tot = BKE_object_defgroup_count(ob);
485 int defbase_add;
486 /* Traverse the bone list, trying to create empty vertex
487 * groups corresponding to the bone.
488 */
489 defbase_add = bone_looper(
490 ob, static_cast<Bone *>(arm->bonebase.first), nullptr, vgroup_add_unique_bone_cb);
491
492 if (defbase_add) {
493 /* It's possible there are DWeights outside the range of the current
494 * object's deform groups. In this case the new groups won't be empty #33889. */
495 blender::ed::object::vgroup_data_clamp_range(static_cast<ID *>(ob->data), defbase_tot);
496 }
497 }
498 else if (ELEM(mode, ARM_GROUPS_ENVELOPE, ARM_GROUPS_AUTO)) {
499 /* Traverse the bone list, trying to create vertex groups
500 * that are populated with the vertices for which the
501 * bone is closest.
502 */
503 add_verts_to_dgroups(reports, depsgraph, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
504 }
505}
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:1334
#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:596
bDeformGroup * BKE_object_defgroup_find_name(const Object *ob, blender::StringRef name)
Definition deform.cc:520
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:125
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(...)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
#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:901
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 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)
const Depsgraph * depsgraph
draw_view in_light_buf[] float
static float verts[][3]
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
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:413
void * first
float mat[4][4]
int verts_num
struct bPose * pose