Blender V5.0
armature_deform_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_listbase.h"
6#include "BLI_math_rotation.h"
7#include "BLI_math_vector.h"
8#include "BLI_string.h"
9
10#include "BKE_action.hh"
11#include "BKE_armature.hh"
12#include "BKE_curves.hh"
13#include "BKE_deform.hh"
14#include "BKE_editmesh.hh"
15#include "BKE_grease_pencil.hh"
16#include "BKE_idtype.hh"
17#include "BKE_lib_id.hh"
18#include "BKE_main.hh"
19#include "BKE_mesh.hh"
20#include "BKE_object.hh"
21#include "BKE_object_deform.h"
22
23#include "CLG_log.h"
24
25#include "DNA_armature_types.h"
26#include "DNA_curves_types.h"
28#include "DNA_meshdata_types.h"
29#include "DNA_object_types.h"
30
31#include "testing/testing.h"
32
33/* TODO Parameterized tests are not registered in `blender_test`.
34 * Possible reason: the cmake gtest_add_tests function may not be able to detect them reliably.
35 * https://cmake.org/cmake/help/latest/module/GoogleTest.html
36 * https://www.kitware.com/dynamic-google-test-discovery-in-cmake-3-10/
37 */
38// #define USE_PARAMETERIZED_TESTS
39
40namespace blender::bke::tests {
41
42/* Type of data that is being deformed.
43 * This distinction is needed to handle some inconsistent behaviors. */
50
52 /* Linear interpolation. */
54 /* Dual-quaternion method, aka. "Preserve Volume" (ARM_DEF_QUATERNION). */
56};
57
58enum class OutputValueTest {
59 /* Only position vector. */
61 /* Vector and deformation matrix ("full deform"). */
63};
64
65enum class WeightingTest {
66 /* Disabled (no deform). */
68 /* Falloff from closest envelope point. */
70 /* Vertex group weight. */
72 /* Use both envelopes and vertex groups. */
74};
75
76enum class MaskingTest {
77 /* Deform all vertices. */
79 /* Limit deformation to one vertex group. */
81};
82
83/* Defines the source of vertex groups and weights for mesh deformation. */
85 /* Read vertex groups and weights from the target object's mesh data. */
87 /* Use a separate mesh for defining vertex weights. */
89};
90
92 public:
94
95 /* Translation for bones.
96 * Rotation is omitted here for simplicity, the goal is to test all the code paths rather than
97 * the details of the bone transformation. Other tests are more suitable for comparing
98 * deformation results. */
100 {
101 return float3(5, 0, 1);
102 }
104 {
105 return float3(0, -2, 0);
106 }
107
108 /* This happens usually in BKE_pose_bone_done. Update here to avoid creating a full depsgraph. */
110 {
111 BKE_pchan_calc_mat(&pchan);
112 if (!(pchan.bone->flag & BONE_NO_DEFORM)) {
114 }
115 }
116
118 {
119 Object *ob = BKE_object_add_only_object(bmain, OB_ARMATURE, "Test Armature Object");
120 bArmature *arm = BKE_id_new<bArmature>(bmain, "Test Armature");
121 ob->data = arm;
122
123 Bone *bone1 = MEM_callocN<Bone>("Bone1");
124 STRNCPY(bone1->name, "Bone1");
125 copy_v3_v3(bone1->tail, float3(0, 0, 0));
126 copy_v3_v3(bone1->head, float3(0, 0, 1));
127 BLI_addtail(&arm->bonebase, bone1);
128 BKE_armature_where_is_bone(bone1, nullptr, false);
129 bone1->weight = 1.0f;
130 /* Bone envelope large enough to include all vertices.
131 * Falloff math isn't tested here, just have to make sure vertices are included. */
132 bone1->rad_head = 2.0f;
133 bone1->rad_tail = 2.0f;
134
135 Bone *bone2 = MEM_callocN<Bone>("Bone2");
136 STRNCPY(bone2->name, "Bone2");
137 copy_v3_v3(bone2->tail, float3(0, 0, 0));
138 copy_v3_v3(bone2->head, float3(0, 0, 1));
139 BLI_addtail(&arm->bonebase, bone2);
140 BKE_armature_where_is_bone(bone2, nullptr, false);
141 bone2->weight = 1.0f;
142 bone2->rad_head = 2.0f;
143 bone2->rad_tail = 2.0f;
144
145 BKE_pose_ensure(bmain, ob, arm, false);
146
147 bPoseChannel *pchan1 = BKE_pose_channel_find_name(ob->pose, "Bone1");
148 bPoseChannel *pchan2 = BKE_pose_channel_find_name(ob->pose, "Bone2");
149 copy_v3_v3(pchan1->loc, offset_bone1());
150 copy_v3_v3(pchan2->loc, offset_bone2());
151 update_pose_matrices(*pchan1);
152 update_pose_matrices(*pchan2);
153
154 return ob;
155 }
156
158 {
159 static Array<float3> data = {float3(-1, -1, -1),
160 float3(1, -1, -1),
161 float3(-1, 1, -1),
162 float3(1, 1, -1),
163 float3(-1, -1, 1),
164 float3(1, -1, 1),
165 float3(-1, 1, 1),
166 float3(1, 1, 1)};
167 return data;
168 }
169
174
176 {
177 static Array<float> data = {1, 1, 1, 1, 1, 1, 1, 1};
178 return data;
179 }
180
182 {
183 static Array<float> data = {0, 0, 0, 0, 1, 1, 1, 1};
184 return data;
185 }
186
188 {
189 static Array<int> data = {0, 2, 5, 8};
190 return data;
191 }
192
194 {
196 mesh->vert_positions_for_write().copy_from(vertex_positions());
197 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
198 for (const int i : dverts.index_range()) {
199 const float weight0 = vertex_weights_bone1()[i];
200 const float weight1 = vertex_weights_bone2()[i];
201
202 if (weight0 > 0.0f) {
203 BKE_defvert_add_index_notest(&dverts[i], 0, weight0);
204 }
205 if (weight1 > 0.0f) {
206 BKE_defvert_add_index_notest(&dverts[i], 1, weight1);
207 }
208 }
209 mesh->tag_positions_changed();
210
211 bDeformGroup *defgroup1 = MEM_callocN<bDeformGroup>(__func__);
212 bDeformGroup *defgroup2 = MEM_callocN<bDeformGroup>(__func__);
213 STRNCPY(defgroup1->name, "Bone1");
214 STRNCPY(defgroup2->name, "Bone2");
215 BLI_addtail(&mesh->vertex_group_names, defgroup1);
216 BLI_addtail(&mesh->vertex_group_names, defgroup2);
217
218 return mesh;
219 }
220
221 /* Creates a cube with all vertices in "Bone1" group and the top face in "Bone2" group. */
223 {
224 Object *ob = BKE_object_add_only_object(bmain, OB_MESH, "Test Mesh Object");
225 Mesh *mesh_in_main = BKE_mesh_add(bmain, "Test Mesh");
226 ob->data = mesh_in_main;
227
229 BKE_mesh_nomain_to_mesh(mesh, mesh_in_main, ob);
230 BLI_assert(!mesh_in_main->deform_verts().is_empty());
231
232 return ob;
233 }
234
235 /* Creates curves with a mix of vertices in "Bone1" and "Bone2" groups.
236 * Curves datablock does not support vertex groups at this point, these are ignored. */
238 {
239 Object *ob = BKE_object_add_only_object(bmain, OB_CURVES, "Test Curves Object");
240 Curves *curves_id = BKE_curves_add(bmain, "Test Curves");
241 ob->data = curves_id;
242 bke::CurvesGeometry &curves = curves_id->geometry.wrap();
243
244 curves.resize(vertex_positions().size(), 3);
245 curves.offsets_for_write().copy_from(curve_offsets());
246
247 curves.positions_for_write().copy_from(vertex_positions());
248 MutableSpan<MDeformVert> dverts = curves.deform_verts_for_write();
249 for (const int i : dverts.index_range()) {
250 const float weight0 = vertex_weights_bone1()[i];
251 const float weight1 = vertex_weights_bone2()[i];
252
253 if (weight0 > 0.0f) {
254 BKE_defvert_add_index_notest(&dverts[i], 0, weight0);
255 }
256 if (weight1 > 0.0f) {
257 BKE_defvert_add_index_notest(&dverts[i], 1, weight1);
258 }
259 }
260 curves.tag_topology_changed();
261 curves.tag_positions_changed();
262
263 return ob;
264 }
265
266 /* Creates grease pencil with a mix of vertices in "Bone1" and "Bone2" groups. */
268 {
269 Object *ob = BKE_object_add_only_object(bmain, OB_GREASE_PENCIL, "Test Grease Pencil Object");
270 GreasePencil *grease_pencil = BKE_grease_pencil_add(bmain, "Test Grease Pencil");
271 ob->data = grease_pencil;
272
273 bke::greasepencil::Layer &layer = grease_pencil->add_layer("Test");
274 greasepencil::Drawing &drawing = grease_pencil->insert_frame(layer, 1)->wrap();
275 bke::CurvesGeometry &curves = drawing.geometry.wrap();
276
277 curves.resize(vertex_positions().size(), 3);
278 curves.offsets_for_write().copy_from(curve_offsets());
279
280 curves.positions_for_write().copy_from(vertex_positions());
281 MutableSpan<MDeformVert> dverts = curves.deform_verts_for_write();
282 for (const int i : dverts.index_range()) {
283 const float weight0 = vertex_weights_bone1()[i];
284 const float weight1 = vertex_weights_bone2()[i];
285
286 if (weight0 > 0.0f) {
287 BKE_defvert_add_index_notest(&dverts[i], 0, weight0);
288 }
289 if (weight1 > 0.0f) {
290 BKE_defvert_add_index_notest(&dverts[i], 1, weight1);
291 }
292 }
293 curves.tag_topology_changed();
294 curves.tag_positions_changed();
295
296 BKE_object_defgroup_new(ob, "Bone1");
297 BKE_object_defgroup_new(ob, "Bone2");
298
299 return ob;
300 }
301
302 /* Select the expected positions result based on data type and parameters. */
304 const WeightingTest weighting,
305 const MaskingTest masking)
306 {
307 /* Both bones weighted equally. */
308 static Array<float3> data_envelope = {float3(1.5f, -2, -0.5f),
309 float3(3.5f, -2, -0.5f),
310 float3(1.5f, 0, -0.5f),
311 float3(3.5f, 0, -0.5f),
312 float3(1.5f, -2, 1.5f),
313 float3(3.5f, -2, 1.5f),
314 float3(1.5f, 0, 1.5f),
315 float3(3.5f, 0, 1.5f)};
316 static Array<float3> data_envelope_masked = {float3(-1, -1, -1),
317 float3(1, -1, -1),
318 float3(-1, 1, -1),
319 float3(1, 1, -1),
320 float3(1.5f, -2, 1.5f),
321 float3(3.5f, -2, 1.5f),
322 float3(1.5f, 0, 1.5f),
323 float3(3.5f, 0, 1.5f)};
324 /* Bottom verts deformed only by Bone1, top group deformed equally by both bones. */
325 static Array<float3> data_vgroups = {float3(4, -1, 0),
326 float3(6, -1, 0),
327 float3(4, 1, 0),
328 float3(6, 1, 0),
329 float3(1.5f, -2, 1.5f),
330 float3(3.5f, -2, 1.5f),
331 float3(1.5f, 0, 1.5f),
332 float3(3.5f, 0, 1.5f)};
333 static Array<float3> data_vgroups_masked = {float3(-1, -1, -1),
334 float3(1, -1, -1),
335 float3(-1, 1, -1),
336 float3(1, 1, -1),
337 float3(1.5f, -2, 1.5f),
338 float3(3.5f, -2, 1.5f),
339 float3(1.5f, 0, 1.5f),
340 float3(3.5f, 0, 1.5f)};
341
342 /* Curves data type does not support vertext groups. */
343 const bool vgroups_supported = ELEM(
345 /* Might be a bug: Mesh and GreasePencil allows masking even in envelope mode, but EditMesh
346 * does not! Curves does not have vgroups and therefore masking in the first place. */
347 const bool allow_masking_with_envelope = ELEM(
349 const bool vertex_groups_enabled = ELEM(
351 const bool masked = (masking == MaskingTest::VertexGroup) &&
352 ((vgroups_supported && vertex_groups_enabled) ||
353 allow_masking_with_envelope);
354
355 switch (weighting) {
357 return vertex_positions();
359 return masked ? data_envelope_masked : data_envelope;
361 if (vgroups_supported) {
362 return masked ? data_vgroups_masked : data_vgroups;
363 }
364 else {
365 return vertex_positions();
366 }
368 if (vgroups_supported) {
369 return masked ? data_vgroups_masked : data_vgroups;
370 }
371 else {
372 return masked ? data_envelope_masked : data_envelope;
373 }
374 }
376 return {};
377 }
378
380 {
381 static Array<float3x3> data_zero = identity_deform_mats();
390
391 switch (weighting) {
393 return data_zero;
397 return data;
398 }
399 return {};
400 }
401
402 static int get_deform_flag(const InterpolationTest interpolation, const WeightingTest weighting)
403 {
404 int deform_flag = 0;
405
406 switch (interpolation) {
408 /* Nothing to change, default mode. */
409 break;
411 deform_flag |= ARM_DEF_QUATERNION;
412 break;
413 }
414
415 switch (weighting) {
417 /* Nothing to do. */
418 break;
420 deform_flag |= ARM_DEF_ENVELOPE;
421 break;
423 deform_flag |= ARM_DEF_VGROUP;
424 break;
426 deform_flag |= ARM_DEF_ENVELOPE | ARM_DEF_VGROUP;
427 break;
428 }
429
430 return deform_flag;
431 }
432
433 static const char *get_defgrp_name(const MaskingTest masking)
434 {
435 switch (masking) {
436 case MaskingTest::All:
437 return "";
439 return "Bone2";
440 }
442 return "";
443 }
444
445 void mesh_test(const InterpolationTest interpolation,
447 const WeightingTest weighting,
448 const MaskingTest masking,
449 const VertexWeightSource dvert_source)
450 {
451 Object *ob_arm = this->create_test_armature_object();
452 Object *ob_target = this->create_test_mesh_object();
453 Mesh *mesh = static_cast<Mesh *>(ob_target->data);
454 /* Mesh deform function supports a separate Mesh data block for deform_groups and dverts. */
455 Mesh *mesh_target = (dvert_source == VertexWeightSource::SeparateMesh) ? create_test_mesh() :
456 nullptr;
457
458 MutableSpan<float3> vert_positions = mesh->vert_positions_for_write();
459
460 Array<float3x3> deform_mats;
461 std::optional<MutableSpan<float3x3>> deform_mats_opt;
463 deform_mats = identity_deform_mats();
464 deform_mats_opt = deform_mats;
465 }
466
467 const int deform_flag = get_deform_flag(interpolation, weighting);
468 const char *defgrp_name = get_defgrp_name(masking);
470 *ob_target,
471 vert_positions,
472 std::nullopt,
473 deform_mats_opt,
474 deform_flag,
475 defgrp_name,
476 mesh_target);
477
478 EXPECT_EQ_SPAN(expected_positions(TargetDataType::Mesh, weighting, masking),
479 vert_positions.as_span());
481 EXPECT_EQ_SPAN(expected_deform_mats(weighting), deform_mats.as_span());
482 }
483
484 if (mesh_target) {
485 /* Not in bmain. */
486 BKE_id_free(nullptr, mesh_target);
487 }
488 BKE_id_delete(bmain, ob_arm);
489 BKE_id_delete(bmain, ob_target);
490 }
491
492 void edit_mesh_test(const InterpolationTest interpolation,
494 const WeightingTest weighting,
495 const MaskingTest masking)
496 {
497 Object *ob_arm = this->create_test_armature_object();
498 Object *ob_target = this->create_test_mesh_object();
499 Mesh *mesh = static_cast<Mesh *>(ob_target->data);
500
501 BMeshCreateParams create_params{};
502 create_params.use_toolflags = true;
503 BMesh *bm = BKE_mesh_to_bmesh(mesh, 0, false, &create_params);
504 BMEditMesh *edit_mesh = BKE_editmesh_create(bm);
505 Array<float3> bm_verts_wrapper = BM_mesh_vert_coords_alloc(edit_mesh->bm);
506
507 Array<float3x3> deform_mats;
508 std::optional<MutableSpan<float3x3>> deform_mats_opt;
510 deform_mats = identity_deform_mats();
511 deform_mats_opt = deform_mats;
512 }
513
514 const int deform_flag = get_deform_flag(interpolation, weighting);
515 const char *defgrp_name = get_defgrp_name(masking);
517 *ob_target,
518 bm_verts_wrapper,
519 std::nullopt,
520 deform_mats_opt,
521 deform_flag,
522 defgrp_name,
523 *edit_mesh);
524
525 EXPECT_EQ_SPAN(expected_positions(TargetDataType::EditMesh, weighting, masking),
526 bm_verts_wrapper.as_span());
528 EXPECT_EQ_SPAN(expected_deform_mats(weighting), deform_mats.as_span());
529 }
530
531 BKE_editmesh_free_data(edit_mesh);
532 MEM_delete(edit_mesh);
533 BKE_id_delete(bmain, ob_arm);
534 BKE_id_delete(bmain, ob_target);
535 }
536
537 void curves_test(const InterpolationTest interpolation,
539 const WeightingTest weighting,
540 const MaskingTest masking)
541 {
542 Object *ob_arm = this->create_test_armature_object();
543 Object *ob_target = this->create_test_curves_object();
544 Curves *curves_id = static_cast<Curves *>(ob_target->data);
545 bke::CurvesGeometry &curves = curves_id->geometry.wrap();
546
547 Array<float3x3> deform_mats;
548 std::optional<MutableSpan<float3x3>> deform_mats_opt;
550 deform_mats = identity_deform_mats();
551 deform_mats_opt = deform_mats;
552 }
553
554 const int deform_flag = get_deform_flag(interpolation, weighting);
555 const char *defgrp_name = get_defgrp_name(masking);
557 *ob_target,
558 nullptr,
559 curves.positions_for_write(),
560 std::nullopt,
561 deform_mats_opt,
562 curves.deform_verts(),
563 deform_flag,
564 defgrp_name);
565
566 /* Note: Curves objects don't support vertex groups. */
567 EXPECT_EQ_SPAN(expected_positions(TargetDataType::Curves, weighting, masking),
568 curves.positions());
570 EXPECT_EQ_SPAN(expected_deform_mats(weighting), deform_mats.as_span());
571 }
572
573 BKE_id_delete(bmain, ob_arm);
574 BKE_id_delete(bmain, ob_target);
575 }
576
577 void grease_pencil_test(const InterpolationTest interpolation,
579 const WeightingTest weighting,
580 const MaskingTest masking)
581 {
582 Object *ob_arm = this->create_test_armature_object();
583 Object *ob_target = this->create_test_grease_pencil_object();
584 GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob_target->data);
585
586 BLI_assert(!grease_pencil->drawings().is_empty());
587 GreasePencilDrawingBase *drawing_base = grease_pencil->drawings()[0];
588 BLI_assert(drawing_base->type == GP_DRAWING);
589 greasepencil::Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base)->wrap();
590 bke::CurvesGeometry &curves = drawing.geometry.wrap();
591
592 Array<float3x3> deform_mats;
593 std::optional<MutableSpan<float3x3>> deform_mats_opt;
595 deform_mats = identity_deform_mats();
596 deform_mats_opt = deform_mats;
597 }
598
599 const int deform_flag = get_deform_flag(interpolation, weighting);
600 const char *defgrp_name = get_defgrp_name(masking);
602 *ob_target,
603 &grease_pencil->vertex_group_names,
604 curves.positions_for_write(),
605 std::nullopt,
606 deform_mats_opt,
607 curves.deform_verts(),
608 deform_flag,
609 defgrp_name);
610
611 EXPECT_EQ_SPAN(expected_positions(TargetDataType::GreasePencil, weighting, masking),
612 curves.positions());
614 EXPECT_EQ_SPAN(expected_deform_mats(weighting), deform_mats.as_span());
615 }
616
617 BKE_id_delete(bmain, ob_arm);
618 BKE_id_delete(bmain, ob_target);
619 }
620};
621
622#ifdef USE_PARAMETERIZED_TESTS
623
624using ArmatureDeformTestParams =
625 std::tuple<InterpolationTest, OutputValueTest, WeightingTest, MaskingTest, VertexWeightSource>;
626
627class ArmatureDeformParamTest : public ArmatureDeformTestBase,
628 public testing::TestWithParam<ArmatureDeformTestParams> {
629 public:
630 static void SetUpTestSuite()
631 {
632 CLG_init();
634 }
635
636 static void TearDownTestSuite()
637 {
638 CLG_exit();
639 }
640
641 void SetUp() override
642 {
643 bmain = BKE_main_new();
644 }
645
646 void TearDown() override
647 {
648 BKE_main_free(bmain);
649 }
650};
651
652TEST_P(ArmatureDeformParamTest, MeshDeformParameterized)
653{
654 const ArmatureDeformTestParams &params = this->GetParam();
655 InterpolationTest interpolation = std::get<0>(params);
656 OutputValueTest output = std::get<1>(params);
657 WeightingTest weighting = std::get<2>(params);
658 MaskingTest masking = std::get<3>(params);
659 VertexWeightSource dvert_source = std::get<4>(params);
660
661 mesh_test(interpolation, output, weighting, masking, dvert_source);
662}
663
664TEST_P(ArmatureDeformParamTest, EditMeshDeformParameterized)
665{
666 const ArmatureDeformTestParams &params = this->GetParam();
667 InterpolationTest interpolation = std::get<0>(params);
668 OutputValueTest output = std::get<1>(params);
669 WeightingTest weighting = std::get<2>(params);
670 MaskingTest masking = std::get<3>(params);
671
672 edit_mesh_test(interpolation, output, weighting, masking);
673}
674
675TEST_P(ArmatureDeformParamTest, CurvesDeformParameterized)
676{
677 const ArmatureDeformTestParams &params = this->GetParam();
678 InterpolationTest interpolation = std::get<0>(params);
679 OutputValueTest output = std::get<1>(params);
680 WeightingTest weighting = std::get<2>(params);
681 MaskingTest masking = std::get<3>(params);
682
683 curves_test(interpolation, output, weighting, masking);
684}
685
686TEST_P(ArmatureDeformParamTest, GreasePencilDeformParameterized)
687{
688 const ArmatureDeformTestParams &params = this->GetParam();
689 InterpolationTest interpolation = std::get<0>(params);
690 OutputValueTest output = std::get<1>(params);
691 WeightingTest weighting = std::get<2>(params);
692 MaskingTest masking = std::get<3>(params);
693
694 grease_pencil_test(interpolation, output, weighting, masking);
695}
696
698 AllArmatureDeformTests,
699 ArmatureDeformParamTest,
700 testing::Combine(
703 testing::Values(WeightingTest::None,
709 [](const testing::TestParamInfo<ArmatureDeformTestParams> &info) {
710 InterpolationTest interpolation = std::get<0>(info.param);
711 OutputValueTest output = std::get<1>(info.param);
712 WeightingTest weighting = std::get<2>(info.param);
713 MaskingTest masking = std::get<3>(info.param);
714 VertexWeightSource dvert_source = std::get<4>(info.param);
715
716 std::string name;
717 switch (interpolation) {
719 name += "linear";
720 break;
722 name += "dualquat";
723 break;
724 }
725 switch (output) {
727 name += "_pos";
728 break;
730 name += "_posdefmat";
731 break;
732 }
733 switch (weighting) {
735 name += "_disabled";
736 break;
738 name += "_envelope";
739 break;
741 name += "_vgroups";
742 break;
744 name += "_envelopevgroups";
745 break;
746 }
747 switch (masking) {
748 case MaskingTest::All:
749 break;
751 name += "_masked";
752 break;
753 }
754 switch (dvert_source) {
756 break;
758 name += "_dvertsource";
759 break;
760 }
761 return name;
762 });
763
764#else // USE_PARAMETERIZED_TESTS
765
766class ArmatureDeformTest : public ArmatureDeformTestBase, public testing::Test {
767 public:
768 static void SetUpTestSuite()
769 {
770 CLG_init();
772 }
773
774 static void TearDownTestSuite()
775 {
776 CLG_exit();
777 }
778
779 void SetUp() override
780 {
782 }
783
784 void TearDown() override
785 {
787 }
788};
789
812
831
850
869
870#endif
871
872} // namespace blender::bke::tests
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
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)
void BKE_pchan_calc_mat(bPoseChannel *pchan)
void BKE_armature_where_is_bone(Bone *bone, const Bone *bone_parent, bool use_recursion)
void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, bool do_id_user)
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)
struct Curves * BKE_curves_add(struct Main *bmain, const char *name)
Low-level operations for curves.
support for deformation groups and hooks.
bDeformGroup * BKE_object_defgroup_new(Object *ob, blender::StringRef name)
Definition deform.cc:48
void BKE_defvert_add_index_notest(MDeformVert *dv, int defgroup, float weight)
Definition deform.cc:856
void BKE_editmesh_free_data(BMEditMesh *em)
Definition editmesh.cc:132
BMEditMesh * BKE_editmesh_create(BMesh *bm)
Definition editmesh.cc:32
Low-level operations for grease pencil.
GreasePencil * BKE_grease_pencil_add(Main *bmain, const char *name)
void BKE_idtype_init()
Definition idtype.cc:121
void BKE_id_delete(Main *bmain, void *idv) ATTR_NONNULL()
void BKE_id_free(Main *bmain, void *idv)
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1514
Main * BKE_main_new()
Definition main.cc:89
void BKE_main_free(Main *bmain)
Definition main.cc:192
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
Mesh * BKE_mesh_add(Main *bmain, const char *name)
void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob, bool process_shape_keys=true)
BMesh * BKE_mesh_to_bmesh(Mesh *mesh, int active_shapekey, bool add_key_index, const BMeshCreateParams *params)
General operations, lookup, etc. for blender objects.
Object * BKE_object_add_only_object(Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
Functions for dealing with objects and deform verts, used by painting and tools.
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void mat4_to_dquat(DualQuat *dq, const float basemat[4][4], const float mat[4][4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define ELEM(...)
void CLG_exit()
Definition clog.cc:880
void CLG_init()
Definition clog.cc:873
@ ARM_DEF_VGROUP
@ ARM_DEF_QUATERNION
@ ARM_DEF_ENVELOPE
@ BONE_NO_DEFORM
Object is a sort of wrapper for general info.
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ OB_MESH
@ OB_CURVES
BMesh const char void * data
BMesh * bm
Array< float3 > BM_mesh_vert_coords_alloc(BMesh *bm)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
Span< T > as_span() const
Definition BLI_array.hh:243
constexpr Span< T > as_span() const
Definition BLI_span.hh:661
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
static Span< float3x3 > expected_deform_mats(const WeightingTest weighting)
void grease_pencil_test(const InterpolationTest interpolation, const OutputValueTest output, const WeightingTest weighting, const MaskingTest masking)
void edit_mesh_test(const InterpolationTest interpolation, const OutputValueTest output, const WeightingTest weighting, const MaskingTest masking)
static int get_deform_flag(const InterpolationTest interpolation, const WeightingTest weighting)
static const char * get_defgrp_name(const MaskingTest masking)
void mesh_test(const InterpolationTest interpolation, const OutputValueTest output, const WeightingTest weighting, const MaskingTest masking, const VertexWeightSource dvert_source)
static Span< float3 > expected_positions(const TargetDataType target_type, const WeightingTest weighting, const MaskingTest masking)
void curves_test(const InterpolationTest interpolation, const OutputValueTest output, const WeightingTest weighting, const MaskingTest masking)
static void update_pose_matrices(bPoseChannel &pchan)
#define output
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
TEST_F(ArmatureDeformTest, MeshDeform)
INSTANTIATE_TEST_SUITE_P(, VKRenderGraphTestRender, ::testing::Values(true, false))
TEST_P(VKRenderGraphTestRender, begin_clear_attachments_end_read_back)
VecBase< float, 3 > float3
float wrap(float value, float max, float min)
Definition node_math.h:103
const char * name
char name[64]
float tail[3]
float arm_mat[4][4]
float head[3]
CurvesGeometry geometry
struct bPose * pose
struct DualQuat deform_dual_quat
struct Bone * bone
float chan_mat[4][4]
struct bPoseChannel_Runtime runtime
i
Definition text_draw.cc:230