Blender V5.0
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"
21#include "BLI_math_matrix.h"
23#include "BLI_math_rotation.h"
24#include "BLI_math_vector.h"
25#include "BLI_task.h"
26#include "BLI_task.hh"
27
28#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_customdata.hh"
38#include "BKE_deform.hh"
39#include "BKE_editmesh.hh"
40#include "BKE_lattice.hh"
41#include "BKE_mesh.hh"
42
43#include "CLG_log.h"
44
45static CLG_LogRef LOG = {"geom.armature_deform"};
46
47/* -------------------------------------------------------------------- */
50
51static float bone_envelope_falloff(const float distance_squared,
52 const float closest_radius,
53 const float falloff_distance)
54{
55 using namespace blender;
56
57 if (distance_squared < closest_radius * closest_radius) {
58 return 1.0f;
59 }
60
61 /* Zero influence beyond falloff distance. */
62 if (falloff_distance == 0.0f ||
63 distance_squared >= math::square(closest_radius + falloff_distance))
64 {
65 return 0.0f;
66 }
67
68 /* Compute influence from envelope over the falloff distance. */
69 const float dist_envelope = sqrtf(distance_squared) - closest_radius;
70 return 1.0f - (dist_envelope * dist_envelope) / (falloff_distance * falloff_distance);
71}
72
73float distfactor_to_bone(const blender::float3 &position,
74 const blender::float3 &head,
75 const blender::float3 &tail,
76 const float radius_head,
77 const float radius_tail,
78 const float falloff_distance)
79{
80 using namespace blender;
81
82 float bone_length;
83 const float3 bone_axis = math::normalize_and_get_length(tail - head, bone_length);
84 /* Distance along the bone axis from head. */
85 const float height = math::dot(position - head, bone_axis);
86
87 if (height < 0.0f) {
88 /* Below the start of the bone use the head radius. */
89 const float distance_squared = math::distance_squared(position, head);
90 return bone_envelope_falloff(distance_squared, radius_head, falloff_distance);
91 }
92 else if (height > bone_length) {
93 /* After the end of the bone use the tail radius. */
94 const float distance_squared = math::distance_squared(tail, position);
95 return bone_envelope_falloff(distance_squared, radius_tail, falloff_distance);
96 }
97 else {
98 /* Interpolate radius. */
99 const float distance_squared = math::distance_squared(position, head) - height * height;
100 const float closest_radius = bone_length != 0.0f ? math::interpolate(radius_head,
101 radius_tail,
102 height / bone_length) :
103 radius_head;
104 return bone_envelope_falloff(distance_squared, closest_radius, falloff_distance);
105 }
106}
107
108namespace blender::bke {
109
114template<bool full_deform> struct BoneDeformLinearMixer {
115
118
119 void accumulate(const bPoseChannel &pchan, const float3 &co, const float weight)
120 {
121 const float4x4 &pose_mat = float4x4(pchan.chan_mat);
122
123 position_delta += weight * (math::transform_point(pose_mat, co) - co);
124 if constexpr (full_deform) {
125 deform += weight * pose_mat.view<3, 3>();
126 }
127 }
128
130 const float3 &co,
131 const float weight,
132 const int index)
133 {
134 const Span<float4x4> pose_mats = Span<Mat4>(pchan.runtime.bbone_deform_mats,
135 pchan.runtime.bbone_segments + 2)
136 .cast<float4x4>();
137 const float4x4 &pose_mat = pose_mats[index + 1];
138
139 position_delta += weight * (math::transform_point(pose_mat, co) - co);
140 if constexpr (full_deform) {
141 deform += weight * pose_mat.view<3, 3>();
142 }
143 }
144
145 void finalize(const float3 & /*co*/,
146 float total,
147 float armature_weight,
148 float3 &r_delta_co,
149 float3x3 &r_deform_mat)
150 {
151 const float scale_factor = armature_weight / total;
152 r_delta_co = position_delta * scale_factor;
153 r_deform_mat = deform * scale_factor;
154 };
155};
156
161template<bool full_deform> struct BoneDeformDualQuaternionMixer {
163
164 void accumulate(const bPoseChannel &pchan, const float3 &co, const float weight)
165 {
166 const DualQuat &deform_quat = pchan.runtime.deform_dual_quat;
167
168 add_weighted_dq_dq_pivot(&dq, &deform_quat, co, weight, full_deform);
169 }
170
172 const float3 &co,
173 const float weight,
174 const int index)
175 {
176 const Span<DualQuat> quats = {pchan.runtime.bbone_dual_quats,
177 pchan.runtime.bbone_segments + 1};
178 const DualQuat &deform_quat = quats[index];
179
180 add_weighted_dq_dq_pivot(&dq, &deform_quat, co, weight, full_deform);
181 }
182
183 void finalize(const float3 &co,
184 float total,
185 float armature_weight,
186 float3 &r_delta_co,
187 float3x3 &r_deform_mat)
188 {
189 normalize_dq(&dq, total);
190 float3 dco = co;
191 float3x3 dmat;
192 mul_v3m3_dq(dco, dmat.ptr(), &dq);
193 r_delta_co = (dco - co) * armature_weight;
194 /* Quaternion already is scale corrected. */
195 r_deform_mat = dmat;
196 }
197};
198
199/* Add interpolated deformation along a b-bone segment of the pose channel. */
200template<typename MixerT>
201static void b_bone_deform(const bPoseChannel &pchan,
202 const float3 &co,
203 const float weight,
204 MixerT &mixer)
205{
206 /* Calculate the indices of the 2 affecting b_bone segments. */
207 int index;
208 float blend;
209 BKE_pchan_bbone_deform_segment_index(&pchan, co, &index, &blend);
210
211 mixer.accumulate_bbone(pchan, co, weight * (1.0f - blend), index);
212 mixer.accumulate_bbone(pchan, co, weight * blend, index + 1);
213}
214
215/* Add bone deformation based on envelope distance. */
216template<typename MixerT>
217static float dist_bone_deform(const bPoseChannel &pchan, const float3 &co, MixerT &mixer)
218{
219 const Bone *bone = pchan.bone;
220 if (bone == nullptr || bone->weight == 0.0f) {
221 return 0.0f;
222 }
223
224 const float fac = distfactor_to_bone(co,
225 float3(bone->arm_head),
226 float3(bone->arm_tail),
227 bone->rad_head,
228 bone->rad_tail,
229 bone->dist);
230 if (fac == 0.0f) {
231 return 0.0f;
232 }
233
234 const float weight = fac * bone->weight;
235 if (bone->segments > 1 && pchan.runtime.bbone_segments == bone->segments) {
236 b_bone_deform(pchan, co, weight, mixer);
237 }
238 else {
239 mixer.accumulate(pchan, co, weight);
240 }
241
242 return weight;
243}
244
245/* Add bone deformation based on vertex group weight. */
246template<typename MixerT>
247static float pchan_bone_deform(const bPoseChannel &pchan,
248 const float weight,
249 const float3 &co,
250 MixerT &mixer)
251{
252 const Bone *bone = pchan.bone;
253
254 if (!weight) {
255 return 0.0f;
256 }
257
258 if (bone->segments > 1 && pchan.runtime.bbone_segments == bone->segments) {
259 b_bone_deform(pchan, co, weight, mixer);
260 }
261 else {
262 mixer.accumulate(pchan, co, weight);
263 }
264
265 return weight;
266}
267
268} // namespace blender::bke
269
271
272/* -------------------------------------------------------------------- */
277
278namespace blender::bke {
279
282 std::optional<MutableSpan<float3x3>> vert_deform_mats;
283 std::optional<Span<float3>> vert_coords_prev;
284
288
290
291 /* List of all pose channels on the target object. */
293 /* Maps vertex group index (def_nr) to pose channels, if vertex groups are used.
294 * Vertex groups used for deform can be different from the target object vertex groups list,
295 * the def_nr needs to be mapped to the correct pose channel first. */
297
300};
301
303 const Object &ob_arm,
304 const Object &ob_target,
305 const ListBase *defbase,
306 MutableSpan<float3> vert_coords,
307 std::optional<Span<float3>> vert_coords_prev,
308 std::optional<MutableSpan<float3x3>> vert_deform_mats,
309 const int deformflag,
310 blender::StringRefNull defgrp_name,
311 const bool try_use_dverts)
312{
313 const bool dverts_supported = BKE_object_supports_vertex_groups(&ob_target);
314
315 ArmatureDeformParams deform_params;
316 deform_params.vert_coords = vert_coords;
317 deform_params.vert_deform_mats = vert_deform_mats;
318 deform_params.vert_coords_prev = vert_coords_prev;
319 deform_params.use_envelope = bool(deformflag & ARM_DEF_ENVELOPE);
320 deform_params.invert_vgroup = bool(deformflag & ARM_DEF_INVERT_VGROUP);
321
322 deform_params.pose_channels = {ob_arm.pose->chanbase};
323 deform_params.use_dverts = try_use_dverts && dverts_supported && (deformflag & ARM_DEF_VGROUP);
324 if (deform_params.use_dverts) {
325 const int defbase_len = BLI_listbase_count(defbase);
326 deform_params.pose_channel_by_vertex_group.reinitialize(defbase_len);
327 /* TODO(sergey): Some considerations here:
328 *
329 * - Check whether keeping this consistent across frames gives speedup.
330 */
331 int i;
332 LISTBASE_FOREACH_INDEX (bDeformGroup *, dg, defbase, i) {
333 bPoseChannel *pchan = BKE_pose_channel_find_name(ob_arm.pose, dg->name);
334 /* Exclude non-deforming bones. */
335 deform_params.pose_channel_by_vertex_group[i] = (pchan &&
336 !(pchan->bone->flag & BONE_NO_DEFORM)) ?
337 pchan :
338 nullptr;
339 }
340 }
341
342 /* Index of singular vertex group, if used. */
343 deform_params.armature_def_nr = dverts_supported ?
344 BKE_defgroup_name_index(defbase, defgrp_name) :
345 -1;
346
347/* TODO using the existing matrices directly is better, but fails tests because old code was
348 * doing a double-inverse of the object matrix, leading to small differences on the order of 10^-5.
349 * Test data needs to be updated if the transforms change. */
350#if 0
351 deform_params.target_to_armature = ob_arm.world_to_object() * ob_target.object_to_world();
352 deform_params.armature_to_target = ob_target.world_to_object() * ob_arm.object_to_world();
353#else
354 deform_params.armature_to_target = ob_target.world_to_object() * ob_arm.object_to_world();
355 deform_params.target_to_armature = math::invert(deform_params.armature_to_target);
356#endif
357
358 return deform_params;
359}
360
361/* Accumulate bone deformations using the mixer implementation. */
362template<typename MixerT>
364 const int i,
365 const MDeformVert *dvert,
366 MixerT &mixer)
367{
368 const bool full_deform = params.vert_deform_mats.has_value();
369
370 /* Overall influence, can change by masking with a vertex group. */
371 float armature_weight = 1.0f;
372 float prevco_weight = 0.0f; /* weight for optional cached vertexcos */
373 if (params.armature_def_nr != -1 && dvert) {
374 const float mask_weight = BKE_defvert_find_weight(dvert, params.armature_def_nr);
375 /* On multi-modifier the mask is used to blend with previous coordinates. */
376 if (params.vert_coords_prev) {
377 prevco_weight = params.invert_vgroup ? mask_weight : 1.0f - mask_weight;
378 if (prevco_weight == 1.0f) {
379 return;
380 }
381 }
382 else {
383 armature_weight = params.invert_vgroup ? 1.0f - mask_weight : mask_weight;
384 if (armature_weight == 0.0f) {
385 return;
386 }
387 }
388 }
389
390 /* Input coordinates to start from. */
391 float3 co = params.vert_coords_prev ? (*params.vert_coords_prev)[i] : params.vert_coords[i];
392 /* Transform to armature space. */
393 co = math::transform_point(params.target_to_armature, co);
394
395 float contrib = 0.0f;
396 bool deformed = false;
397 /* Apply vertex group deformation if enabled. */
398 if (params.use_dverts && dvert) {
399 /* Range of valid def_nr in MDeformWeight. */
400 const IndexRange def_nr_range = params.pose_channel_by_vertex_group.index_range();
401 const Span<MDeformWeight> dweights(dvert->dw, dvert->totweight);
402 for (const auto &dw : dweights) {
403 const bPoseChannel *pchan = def_nr_range.contains(dw.def_nr) ?
404 params.pose_channel_by_vertex_group[dw.def_nr] :
405 nullptr;
406 if (pchan == nullptr) {
407 continue;
408 }
409
410 float weight = dw.weight;
411
412 /* Bone option to mix with envelope weight. */
413 const Bone *bone = pchan->bone;
414 if (bone && bone->flag & BONE_MULT_VG_ENV) {
415 weight *= distfactor_to_bone(co,
416 float3(bone->arm_head),
417 float3(bone->arm_tail),
418 bone->rad_head,
419 bone->rad_tail,
420 bone->dist);
421 }
422
423 contrib += pchan_bone_deform(*pchan, weight, co, mixer);
424 deformed = true;
425 }
426 }
427 /* Use envelope if enabled and no bone deformed the vertex yet. */
428 if (!deformed && params.use_envelope) {
429 for (const bPoseChannel *pchan : params.pose_channels) {
430 if (!(pchan->bone->flag & BONE_NO_DEFORM)) {
431 contrib += dist_bone_deform(*pchan, co, mixer);
432 }
433 }
434 }
435
436 /* TODO Actually should be EPSILON? Weight values and contrib can be like 10e-39 small. */
437 constexpr float contrib_threshold = 0.0001f;
438 if (contrib > contrib_threshold) {
439 float3 delta_co;
440 float3x3 local_deform_mat;
441 mixer.finalize(co, contrib, armature_weight, delta_co, local_deform_mat);
442
443 co += delta_co;
444 if (full_deform) {
445 float3x3 &deform_mat = (*params.vert_deform_mats)[i];
446 const float3x3 armature_to_target = params.armature_to_target.view<3, 3>();
447 const float3x3 target_to_armature = params.target_to_armature.view<3, 3>();
448 deform_mat = armature_to_target * local_deform_mat * target_to_armature * deform_mat;
449 }
450 }
451
452 /* Transform back to target object space. */
453 co = math::transform_point(params.armature_to_target, co);
454
455 /* Multi-modifier: Interpolate with previous modifier position using the vertex group mask. */
456 if (params.vert_coords_prev) {
457 copy_v3_v3(params.vert_coords[i], math::interpolate(co, params.vert_coords[i], prevco_weight));
458 }
459 else {
460 copy_v3_v3(params.vert_coords[i], co);
461 }
462}
463
464/* Accumulate bone deformations for a vertex. */
466 const int i,
467 const MDeformVert *dvert,
468 const bool use_quaternion)
469{
470 const bool full_deform = deform_params.vert_deform_mats.has_value();
471 if (use_quaternion) {
472 if (full_deform) {
474 armature_vert_task_with_mixer(deform_params, i, dvert, mixer);
475 }
476 else {
478 armature_vert_task_with_mixer(deform_params, i, dvert, mixer);
479 }
480 }
481 else {
482 if (full_deform) {
484 armature_vert_task_with_mixer(deform_params, i, dvert, mixer);
485 }
486 else {
488 armature_vert_task_with_mixer(deform_params, i, dvert, mixer);
489 }
490 }
491}
492
493static void armature_deform_coords(const Object &ob_arm,
494 const Object &ob_target,
495 const ListBase *defbase,
496 const MutableSpan<float3> vert_coords,
497 const std::optional<MutableSpan<float3x3>> vert_deform_mats,
498 const int deformflag,
499 const std::optional<Span<float3>> vert_coords_prev,
500 blender::StringRefNull defgrp_name,
501 const std::optional<Span<MDeformVert>> dverts,
502 const Mesh *me_target)
503{
505 ob_target,
506 defbase,
507 vert_coords,
508 vert_coords_prev,
509 vert_deform_mats,
510 deformflag,
511 defgrp_name,
512 dverts.has_value());
513
514 const bool use_quaternion = bool(deformflag & ARM_DEF_QUATERNION);
515 constexpr int grain_size = 32;
516 threading::parallel_for(vert_coords.index_range(), grain_size, [&](const IndexRange range) {
517 for (const int i : range) {
518 const MDeformVert *dvert = nullptr;
519 if (deform_params.use_dverts || deform_params.armature_def_nr >= 0) {
520 if (me_target) {
521 BLI_assert(i < me_target->verts_num);
522 if (dverts) {
523 dvert = &(*dverts)[i];
524 }
525 }
526 else if (dverts && i < dverts->size()) {
527 dvert = &(*dverts)[i];
528 }
529 }
530
531 armature_vert_task_with_dvert(deform_params, i, dvert, use_quaternion);
532 }
533 });
534}
535
542
543template<bool use_dvert>
544static void armature_vert_task_editmesh(void *__restrict userdata,
545 MempoolIterData *iter,
546 const TaskParallelTLS *__restrict /*tls*/)
547{
548 const ArmatureEditMeshUserdata &data = *static_cast<const ArmatureEditMeshUserdata *>(userdata);
549 BMVert *v = (BMVert *)iter;
550 const MDeformVert *dvert = use_dvert ? static_cast<const MDeformVert *>(
551 BM_ELEM_CD_GET_VOID_P(v, data.cd_dvert_offset)) :
552 nullptr;
554 data.deform_params, BM_elem_index_get(v), dvert, data.use_quaternion);
555}
556
557static void armature_deform_editmesh(const Object &ob_arm,
558 const Object &ob_target,
559 const ListBase *defbase,
560 const MutableSpan<float3> vert_coords,
561 const std::optional<MutableSpan<float3x3>> vert_deform_mats,
562 const int deformflag,
563 const std::optional<Span<float3>> vert_coords_prev,
564 blender::StringRefNull defgrp_name,
565 const BMEditMesh &em_target,
566 const int cd_dvert_offset)
567{
569 ob_target,
570 defbase,
571 vert_coords,
572 vert_coords_prev,
573 vert_deform_mats,
574 deformflag,
575 defgrp_name,
576 cd_dvert_offset >= 0);
577
579 data.use_quaternion = bool(deformflag & ARM_DEF_QUATERNION);
580 data.cd_dvert_offset = cd_dvert_offset;
581 data.deform_params = std::move(deform_params);
582
583 /* While this could cause an extra loop over mesh data, in most cases this will
584 * have already been properly set. */
586
587 TaskParallelSettings settings;
589
590 if (data.deform_params.use_dverts) {
592 em_target.bm->vpool, &data, armature_vert_task_editmesh<true>, &settings);
593 }
594 else {
596 em_target.bm->vpool, &data, armature_vert_task_editmesh<false>, &settings);
597 }
598}
599
600static bool verify_armature_deform_valid(const Object &ob_arm)
601{
602 /* Not supported in armature edit mode or without pose data. */
603 const bArmature *arm = static_cast<const bArmature *>(ob_arm.data);
604 if (arm->edbo || (ob_arm.pose == nullptr)) {
605 return false;
606 }
607 if ((ob_arm.pose->flag & POSE_RECALC) != 0) {
609 "Trying to evaluate influence of armature '%s' which needs Pose recalc!",
610 ob_arm.id.name);
612 }
613 return true;
614}
615
616} // namespace blender::bke
617
619 const Object &ob_arm,
620 const Object &ob_target,
621 const ListBase *defbase,
623 std::optional<blender::Span<blender::float3>> vert_coords_prev,
624 std::optional<blender::MutableSpan<blender::float3x3>> vert_deform_mats,
626 int deformflag,
627 blender::StringRefNull defgrp_name)
628{
629 using namespace blender;
630
632 return;
633 }
634
635 /* Vertex groups must be provided explicitly, cannot rely on object vertex groups since this is
636 * used for Grease Pencil layers as well. */
637 BLI_assert(dverts.size() == vert_coords.size());
638
640 ob_target,
641 defbase,
642 vert_coords,
643 vert_deform_mats,
644 deformflag,
645 vert_coords_prev,
646 defgrp_name,
647 dverts,
648 nullptr);
649}
650
652 const Object &ob_arm,
653 const Object &ob_target,
655 std::optional<blender::Span<blender::float3>> vert_coords_prev,
656 std::optional<blender::MutableSpan<blender::float3x3>> vert_deform_mats,
657 int deformflag,
658 blender::StringRefNull defgrp_name,
659 const Mesh *me_target)
660{
661 using namespace blender;
662
664 return;
665 }
666
667 /* Note armature modifier on legacy curves calls this, so vertex groups are not guaranteed to
668 * exist. */
669 const ID *id_target = static_cast<const ID *>(ob_target.data);
670 const ListBase *defbase = nullptr;
671 if (me_target) {
672 /* Use the vertex groups from the evaluated mesh that is being deformed. */
673 defbase = BKE_id_defgroup_list_get(&me_target->id);
674 }
675 else if (BKE_id_supports_vertex_groups(id_target)) {
676 /* Take the vertex groups from the original object data. */
677 defbase = BKE_id_defgroup_list_get(id_target);
678 }
679
681 if (ob_target.type == OB_MESH) {
682 if (me_target == nullptr) {
683 me_target = static_cast<const Mesh *>(ob_target.data);
684 }
685 dverts = me_target->deform_verts();
686 }
687 else if (ob_target.type == OB_LATTICE) {
688 const Lattice *lt = static_cast<const Lattice *>(ob_target.data);
689 if (lt->dvert != nullptr) {
690 dverts = blender::Span<MDeformVert>(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
691 }
692 }
693
694 std::optional<Span<MDeformVert>> dverts_opt;
695 if ((me_target && !me_target->deform_verts().is_empty()) || dverts.size() == vert_coords.size())
696 {
697 dverts_opt = dverts;
698 }
699
701 ob_target,
702 defbase,
703 vert_coords,
704 vert_deform_mats,
705 deformflag,
706 vert_coords_prev,
707 defgrp_name,
708 dverts_opt,
709 me_target);
710}
711
713 const Object &ob_arm,
714 const Object &ob_target,
716 std::optional<blender::Span<blender::float3>> vert_coords_prev,
717 std::optional<blender::MutableSpan<blender::float3x3>> vert_deform_mats,
718 int deformflag,
719 blender::StringRefNull defgrp_name,
720 const BMEditMesh &em_target)
721{
722 using namespace blender;
723
725 return;
726 }
727
728 const ListBase *defbase = BKE_id_defgroup_list_get(static_cast<const ID *>(ob_target.data));
729 const int cd_dvert_offset = CustomData_get_offset(&em_target.bm->vdata, CD_MDEFORMVERT);
731 ob_target,
732 defbase,
733 vert_coords,
734 vert_deform_mats,
735 deformflag,
736 vert_coords_prev,
737 defgrp_name,
738 em_target,
739 cd_dvert_offset);
740}
741
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)
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)
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:455
bool BKE_object_supports_vertex_groups(const Object *ob)
Definition deform.cc:463
int BKE_defgroup_name_index(const ListBase *defbase, blender::StringRef name)
Definition deform.cc:540
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:774
const ListBase * BKE_id_defgroup_list_get(const ID *id)
Definition deform.cc:470
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#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_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 void copy_v3_v3(float r[3], const float a[3])
struct MempoolIterData MempoolIterData
Definition BLI_task.h:200
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:188
@ 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.
void BKE_armature_deform_coords_with_mesh(const Object &ob_arm, const Object &ob_target, blender::MutableSpan< blender::float3 > vert_coords, std::optional< blender::Span< blender::float3 > > vert_coords_prev, std::optional< blender::MutableSpan< blender::float3x3 > > vert_deform_mats, int deformflag, blender::StringRefNull defgrp_name, const Mesh *me_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)
float distfactor_to_bone(const blender::float3 &position, const blender::float3 &head, const blender::float3 &tail, const float radius_head, const float radius_tail, const float falloff_distance)
void BKE_armature_deform_coords_with_editmesh(const Object &ob_arm, const Object &ob_target, blender::MutableSpan< blender::float3 > vert_coords, std::optional< blender::Span< blender::float3 > > vert_coords_prev, std::optional< blender::MutableSpan< blender::float3x3 > > vert_deform_mats, int deformflag, blender::StringRefNull defgrp_name, const BMEditMesh &em_target)
static float bone_envelope_falloff(const float distance_squared, const float closest_radius, const float falloff_distance)
#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 BMVert * v
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
constexpr bool contains(int64_t value) const
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
Span< NewT > constexpr cast() const
Definition BLI_span.hh:418
constexpr int64_t size() const
Definition BLI_span.hh:252
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define LOG(level)
Definition log.h:97
static void armature_vert_task_editmesh(void *__restrict userdata, MempoolIterData *iter, const TaskParallelTLS *__restrict)
static void armature_vert_task_with_mixer(const ArmatureDeformParams &params, const int i, const MDeformVert *dvert, MixerT &mixer)
static void armature_vert_task_with_dvert(const ArmatureDeformParams &deform_params, const int i, const MDeformVert *dvert, const bool use_quaternion)
static float dist_bone_deform(const bPoseChannel &pchan, const float3 &co, MixerT &mixer)
static void b_bone_deform(const bPoseChannel &pchan, const float3 &co, const float weight, MixerT &mixer)
static void armature_deform_editmesh(const Object &ob_arm, const Object &ob_target, const ListBase *defbase, const MutableSpan< float3 > vert_coords, const std::optional< MutableSpan< float3x3 > > vert_deform_mats, const int deformflag, const std::optional< Span< float3 > > vert_coords_prev, blender::StringRefNull defgrp_name, const BMEditMesh &em_target, const int cd_dvert_offset)
static float pchan_bone_deform(const bPoseChannel &pchan, const float weight, const float3 &co, MixerT &mixer)
static bool verify_armature_deform_valid(const Object &ob_arm)
static ArmatureDeformParams get_armature_deform_params(const Object &ob_arm, const Object &ob_target, const ListBase *defbase, MutableSpan< float3 > vert_coords, std::optional< Span< float3 > > vert_coords_prev, std::optional< MutableSpan< float3x3 > > vert_deform_mats, const int deformflag, blender::StringRefNull defgrp_name, const bool try_use_dverts)
static void armature_deform_coords(const Object &ob_arm, const Object &ob_target, const ListBase *defbase, const MutableSpan< float3 > vert_coords, const std::optional< MutableSpan< float3x3 > > vert_deform_mats, const int deformflag, const std::optional< Span< float3 > > vert_coords_prev, blender::StringRefNull defgrp_name, const std::optional< Span< MDeformVert > > dverts, const Mesh *me_target)
QuaternionBase< T > normalize_and_get_length(const QuaternionBase< T > &q, T &out_length)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
CartesianBasis invert(const CartesianBasis &basis)
T interpolate(const T &a, const T &b, const FactorT &t)
T square(const T &a)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
MatBase< float, 4, 4 > float4x4
ListBaseWrapperTemplate< const ListBase, const T > ConstListBaseWrapper
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
#define sqrtf
CustomData vdata
struct BLI_mempool * vpool
float arm_head[3]
float arm_tail[3]
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
struct MDeformVert * dvert
struct MDeformWeight * dw
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_Runtime runtime
ListBase chanbase
const c_style_mat & ptr() const
const MatView< T, ViewNumCol, ViewNumRow, NumCol, NumRow, SrcStartCol, SrcStartRow, Alignment > view() const
std::optional< Span< float3 > > vert_coords_prev
ConstListBaseWrapper< bPoseChannel > pose_channels
Array< bPoseChannel * > pose_channel_by_vertex_group
std::optional< MutableSpan< float3x3 > > vert_deform_mats
void accumulate_bbone(const bPoseChannel &pchan, const float3 &co, const float weight, const int index)
void accumulate(const bPoseChannel &pchan, const float3 &co, const float weight)
void finalize(const float3 &co, float total, float armature_weight, float3 &r_delta_co, float3x3 &r_deform_mat)
void accumulate_bbone(const bPoseChannel &pchan, const float3 &co, const float weight, const int index)
void finalize(const float3 &, float total, float armature_weight, float3 &r_delta_co, float3x3 &r_deform_mat)
void accumulate(const bPoseChannel &pchan, const float3 &co, const float weight)
i
Definition text_draw.cc:230
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)