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