Blender V4.3
armature_deform.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 <cctype>
12#include <cfloat>
13#include <cmath>
14#include <cstdio>
15#include <cstdlib>
16#include <cstring>
17
18#include "MEM_guardedalloc.h"
19
20#include "BLI_listbase.h"
21#include "BLI_math_matrix.h"
22#include "BLI_math_rotation.h"
23#include "BLI_math_vector.h"
24#include "BLI_task.h"
25#include "BLI_utildefines.h"
26
27#include "DNA_armature_types.h"
29#include "DNA_lattice_types.h"
30#include "DNA_listBase.h"
31#include "DNA_mesh_types.h"
32#include "DNA_meshdata_types.h"
33#include "DNA_object_types.h"
34
35#include "BKE_action.hh"
36#include "BKE_armature.hh"
37#include "BKE_curves.hh"
38#include "BKE_customdata.hh"
39#include "BKE_deform.hh"
40#include "BKE_editmesh.hh"
41#include "BKE_lattice.hh"
42#include "BKE_mesh.hh"
43
45
46#include "CLG_log.h"
47
48static CLG_LogRef LOG = {"bke.armature_deform"};
49
50/* -------------------------------------------------------------------- */
54/* Add the effect of one bone or B-Bone segment to the accumulated result. */
55static void pchan_deform_accumulate(const DualQuat *deform_dq,
56 const float deform_mat[4][4],
57 const float co_in[3],
58 const float weight,
59 float co_accum[3],
60 DualQuat *dq_accum,
61 float mat_accum[3][3],
62 const bool full_deform)
63{
64 if (weight == 0.0f) {
65 return;
66 }
67
68 if (dq_accum) {
69 BLI_assert(!co_accum);
70
71 add_weighted_dq_dq_pivot(dq_accum, deform_dq, co_in, weight, full_deform);
72 }
73 else {
74 float tmp[3];
75 mul_v3_m4v3(tmp, deform_mat, co_in);
76
77 sub_v3_v3(tmp, co_in);
78 madd_v3_v3fl(co_accum, tmp, weight);
79
80 if (full_deform) {
81 float tmpmat[3][3];
82 copy_m3_m4(tmpmat, deform_mat);
83
84 madd_m3_m3m3fl(mat_accum, mat_accum, tmpmat, weight);
85 }
86 }
87}
88
89static void b_bone_deform(const bPoseChannel *pchan,
90 const float co[3],
91 const float weight,
92 float vec[3],
93 DualQuat *dq,
94 float defmat[3][3],
95 const bool full_deform)
96{
97 const DualQuat *quats = pchan->runtime.bbone_dual_quats;
98 const Mat4 *mats = pchan->runtime.bbone_deform_mats;
99 float blend;
100 int index;
101
102 /* Calculate the indices of the 2 affecting b_bone segments. */
103 BKE_pchan_bbone_deform_segment_index(pchan, co, &index, &blend);
104
105 pchan_deform_accumulate(&quats[index],
106 mats[index + 1].mat,
107 co,
108 weight * (1.0f - blend),
109 vec,
110 dq,
111 defmat,
112 full_deform);
114 &quats[index + 1], mats[index + 2].mat, co, weight * blend, vec, dq, defmat, full_deform);
115}
116
118 const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist)
119{
120 float dist_sq;
121 float bdelta[3];
122 float pdelta[3];
123 float hsqr, a, l, rad;
124
125 sub_v3_v3v3(bdelta, b2, b1);
126 l = normalize_v3(bdelta);
127
128 sub_v3_v3v3(pdelta, vec, b1);
129
130 a = dot_v3v3(bdelta, pdelta);
131 hsqr = len_squared_v3(pdelta);
132
133 if (a < 0.0f) {
134 /* If we're past the end of the bone, do a spherical field attenuation thing */
135 dist_sq = len_squared_v3v3(b1, vec);
136 rad = rad1;
137 }
138 else if (a > l) {
139 /* If we're past the end of the bone, do a spherical field attenuation thing */
140 dist_sq = len_squared_v3v3(b2, vec);
141 rad = rad2;
142 }
143 else {
144 dist_sq = (hsqr - (a * a));
145
146 if (l != 0.0f) {
147 rad = a / l;
148 rad = rad * rad2 + (1.0f - rad) * rad1;
149 }
150 else {
151 rad = rad1;
152 }
153 }
154
155 a = rad * rad;
156 if (dist_sq < a) {
157 return 1.0f;
158 }
159
160 l = rad + rdist;
161 l *= l;
162 if (rdist == 0.0f || dist_sq >= l) {
163 return 0.0f;
164 }
165
166 a = sqrtf(dist_sq) - rad;
167 return 1.0f - (a * a) / (rdist * rdist);
168}
169
170static float dist_bone_deform(const bPoseChannel *pchan,
171 float vec[3],
172 DualQuat *dq,
173 float mat[3][3],
174 const float co[3],
175 const bool full_deform)
176{
177 const Bone *bone = pchan->bone;
178 float fac, contrib = 0.0;
179
180 if (bone == nullptr) {
181 return 0.0f;
182 }
183
184 fac = distfactor_to_bone(
185 co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
186
187 if (fac > 0.0f) {
188 fac *= bone->weight;
189 contrib = fac;
190 if (contrib > 0.0f) {
191 if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) {
192 b_bone_deform(pchan, co, fac, vec, dq, mat, full_deform);
193 }
194 else {
196 &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, fac, vec, dq, mat, full_deform);
197 }
198 }
199 }
200
201 return contrib;
202}
203
204static void pchan_bone_deform(const bPoseChannel *pchan,
205 const float weight,
206 float vec[3],
207 DualQuat *dq,
208 float mat[3][3],
209 const float co[3],
210 const bool full_deform,
211 float *contrib)
212{
213 const Bone *bone = pchan->bone;
214
215 if (!weight) {
216 return;
217 }
218
219 if (bone->segments > 1 && pchan->runtime.bbone_segments == bone->segments) {
220 b_bone_deform(pchan, co, weight, vec, dq, mat, full_deform);
221 }
222 else {
224 &pchan->runtime.deform_dual_quat, pchan->chan_mat, co, weight, vec, dq, mat, full_deform);
225 }
226
227 (*contrib) += weight;
228}
229
232/* -------------------------------------------------------------------- */
266
268 const int i,
269 const MDeformVert *dvert)
270{
271 float(*const vert_coords)[3] = data->vert_coords;
272 float(*const vert_deform_mats)[3][3] = data->vert_deform_mats;
273 float(*const vert_coords_prev)[3] = data->vert_coords_prev;
274 const bool use_envelope = data->use_envelope;
275 const bool use_quaternion = data->use_quaternion;
276 const bool use_dverts = data->use_dverts;
277 const int armature_def_nr = data->armature_def_nr;
278
279 DualQuat sumdq, *dq = nullptr;
280 const bPoseChannel *pchan;
281 float *co, dco[3];
282 float sumvec[3], summat[3][3];
283 float *vec = nullptr, (*smat)[3] = nullptr;
284 float contrib = 0.0f;
285 float armature_weight = 1.0f; /* default to 1 if no overall def group */
286 float prevco_weight = 0.0f; /* weight for optional cached vertexcos */
287
288 const bool full_deform = vert_deform_mats != nullptr;
289
290 if (use_quaternion) {
291 memset(&sumdq, 0, sizeof(DualQuat));
292 dq = &sumdq;
293 }
294 else {
295 zero_v3(sumvec);
296 vec = sumvec;
297
298 if (full_deform) {
299 zero_m3(summat);
300 smat = summat;
301 }
302 }
303
304 if (armature_def_nr != -1 && dvert) {
305 armature_weight = BKE_defvert_find_weight(dvert, armature_def_nr);
306
307 if (data->invert_vgroup) {
308 armature_weight = 1.0f - armature_weight;
309 }
310
311 /* hackish: the blending factor can be used for blending with vert_coords_prev too */
312 if (vert_coords_prev) {
313 /* This weight specifies the contribution from the coordinates at the start of this
314 * modifier evaluation, while armature_weight is normally the opposite of that. */
315 prevco_weight = 1.0f - armature_weight;
316 armature_weight = 1.0f;
317 }
318 }
319
320 /* check if there's any point in calculating for this vert */
321 if (vert_coords_prev) {
322 if (prevco_weight == 1.0f) {
323 return;
324 }
325
326 /* get the coord we work on */
327 co = vert_coords_prev[i];
328 }
329 else {
330 if (armature_weight == 0.0f) {
331 return;
332 }
333
334 /* get the coord we work on */
335 co = vert_coords[i];
336 }
337
338 /* Apply the object's matrix */
339 mul_m4_v3(data->premat, co);
340
341 if (use_dverts && dvert && dvert->totweight) { /* use weight groups ? */
342 const MDeformWeight *dw = dvert->dw;
343 int deformed = 0;
344 uint j;
345 for (j = dvert->totweight; j != 0; j--, dw++) {
346 const uint index = dw->def_nr;
347 if (index < data->defbase_len && (pchan = data->pchan_from_defbase[index])) {
348 float weight = dw->weight;
349 const Bone *bone = pchan->bone;
350
351 deformed = 1;
352
353 if (bone && bone->flag & BONE_MULT_VG_ENV) {
354 weight *= distfactor_to_bone(
355 co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
356 }
357
358 pchan_bone_deform(pchan, weight, vec, dq, smat, co, full_deform, &contrib);
359 }
360 }
361 /* If there are vertex-groups but not groups with bones (like for soft-body groups). */
362 if (deformed == 0 && use_envelope) {
363 for (pchan = static_cast<const bPoseChannel *>(data->ob_arm->pose->chanbase.first); pchan;
364 pchan = pchan->next)
365 {
366 if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
367 contrib += dist_bone_deform(pchan, vec, dq, smat, co, full_deform);
368 }
369 }
370 }
371 }
372 else if (use_envelope) {
373 for (pchan = static_cast<const bPoseChannel *>(data->ob_arm->pose->chanbase.first); pchan;
374 pchan = pchan->next)
375 {
376 if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
377 contrib += dist_bone_deform(pchan, vec, dq, smat, co, full_deform);
378 }
379 }
380 }
381
382 /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */
383 if (contrib > 0.0001f) {
384 if (use_quaternion) {
385 normalize_dq(dq, contrib);
386
387 if (armature_weight != 1.0f) {
388 copy_v3_v3(dco, co);
389 mul_v3m3_dq(dco, full_deform ? summat : nullptr, dq);
390 sub_v3_v3(dco, co);
391 mul_v3_fl(dco, armature_weight);
392 add_v3_v3(co, dco);
393 }
394 else {
395 mul_v3m3_dq(co, full_deform ? summat : nullptr, dq);
396 }
397
398 smat = summat;
399 }
400 else {
401 mul_v3_fl(vec, armature_weight / contrib);
402 add_v3_v3v3(co, vec, co);
403 }
404
405 if (full_deform) {
406 float pre[3][3], post[3][3], tmpmat[3][3];
407
408 copy_m3_m4(pre, data->premat);
409 copy_m3_m4(post, data->postmat);
410 copy_m3_m3(tmpmat, vert_deform_mats[i]);
411
412 if (!use_quaternion) { /* quaternion already is scale corrected */
413 mul_m3_fl(smat, armature_weight / contrib);
414 }
415
416 mul_m3_series(vert_deform_mats[i], post, smat, pre, tmpmat);
417 }
418 }
419
420 /* always, check above code */
421 mul_m4_v3(data->postmat, co);
422
423 /* interpolate with previous modifier position using weight group */
424 if (vert_coords_prev) {
425 float mw = 1.0f - prevco_weight;
426 vert_coords[i][0] = prevco_weight * vert_coords[i][0] + mw * co[0];
427 vert_coords[i][1] = prevco_weight * vert_coords[i][1] + mw * co[1];
428 vert_coords[i][2] = prevco_weight * vert_coords[i][2] + mw * co[2];
429 }
430}
431
432static void armature_vert_task(void *__restrict userdata,
433 const int i,
434 const TaskParallelTLS *__restrict /*tls*/)
435{
436 const ArmatureUserdata *data = static_cast<const ArmatureUserdata *>(userdata);
437 const MDeformVert *dvert;
438 if (data->use_dverts || data->armature_def_nr != -1) {
439 if (data->me_target) {
440 BLI_assert(i < data->me_target->verts_num);
441 if (data->dverts != nullptr) {
442 dvert = data->dverts + i;
443 }
444 else {
445 dvert = nullptr;
446 }
447 }
448 else if (data->dverts && i < data->dverts_len) {
449 dvert = data->dverts + i;
450 }
451 else {
452 dvert = nullptr;
453 }
454 }
455 else {
456 dvert = nullptr;
457 }
458
459 armature_vert_task_with_dvert(data, i, dvert);
460}
461
462static void armature_vert_task_editmesh(void *__restrict userdata,
463 MempoolIterData *iter,
464 const TaskParallelTLS *__restrict /*tls*/)
465{
466 const ArmatureUserdata *data = static_cast<const ArmatureUserdata *>(userdata);
467 BMVert *v = (BMVert *)iter;
468 const MDeformVert *dvert = static_cast<const MDeformVert *>(
469 BM_ELEM_CD_GET_VOID_P(v, data->bmesh.cd_dvert_offset));
471}
472
473static void armature_vert_task_editmesh_no_dvert(void *__restrict userdata,
474 MempoolIterData *iter,
475 const TaskParallelTLS *__restrict /*tls*/)
476{
477 const ArmatureUserdata *data = static_cast<const ArmatureUserdata *>(userdata);
478 BMVert *v = (BMVert *)iter;
480}
481
482static void armature_deform_coords_impl(const Object *ob_arm,
483 const Object *ob_target,
484 const ListBase *defbase,
485 float (*vert_coords)[3],
486 float (*vert_deform_mats)[3][3],
487 const int vert_coords_len,
488 const int deformflag,
489 float (*vert_coords_prev)[3],
490 const char *defgrp_name,
492 const Mesh *me_target,
493 const BMEditMesh *em_target)
494{
495 const bArmature *arm = static_cast<const bArmature *>(ob_arm->data);
496 bPoseChannel **pchan_from_defbase = nullptr;
497 const bool use_envelope = (deformflag & ARM_DEF_ENVELOPE) != 0;
498 const bool use_quaternion = (deformflag & ARM_DEF_QUATERNION) != 0;
499 const bool invert_vgroup = (deformflag & ARM_DEF_INVERT_VGROUP) != 0;
500 int defbase_len = 0; /* safety for vertexgroup index overflow */
501 bool use_dverts = false;
502 int armature_def_nr = -1;
503 int cd_dvert_offset = -1;
504
505 /* in editmode, or not an armature */
506 if (arm->edbo || (ob_arm->pose == nullptr)) {
507 return;
508 }
509
510 if ((ob_arm->pose->flag & POSE_RECALC) != 0) {
512 "Trying to evaluate influence of armature '%s' which needs Pose recalc!",
513 ob_arm->id.name);
514 BLI_assert(0);
515 }
516
517 if (BKE_object_supports_vertex_groups(ob_target)) {
518 /* Collect the vertex group names from the evaluated data. */
519 armature_def_nr = BKE_defgroup_name_index(defbase, defgrp_name);
520 defbase_len = BLI_listbase_count(defbase);
521
522 /* get a vertex-deform-index to posechannel array */
523 if (deformflag & ARM_DEF_VGROUP) {
524 /* if we have a Mesh, only use dverts if it has them */
525 if (em_target) {
526 cd_dvert_offset = CustomData_get_offset(&em_target->bm->vdata, CD_MDEFORMVERT);
527 use_dverts = (cd_dvert_offset != -1);
528 }
529 else if (me_target) {
530 use_dverts = !me_target->deform_verts().is_empty();
531 }
532 else if (dverts.size() == vert_coords_len) {
533 use_dverts = true;
534 }
535
536 if (use_dverts) {
537 pchan_from_defbase = static_cast<bPoseChannel **>(
538 MEM_callocN(sizeof(*pchan_from_defbase) * defbase_len, "defnrToBone"));
539 /* TODO(sergey): Some considerations here:
540 *
541 * - Check whether keeping this consistent across frames gives speedup.
542 */
543 int i;
544 LISTBASE_FOREACH_INDEX (bDeformGroup *, dg, defbase, i) {
545 pchan_from_defbase[i] = BKE_pose_channel_find_name(ob_arm->pose, dg->name);
546 /* exclude non-deforming bones */
547 if (pchan_from_defbase[i]) {
548 if (pchan_from_defbase[i]->bone->flag & BONE_NO_DEFORM) {
549 pchan_from_defbase[i] = nullptr;
550 }
551 }
552 }
553 }
554 }
555 }
556
557 ArmatureUserdata data{};
558 data.ob_arm = ob_arm;
559 data.me_target = me_target;
560 data.vert_coords = vert_coords;
561 data.vert_deform_mats = vert_deform_mats;
562 data.vert_coords_prev = vert_coords_prev;
563 data.use_envelope = use_envelope;
564 data.use_quaternion = use_quaternion;
565 data.invert_vgroup = invert_vgroup;
566 data.use_dverts = use_dverts;
567 data.armature_def_nr = armature_def_nr;
568 data.dverts = dverts.data();
569 data.dverts_len = dverts.size();
570 data.pchan_from_defbase = pchan_from_defbase;
571 data.defbase_len = defbase_len;
572 data.bmesh.cd_dvert_offset = cd_dvert_offset;
573
574 float obinv[4][4];
575 invert_m4_m4(obinv, ob_target->object_to_world().ptr());
576
577 mul_m4_m4m4(data.postmat, obinv, ob_arm->object_to_world().ptr());
578 invert_m4_m4(data.premat, data.postmat);
579
580 if (em_target != nullptr) {
581 /* While this could cause an extra loop over mesh data, in most cases this will
582 * have already been properly set. */
584
585 TaskParallelSettings settings;
587
588 if (use_dverts) {
590 em_target->bm->vpool, &data, armature_vert_task_editmesh, &settings);
591 }
592 else {
594 em_target->bm->vpool, &data, armature_vert_task_editmesh_no_dvert, &settings);
595 }
596 }
597 else {
598 TaskParallelSettings settings;
600 settings.min_iter_per_thread = 32;
601 BLI_task_parallel_range(0, vert_coords_len, &data, armature_vert_task, &settings);
602 }
603
604 if (pchan_from_defbase) {
605 MEM_freeN(pchan_from_defbase);
606 }
607}
608
610 const Object *ob_target,
611 float (*vert_coords)[3],
612 float (*vert_deform_mats)[3][3],
613 int vert_coords_len,
614 int deformflag,
615 float (*vert_coords_prev)[3],
616 const char *defgrp_name,
617 bGPDstroke *gps_target)
618{
619 const ListBase *defbase = BKE_id_defgroup_list_get(static_cast<const ID *>(ob_target->data));
620 const blender::Span<MDeformVert> dverts = {gps_target->dvert, gps_target->totpoints};
622 ob_target,
623 defbase,
624 vert_coords,
625 vert_deform_mats,
626 vert_coords_len,
627 deformflag,
628 vert_coords_prev,
629 defgrp_name,
630 dverts,
631 nullptr,
632 nullptr);
633}
634
636 const Object &ob_arm,
637 const Object &ob_target,
638 const ListBase *defbase,
640 std::optional<blender::MutableSpan<blender::float3>> vert_coords_prev,
641 std::optional<blender::MutableSpan<blender::float3x3>> vert_deform_mats,
643 int deformflag,
644 blender::StringRefNull defgrp_name)
645{
646 /* Vertex groups must be provided explicitly, cannot rely on object vertex groups since this is
647 * used for Grease Pencil layers as well. */
648 BLI_assert(dverts.size() == vert_coords.size());
649
651 &ob_arm,
652 &ob_target,
653 defbase,
654 reinterpret_cast<float(*)[3]>(vert_coords.data()),
655 vert_deform_mats ? reinterpret_cast<float(*)[3][3]>(vert_deform_mats->data()) : nullptr,
656 vert_coords.size(),
657 deformflag,
658 vert_coords_prev ? reinterpret_cast<float(*)[3]>(vert_coords_prev->data()) : nullptr,
659 defgrp_name.c_str(),
660 dverts,
661 nullptr,
662 nullptr);
663}
664
666 const Object *ob_target,
667 float (*vert_coords)[3],
668 float (*vert_deform_mats)[3][3],
669 int vert_coords_len,
670 int deformflag,
671 float (*vert_coords_prev)[3],
672 const char *defgrp_name,
673 const Mesh *me_target)
674{
675 /* Note armature modifier on legacy curves calls this, so vertex groups are not guaranteed to
676 * exist. */
677 const ID *id_target = static_cast<const ID *>(ob_target->data);
678 const ListBase *defbase = BKE_id_supports_vertex_groups(id_target) ?
679 BKE_id_defgroup_list_get(id_target) :
680 nullptr;
682 if (ob_target->type == OB_MESH) {
683 if (me_target == nullptr) {
684 me_target = static_cast<const Mesh *>(ob_target->data);
685 }
686 dverts = me_target->deform_verts();
687 }
688 else if (ob_target->type == OB_LATTICE) {
689 const Lattice *lt = static_cast<const Lattice *>(ob_target->data);
690 dverts = blender::Span<MDeformVert>(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
691 }
692
694 ob_target,
695 defbase,
696 vert_coords,
697 vert_deform_mats,
698 vert_coords_len,
699 deformflag,
700 vert_coords_prev,
701 defgrp_name,
702 dverts,
703 me_target,
704 nullptr);
705}
706
708 const Object *ob_target,
709 float (*vert_coords)[3],
710 float (*vert_deform_mats)[3][3],
711 int vert_coords_len,
712 int deformflag,
713 float (*vert_coords_prev)[3],
714 const char *defgrp_name,
715 const BMEditMesh *em_target)
716{
717 const ListBase *defbase = BKE_id_defgroup_list_get(static_cast<const ID *>(ob_target->data));
719 ob_target,
720 defbase,
721 vert_coords,
722 vert_deform_mats,
723 vert_coords_len,
724 deformflag,
725 vert_coords_prev,
726 defgrp_name,
727 {},
728 nullptr,
729 em_target);
730}
731
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
void BKE_pchan_bbone_deform_segment_index(const bPoseChannel *pchan, const float *co, int *r_index, float *r_blend_next)
Definition armature.cc:1970
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
support for deformation groups and hooks.
bool BKE_id_supports_vertex_groups(const ID *id)
Definition deform.cc:449
bool BKE_object_supports_vertex_groups(const Object *ob)
Definition deform.cc:457
int BKE_defgroup_name_index(const ListBase *defbase, blender::StringRef name)
Definition deform.cc:534
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:770
const ListBase * BKE_id_defgroup_list_get(const ID *id)
Definition deform.cc:464
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void copy_m3_m3(float m1[3][3], const float m2[3][3])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void mul_m3_fl(float R[3][3], float f)
void zero_m3(float m[3][3])
void mul_m4_v3(const float M[4][4], float r[3])
void madd_m3_m3m3fl(float R[3][3], const float A[3][3], const float B[3][3], float f)
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
#define mul_m3_series(...)
void mul_v3m3_dq(float r[3], float R[3][3], DualQuat *dq)
void add_weighted_dq_dq_pivot(DualQuat *dq_sum, const DualQuat *dq, const float pivot[3], float weight, bool compute_scale_matrix)
void normalize_dq(DualQuat *dq, float totweight)
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
unsigned int uint
struct MempoolIterData MempoolIterData
Definition BLI_task.h:209
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition task_range.cc:99
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:230
void BLI_task_parallel_mempool(struct BLI_mempool *mempool, void *userdata, TaskParallelMempoolFunc func, const TaskParallelSettings *settings)
BLI_INLINE void BLI_parallel_mempool_settings_defaults(TaskParallelSettings *settings)
Definition BLI_task.h:238
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
@ POSE_RECALC
@ ARM_DEF_VGROUP
@ ARM_DEF_QUATERNION
@ ARM_DEF_INVERT_VGROUP
@ ARM_DEF_ENVELOPE
@ BONE_MULT_VG_ENV
@ BONE_NO_DEFORM
@ CD_MDEFORMVERT
These structs are the foundation for all linked lists in the library system.
Object is a sort of wrapper for general info.
@ OB_LATTICE
@ OB_MESH
Read Guarded memory(de)allocation.
static float dist_bone_deform(const bPoseChannel *pchan, float vec[3], DualQuat *dq, float mat[3][3], const float co[3], const bool full_deform)
static void armature_vert_task(void *__restrict userdata, const int i, const TaskParallelTLS *__restrict)
static void b_bone_deform(const bPoseChannel *pchan, const float co[3], const float weight, float vec[3], DualQuat *dq, float defmat[3][3], const bool full_deform)
void BKE_armature_deform_coords_with_editmesh(const Object *ob_arm, const Object *ob_target, float(*vert_coords)[3], float(*vert_deform_mats)[3][3], int vert_coords_len, int deformflag, float(*vert_coords_prev)[3], const char *defgrp_name, const BMEditMesh *em_target)
static void armature_vert_task_with_dvert(const ArmatureUserdata *data, const int i, const MDeformVert *dvert)
float distfactor_to_bone(const float vec[3], const float b1[3], const float b2[3], float rad1, float rad2, float rdist)
void BKE_armature_deform_coords_with_mesh(const Object *ob_arm, const Object *ob_target, float(*vert_coords)[3], float(*vert_deform_mats)[3][3], int vert_coords_len, int deformflag, float(*vert_coords_prev)[3], const char *defgrp_name, const Mesh *me_target)
static void pchan_bone_deform(const bPoseChannel *pchan, const float weight, float vec[3], DualQuat *dq, float mat[3][3], const float co[3], const bool full_deform, float *contrib)
void BKE_armature_deform_coords_with_gpencil_stroke(const Object *ob_arm, const Object *ob_target, float(*vert_coords)[3], float(*vert_deform_mats)[3][3], int vert_coords_len, int deformflag, float(*vert_coords_prev)[3], const char *defgrp_name, bGPDstroke *gps_target)
static void armature_vert_task_editmesh(void *__restrict userdata, MempoolIterData *iter, const TaskParallelTLS *__restrict)
void BKE_armature_deform_coords_with_curves(const Object &ob_arm, const Object &ob_target, const ListBase *defbase, blender::MutableSpan< blender::float3 > vert_coords, std::optional< blender::MutableSpan< blender::float3 > > vert_coords_prev, std::optional< blender::MutableSpan< blender::float3x3 > > vert_deform_mats, blender::Span< MDeformVert > dverts, int deformflag, blender::StringRefNull defgrp_name)
static CLG_LogRef LOG
static void armature_vert_task_editmesh_no_dvert(void *__restrict userdata, MempoolIterData *iter, const TaskParallelTLS *__restrict)
static void armature_deform_coords_impl(const Object *ob_arm, const Object *ob_target, const ListBase *defbase, float(*vert_coords)[3], float(*vert_deform_mats)[3][3], const int vert_coords_len, const int deformflag, float(*vert_coords_prev)[3], const char *defgrp_name, blender::Span< MDeformVert > dverts, const Mesh *me_target, const BMEditMesh *em_target)
static void pchan_deform_accumulate(const DualQuat *deform_dq, const float deform_mat[4][4], const float co_in[3], const float weight, float co_accum[3], DualQuat *dq_accum, float mat_accum[3][3], const bool full_deform)
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
#define BM_elem_index_get(ele)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
#define BM_VERT
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr T * data() const
Definition BLI_span.hh:540
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr const char * c_str() const
#define sqrtf(x)
draw_view in_light_buf[] float
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
float(* vert_deform_mats)[3][3]
bPoseChannel ** pchan_from_defbase
const MDeformVert * dverts
struct ArmatureUserdata::@75 bmesh
float(* vert_coords)[3]
float(* vert_coords_prev)[3]
const Mesh * me_target
const Object * ob_arm
CustomData vdata
struct BLI_mempool * vpool
float arm_head[3]
float arm_tail[3]
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
struct MDeformVert * dvert
struct MDeformWeight * dw
unsigned int def_nr
struct bPose * pose
ListBase * edbo
struct MDeformVert * dvert
struct Mat4 * bbone_deform_mats
struct DualQuat deform_dual_quat
struct DualQuat * bbone_dual_quats
struct Bone * bone
float chan_mat[4][4]
struct bPoseChannel * next
struct bPoseChannel_Runtime runtime