11#include <pxr/usd/usdGeom/primvarsAPI.h>
12#include <pxr/usd/usdSkel/animation.h>
13#include <pxr/usd/usdSkel/bindingAPI.h>
14#include <pxr/usd/usdSkel/blendShape.h>
15#include <pxr/usd/usdSkel/cache.h>
16#include <pxr/usd/usdSkel/skeletonQuery.h>
17#include <pxr/usd/usdSkel/utils.h>
59inline float max_mag_component(
const pxr::GfVec3d &vec)
61 return pxr::GfMax(pxr::GfAbs(vec[0]), pxr::GfAbs(vec[1]), pxr::GfAbs(vec[2]));
64void resize_fcurve(
FCurve *fcu,
uint bezt_count)
67 if (!fcu || bezt_count == fcu->
totvert) {
85void import_skeleton_curves(
Main *bmain,
87 const pxr::UsdSkelSkeletonQuery &skel_query,
93 if (!(bmain && arm_obj && skel_query)) {
101 const pxr::UsdSkelAnimQuery &anim_query = skel_query.GetAnimQuery();
108 std::vector<double> samples;
109 anim_query.GetJointTransformTimeSamples(&samples);
111 if (samples.empty()) {
115 const size_t num_samples = samples.size();
119 BKE_id_rename(*bmain, act->
id, anim_query.GetPrim().GetName().GetText());
125 const pxr::VtTokenArray joint_order = skel_query.GetJointOrder();
128 constexpr int curves_per_joint = 10;
131 curve_desc.
reserve(joint_order.size() * curves_per_joint);
134 for (
const pxr::TfToken &joint : joint_order) {
135 const std::string *name = joint_to_bone_map.
lookup_ptr(joint);
136 if (name ==
nullptr) {
144 std::string rna_path =
"pose.bones[\"" + *name +
"\"].location";
146 curve_desc.
append({path_desc, 0, {}, {}, *name});
147 curve_desc.
append({path_desc, 1, {}, {}, *name});
148 curve_desc.
append({path_desc, 2, {}, {}, *name});
151 rna_path =
"pose.bones[\"" + *name +
"\"].rotation_quaternion";
153 curve_desc.
append({path_desc, 0, {}, {}, *name});
154 curve_desc.
append({path_desc, 1, {}, {}, *name});
155 curve_desc.
append({path_desc, 2, {}, {}, *name});
156 curve_desc.
append({path_desc, 3, {}, {}, *name});
159 rna_path =
"pose.bones[\"" + *name +
"\"].scale";
161 curve_desc.
append({path_desc, 0, {}, {}, *name});
162 curve_desc.
append({path_desc, 1, {}, {}, *name});
163 curve_desc.
append({path_desc, 2, {}, {}, *name});
168 for (
FCurve *fcu : fcurves) {
169 if (fcu !=
nullptr) {
186 pxr::VtMatrix4dArray usd_bind_xforms;
187 if (!skel_query.GetJointWorldBindTransforms(&usd_bind_xforms)) {
190 "%s: Couldn't get world bind transforms for skeleton %s",
192 skel_query.GetSkeleton().GetPrim().GetPath().GetAsString().c_str());
196 if (usd_bind_xforms.size() != joint_order.size()) {
199 "%s: Number of bind transforms doesn't match the number of joints for skeleton %s",
201 skel_query.GetSkeleton().GetPrim().GetPath().GetAsString().c_str());
205 const pxr::UsdSkelTopology &skel_topology = skel_query.GetTopology();
207 const pxr::VtMatrix4dArray &bind_xforms = usd_bind_xforms.AsConst();
208 pxr::VtMatrix4dArray joint_local_bind_xforms(bind_xforms.size());
209 for (
int i = 0;
i < bind_xforms.size(); ++
i) {
210 const int parent_id = skel_topology.GetParent(
i);
212 if (parent_id >= 0) {
215 joint_local_bind_xforms[
i] = bind_xforms[
i] * bind_xforms[parent_id].GetInverse();
219 joint_local_bind_xforms[
i] = bind_xforms[
i];
226 for (
const double frame : samples) {
227 pxr::VtMatrix4dArray joint_local_xforms;
228 if (!skel_query.ComputeJointLocalTransforms(&joint_local_xforms, frame)) {
229 CLOG_WARN(&
LOG,
"Couldn't compute joint local transforms on frame %f", frame);
233 if (joint_local_xforms.size() != joint_order.size()) {
236 "Number of joint local transform entries %zu doesn't match the number of joints %zu",
237 joint_local_xforms.size(),
242 for (
int i = 0;
i < joint_local_xforms.size(); ++
i) {
243 const pxr::GfMatrix4d bone_xform = joint_local_xforms.AsConst()[
i] *
244 joint_local_bind_xforms[
i].GetInverse();
250 if (!pxr::UsdSkelDecomposeTransform(bone_xform, &t, &qrot, &s)) {
251 CLOG_WARN(&
LOG,
"Error decomposing matrix on frame %f", frame);
255 if (bezt_index > 0) {
260 if (pxr::GfDot(prev_rot[
i], qrot) < 0.0f) {
266 const float re = qrot.GetReal();
267 const pxr::GfVec3f &im = qrot.GetImaginary();
269 for (
int j = 0; j < 3; ++j) {
270 const int k = curves_per_joint *
i + j;
271 if (k >= fcurves.size()) {
272 CLOG_ERROR(&
LOG,
"Out of bounds translation curve index %d", k);
275 if (
FCurve *fcu = fcurves[k]) {
280 for (
int j = 0; j < 4; ++j) {
281 const int k = curves_per_joint *
i + j + 3;
282 if (k >= fcurves.size()) {
283 CLOG_ERROR(&
LOG,
"Out of bounds rotation curve index %d", k);
286 if (
FCurve *fcu = fcurves[k]) {
296 for (
int j = 0; j < 3; ++j) {
297 const int k = curves_per_joint *
i + j + 7;
298 if (k >= fcurves.size()) {
302 if (
FCurve *fcu = fcurves[k]) {
312 for (
FCurve *fcu : fcurves) {
313 if (fcu !=
nullptr) {
314 resize_fcurve(fcu, bezt_index);
321void add_skinned_mesh_bindings(
const pxr::UsdSkelSkeleton &skel,
322 const pxr::UsdPrim &mesh_prim,
323 pxr::UsdGeomXformCache &xf_cache)
325 pxr::UsdSkelBindingAPI skel_api = pxr::UsdSkelBindingAPI::Apply(mesh_prim);
329 "Couldn't apply UsdSkelBindingAPI to skinned mesh prim %s",
330 mesh_prim.GetPath().GetAsString().c_str());
335 pxr::SdfPath skel_path = skel.GetPath();
336 skel_api.CreateSkeletonRel().SetTargets(pxr::SdfPathVector({skel_path}));
339 if (pxr::UsdAttribute geom_bind_attr = skel_api.CreateGeomBindTransformAttr()) {
341 pxr::GfMatrix4d mesh_xf = xf_cache.GetLocalToWorldTransform(mesh_prim);
342 pxr::GfMatrix4d skel_xf = xf_cache.GetLocalToWorldTransform(skel.GetPrim());
343 pxr::GfMatrix4d bind_xf = mesh_xf * skel_xf.GetInverse();
344 geom_bind_attr.Set(bind_xf);
348 "Couldn't create geom bind transform attribute for skinned mesh %s",
349 mesh_prim.GetPath().GetAsString().c_str());
359 const pxr::UsdPrim &prim,
361 const bool import_anim)
363 if (!(mesh_obj && mesh_obj->
data && mesh_obj->
type ==
OB_MESH && prim)) {
367 if (prim.IsInstanceProxy()) {
373 pxr::UsdSkelBindingAPI skel_api(prim);
378 if (!skel_api.GetBlendShapeTargetsRel().HasAuthoredTargets()) {
383 pxr::SdfPathVector targets;
384 if (!skel_api.GetBlendShapeTargetsRel().GetTargets(&targets)) {
387 "%s: Couldn't get blendshape targets for prim %s",
389 prim.GetPath().GetAsString().c_str());
393 if (targets.empty()) {
397 if (!skel_api.GetBlendShapesAttr().HasAuthoredValue()) {
402 pxr::VtTokenArray usd_blendshapes;
403 if (!skel_api.GetBlendShapesAttr().Get(&usd_blendshapes)) {
407 if (usd_blendshapes.empty()) {
412 if (targets.size() != usd_blendshapes.size()) {
415 "%s: Number of blendshapes doesn't match number of blendshape targets for prim %s",
417 prim.GetPath().GetAsString().c_str());
421 pxr::UsdStageRefPtr stage = prim.GetStage();
426 "%s: Couldn't get stage for prim %s",
428 prim.GetPath().GetAsString().c_str());
449 for (
int i = 0;
i < targets.size(); ++
i) {
451 const pxr::SdfPath &path = targets[
i];
452 pxr::UsdSkelBlendShape blendshape(stage->GetPrimAtPath(path));
459 if (!blendshape.GetOffsetsAttr().HasAuthoredValue()) {
464 pxr::VtVec3fArray usd_offsets;
465 if (!blendshape.GetOffsetsAttr().Get(&usd_offsets)) {
468 "%s: Couldn't get offsets for blend shape %s",
470 path.GetAsString().c_str());
474 if (usd_offsets.empty()) {
477 "%s: No offsets for blend shape %s",
479 path.GetAsString().c_str());
483 shapekey_names.
add(blendshapes[
i]);
495 pxr::VtArray<int> point_indices;
496 if (blendshape.GetPointIndicesAttr().HasAuthoredValue()) {
497 blendshape.GetPointIndicesAttr().Get(&point_indices);
500 float *fp =
static_cast<float *
>(kb->
data);
503 if (point_indices.empty()) {
506 for (
int a = 0; a < kb->
totelem; ++a, fp += 3) {
507 if (a >= offsets.
size()) {
511 "%s: Number of offsets greater than number of mesh vertices for blend shape %s",
513 path.GetAsString().c_str());
523 for (
const int point : point_indices.AsConst()) {
524 if (point < 0 || point > kb->
totelem) {
526 "Out of bounds point index %d for blendshape %s",
528 path.GetAsString().c_str());
532 if (a >= offsets.
size()) {
536 "%s: Number of offsets greater than number of mesh vertices for blend shape %s",
538 path.GetAsString().c_str());
554 pxr::UsdSkelSkeleton skel_prim = skel_api.GetInheritedSkeleton();
560 skel_api = pxr::UsdSkelBindingAPI(skel_prim.GetPrim());
562 pxr::UsdPrim anim_prim = skel_api.GetInheritedAnimationSource();
567 skel_api.GetAnimationSource(&anim_prim);
574 pxr::UsdSkelAnimation skel_anim(anim_prim);
581 if (!skel_anim.GetBlendShapesAttr().HasAuthoredValue()) {
585 pxr::UsdAttribute weights_attr = skel_anim.GetBlendShapeWeightsAttr();
587 if (!(weights_attr && weights_attr.HasAuthoredValue())) {
592 std::vector<double> times;
593 if (!weights_attr.GetTimeSamples(×)) {
602 if (!skel_anim.GetBlendShapesAttr().Get(&usd_blendshapes)) {
606 if (usd_blendshapes.empty()) {
616 curves.
reserve(usd_blendshapes.size());
618 for (
auto blendshape_name : usd_blendshapes.AsConst()) {
619 if (!shapekey_names.
contains(blendshape_name)) {
627 std::string rna_path =
"key_blocks[\"" + blendshape_name.GetString() +
"\"].value";
634 for (
double frame : times) {
635 pxr::VtFloatArray usd_weights;
636 if (!weights_attr.Get(&usd_weights, frame)) {
637 CLOG_WARN(&
LOG,
"Couldn't get blendshape weights for time %f", frame);
641 if (usd_weights.size() != curves.
size()) {
644 "Number of weight samples doesn't match number of shapekey curve entries for frame %f",
650 for (
int wi = 0; wi < weights.
size(); ++wi) {
651 if (curves[wi] !=
nullptr) {
660 auto recalc_handles = [bezt_index](
FCurve *fcu) {
661 resize_fcurve(fcu, bezt_index);
664 std::for_each(curves.
begin(), curves.
end(), recalc_handles);
670 const pxr::VtArray<pxr::GfMatrix4d> &bind_xforms,
671 const pxr::VtTokenArray &joint_order,
673 const pxr::UsdSkelTopology &skel_topology,
674 const pxr::UsdSkelSkeletonQuery &skel_query)
676 if (!skel_query.HasRestPose()) {
680 pxr::VtArray<pxr::GfMatrix4d> rest_xforms;
681 if (skel_query.ComputeJointLocalTransforms(&rest_xforms, pxr::UsdTimeCode::Default(),
true)) {
685 for (
const pxr::TfToken &joint : joint_order) {
686 const std::string *name = joint_to_bone_map.
lookup_ptr(joint);
687 if (name ==
nullptr) {
694 pxr::GfMatrix4d xf = rest_xforms.AsConst()[
i];
695 pxr::GfMatrix4d bind_xf = bind_xforms[
i];
697 const int parent_id = skel_topology.GetParent(
i);
698 if (parent_id >= 0) {
699 bind_xf = bind_xf * bind_xforms[parent_id].GetInverse();
702 xf = xf * bind_xf.GetInverse();
704 pxr::GfMatrix4f mat(xf);
714 const pxr::UsdSkelSkeleton &skel,
716 const bool import_anim)
722 pxr::UsdSkelCache skel_cache;
723 pxr::UsdSkelSkeletonQuery skel_query = skel_cache.GetSkelQuery(skel);
725 if (!skel_query.IsValid()) {
728 "%s: Couldn't query skeleton %s",
730 skel.GetPath().GetAsString().c_str());
734 const pxr::UsdSkelTopology &skel_topology = skel_query.GetTopology();
735 const pxr::VtTokenArray joint_order = skel_query.GetJointOrder();
737 if (joint_order.size() != skel_topology.size()) {
740 "%s: Topology and joint order size mismatch for skeleton %s",
742 skel.GetPath().GetAsString().c_str());
748 unique_joint_paths.
reserve(joint_order.size());
749 const bool all_valid_paths = std::all_of(
750 joint_order.cbegin(), joint_order.cend(), [&unique_joint_paths](
const pxr::TfToken &val) {
751 const bool is_valid = pxr::SdfPath::IsValidPathString(val);
752 return is_valid && unique_joint_paths.add(val);
754 if (!all_valid_paths) {
757 "%s: USD joint order array contains invalid or duplicated paths for skeleton %s",
759 skel.GetPath().GetAsString().c_str());
777 for (
const pxr::TfToken &joint : joint_order) {
778 pxr::SdfPath bone_path(joint);
779 const std::string &bone_name = bone_path.GetName();
784 "%s: Couldn't add bone for joint %s",
786 joint.GetString().c_str());
787 edit_bones.
append(
nullptr);
790 joint_to_bone_map.
add(joint, bone->
name);
795 const size_t num_joints = skel_topology.GetNumJoints();
796 if (edit_bones.
size() != num_joints) {
799 "%s: Mismatch in bone and joint counts for skeleton %s",
801 skel.GetPath().GetAsString().c_str());
806 pxr::VtMatrix4dArray bind_xforms;
807 if (!skel_query.GetJointWorldBindTransforms(&bind_xforms)) {
810 "%s: Couldn't get world bind transforms for skeleton %s",
812 skel.GetPath().GetAsString().c_str());
816 if (bind_xforms.size() != num_joints) {
819 "%s: Mismatch in bind xforms and joint counts for skeleton %s",
821 skel.GetPath().GetAsString().c_str());
835 bool negative_determinant =
false;
838 for (
size_t i = 0;
i < num_joints; ++
i) {
845 pxr::GfMatrix4f mat(bind_xforms.AsConst()[
i]);
850 pxr::GfVec3f head(0.0f, 0.0f, 0.0f);
851 pxr::GfVec3f tail(0.0f, 1.0f, 0.0f);
858 if (mat.GetDeterminant() < 0.0) {
859 negative_determinant =
true;
863 bool valid_skeleton =
true;
864 if (negative_determinant) {
865 valid_skeleton =
false;
869 "USD Skeleton Import: bone matrices with negative determinants detected in prim %s. "
870 "Such matrices may indicate negative scales, possibly due to mirroring operations, "
871 "and can't currently be converted to Blender's bone representation. "
872 "The skeletal animation won't be imported",
873 skel.GetPath().GetAsString().c_str());
886 for (
size_t i = 0;
i < num_joints; ++
i) {
887 const int parent_idx = skel_topology.GetParent(
i);
888 if (parent_idx < 0) {
891 if (parent_idx >= edit_bones.
size()) {
893 "Out of bounds parent index for bone %s on skeleton %s",
894 pxr::SdfPath(joint_order[
i]).GetAsString().c_str(),
895 skel.GetPath().GetAsString().c_str());
899 child_bones[parent_idx].
append(
i);
900 if (edit_bones[
i] && edit_bones[parent_idx]) {
901 edit_bones[
i]->parent = edit_bones[parent_idx];
906 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(skel.GetPrim());
908 if (pv_lengths.HasValue()) {
909 pxr::VtArray<float> blender_bone_lengths;
910 pv_lengths.ComputeFlattened(&blender_bone_lengths);
912 Span<float> bone_lengths =
Span(blender_bone_lengths.cdata(), blender_bone_lengths.size());
913 for (
size_t i = 0;
i < num_joints; ++
i) {
915 pxr::GfVec3f head(bone->
head);
916 pxr::GfVec3f tail(bone->
tail);
918 tail = head + (tail - head).GetNormalized() * bone_lengths[
i];
923 float avg_len_scale = 0;
924 for (
size_t i = 0;
i < num_joints; ++
i) {
930 if (child_bones[
i].is_empty()) {
939 pxr::GfVec3f avg_child_head(0);
940 for (
int j : child_bones[
i]) {
945 pxr::GfVec3f child_head(child->
head);
946 avg_child_head += child_head;
949 avg_child_head /= child_bones[
i].
size();
951 pxr::GfVec3f parent_head(parent->
head);
952 pxr::GfVec3f parent_tail(parent->
tail);
954 const float new_len = (avg_child_head - parent_head).GetLength();
957 if (new_len > .00001 * max_mag_component(parent_head)) {
958 parent_tail = parent_head + (parent_tail - parent_head).GetNormalized() * new_len;
960 avg_len_scale += new_len;
965 avg_len_scale /= num_joints;
967 for (
size_t i = 0;
i < num_joints; ++
i) {
968 if (!child_bones[
i].is_empty()) {
976 pxr::GfVec3f head(bone->
head);
979 if (avg_len_scale > .00001 * max_mag_component(head)) {
980 pxr::GfVec3f tail(bone->
tail);
981 tail = head + (tail - head).GetNormalized() * avg_len_scale;
992 bmain, arm_obj, arm, bind_xforms, joint_order, joint_to_bone_map, skel_topology, skel_query);
994 if (import_anim && valid_skeleton) {
995 import_skeleton_curves(bmain, arm_obj, skel_query, joint_to_bone_map,
reports);
1001 if (!(mesh_obj && mesh_obj->
type ==
OB_MESH && prim)) {
1005 if (prim.IsInstanceProxy()) {
1011 pxr::UsdSkelBindingAPI skel_api(prim);
1013 pxr::UsdSkelSkeleton skel = skel_api.GetInheritedSkeleton();
1021 pxr::VtArray<pxr::TfToken> joints;
1023 if (skel_api.GetJointsAttr().HasAuthoredValue()) {
1024 skel_api.GetJointsAttr().Get(&joints);
1026 else if (skel.GetJointsAttr().HasAuthoredValue()) {
1027 skel.GetJointsAttr().Get(&joints);
1030 if (joints.empty()) {
1035 pxr::UsdGeomPrimvar joint_indices_primvar = skel_api.GetJointIndicesPrimvar();
1036 if (!(joint_indices_primvar && joint_indices_primvar.HasAuthoredValue())) {
1041 pxr::UsdGeomPrimvar joint_weights_primvar = skel_api.GetJointWeightsPrimvar();
1042 if (!(joint_weights_primvar && joint_weights_primvar.HasAuthoredValue())) {
1048 int joint_indices_elem_size = joint_indices_primvar.GetElementSize();
1049 int joint_weights_elem_size = joint_weights_primvar.GetElementSize();
1052 if (joint_indices_elem_size != joint_weights_elem_size) {
1055 "%s: Joint weights and joint indices element size mismatch for prim %s",
1057 prim.GetPath().GetAsString().c_str());
1062 pxr::VtIntArray joint_indices;
1063 joint_indices_primvar.ComputeFlattened(&joint_indices);
1065 pxr::VtFloatArray joint_weights;
1066 joint_weights_primvar.ComputeFlattened(&joint_weights);
1068 if (joint_indices.empty() || joint_weights.empty()) {
1072 if (joint_indices.size() != joint_weights.size()) {
1075 "%s: Joint weights and joint indices size mismatch for prim %s",
1077 prim.GetPath().GetAsString().c_str());
1083 const pxr::TfToken
interp = joint_weights_primvar.GetInterpolation();
1086 if (!
ELEM(
interp, pxr::UsdGeomTokens->vertex, pxr::UsdGeomTokens->constant)) {
1089 "%s: Unexpected joint weights interpolation type %s for prim %s",
1091 interp.GetString().c_str(),
1092 prim.GetPath().GetAsString().c_str());
1097 if (
interp == pxr::UsdGeomTokens->vertex &&
1098 joint_weights.size() != mesh->
verts_num * joint_weights_elem_size)
1102 "%s: Joint weights of unexpected size for vertex interpolation for prim %s",
1104 prim.GetPath().GetAsString().c_str());
1108 if (
interp == pxr::UsdGeomTokens->constant && joint_weights.size() != joint_weights_elem_size) {
1111 "%s: Joint weights of unexpected size for constant interpolation for prim %s",
1113 prim.GetPath().GetAsString().c_str());
1119 for (
int index : joint_indices.AsConst()) {
1120 if (std::find(used_indices.
begin(), used_indices.
end(), index) == used_indices.
end()) {
1122 if (index < 0 || index >= joints.size()) {
1123 CLOG_ERROR(&
LOG,
"Out of bound joint index %d for mesh %s", index, mesh_obj->
id.
name + 2);
1126 used_indices.
append(index);
1137 "%s: Error creating deform group data for mesh %s",
1153 for (
int idx : used_indices) {
1154 std::string joint_name = pxr::SdfPath(joints.AsConst()[idx]).GetName();
1157 joint_def_grps[idx] = def_grp;
1166 if (
interp == pxr::UsdGeomTokens->vertex) {
1167 offset =
i * joint_weights_elem_size;
1169 for (
int j = 0; j < joint_weights_elem_size; ++j) {
1170 const int k = offset + j;
1171 const float w = joint_weights.AsConst()[k];
1176 const int joint_idx = joint_indices.AsConst()[k];
1177 if (
bDeformGroup *def_grp = joint_def_grps[joint_idx]) {
1193 pxr::UsdGeomXformCache xf_cache(1.0);
1195 stage, armature_export_map, skinned_mesh_export_map, xf_cache,
depsgraph);
1202 pxr::UsdGeomXformCache &xf_cache,
1206 for (
const auto &item : skinned_mesh_export_map.
items()) {
1207 const Object *mesh_obj = item.key;
1208 const pxr::SdfPath &mesh_path = item.value;
1211 pxr::UsdPrim mesh_prim = stage->GetPrimAtPath(mesh_path);
1214 "Invalid export map prim path %s for mesh object %s",
1215 mesh_path.GetAsString().c_str(),
1223 CLOG_WARN(&
LOG,
"Invalid armature modifier for skinned mesh %s", mesh_obj->
id.
name + 2);
1227 const pxr::SdfPath *path = armature_export_map.
lookup_ptr(arm_obj);
1229 CLOG_WARN(&
LOG,
"No export map entry for armature object %s", mesh_obj->
id.
name + 2);
1233 pxr::UsdPrim skel_prim = stage->GetPrimAtPath(*path);
1234 pxr::UsdSkelSkeleton skel(skel_prim);
1236 CLOG_WARN(&
LOG,
"Invalid USD skeleton for armature object %s", arm_obj->
id.
name + 2);
1240 add_skinned_mesh_bindings(skel, mesh_prim, xf_cache);
1254 for (
const auto &item : shape_key_mesh_export_map.
items()) {
1255 const Object *mesh_obj = item.key;
1256 const pxr::SdfPath &mesh_path = item.value;
1259 pxr::UsdPrim mesh_prim = stage->GetPrimAtPath(mesh_path);
1262 "Invalid export map prim path %s for mesh object %s",
1263 mesh_path.GetAsString().c_str(),
1269 mesh_prims.
append(mesh_prim);
1271 pxr::UsdSkelBindingAPI skel_api = pxr::UsdSkelBindingAPI::Apply(mesh_prim);
1275 "Couldn't apply UsdSkelBindingAPI to prim %s",
1276 mesh_prim.GetPath().GetAsString().c_str());
1280 pxr::UsdSkelSkeleton skel;
1281 if (skel_api.GetSkeleton(&skel)) {
1283 pxr::SdfPathSet *mesh_paths = skel_to_mesh.
lookup_ptr(skel.GetPath());
1285 skel_to_mesh.
add_new(skel.GetPath(), pxr::SdfPathSet());
1286 mesh_paths = skel_to_mesh.
lookup_ptr(skel.GetPath());
1289 mesh_paths->insert(mesh_prim.GetPath());
1302 for (
const auto &item : skel_to_mesh.
items()) {
1307 for (
const pxr::UsdPrim &prim : mesh_prims) {
1313 const pxr::UsdSkelBindingAPI &skel_api,
1329 for (
int i = 0;
i < bone_names.
size(); ++
i) {
1330 if (bone_names[
i] == def->name) {
1336 joint_index.
append(bone_idx);
1345 int max_totweight = 1;
1348 max_totweight = std::max(vert.
totweight, max_totweight);
1353 const int element_size = max_totweight;
1356 pxr::VtArray<int> joint_indices(num_points * element_size, 0);
1357 pxr::VtArray<float> joint_weights(num_points * element_size, 0.0f);
1365 for (
int j = 0; j < element_size; ++j, ++offset) {
1367 if (offset >= joint_indices.size()) {
1376 int def_nr = int(vert.
dw[j].
def_nr);
1378 if (def_nr >= joint_index.
size()) {
1383 if (joint_index[def_nr] == -1) {
1387 joint_indices[offset] = joint_index[def_nr];
1388 joint_weights[offset] = vert.
dw[j].
weight;
1392 pxr::UsdSkelNormalizeWeights(joint_weights, element_size);
1394 skel_api.CreateJointIndicesPrimvar(
false, element_size).GetAttr().Set(joint_indices);
1395 skel_api.CreateJointWeightsPrimvar(
false, element_size).GetAttr().Set(joint_weights);
Functions and classes to work with Actions.
Functions to work with AnimData.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
void BKE_pchan_apply_mat4(bPoseChannel *pchan, const float mat[4][4], bool use_compat)
void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, bool do_id_user)
void BKE_fcurve_handles_recalc(FCurve *fcu)
void BKE_fcurve_bezt_resize(FCurve *fcu, int new_totvert)
Key * BKE_key_add(Main *bmain, ID *id)
KeyBlock * BKE_keyblock_add(Key *key, const char *name)
void BKE_keyblock_convert_from_mesh(const Mesh *mesh, const Key *key, KeyBlock *kb)
IDNewNameResult BKE_id_rename(Main &bmain, ID &id, blender::StringRefNull name, const IDNewNameMode mode=IDNewNameMode::RenameExistingNever)
ModifierData * BKE_modifiers_findby_type(const Object *ob, ModifierType type)
void BKE_modifiers_persistent_uid_init(const Object &object, ModifierData &md)
ModifierData * BKE_modifier_new(int type)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert_unreachable()
#define BLI_assert_msg(a, msg)
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
#define CLOG_ERROR(clg_ref,...)
#define CLOG_WARN(clg_ref,...)
EditBone * ED_armature_ebone_add(bArmature *arm, const char *name)
void ED_armature_edit_free(bArmature *arm)
void ED_armature_from_edit(Main *bmain, bArmature *arm)
void ED_armature_ebone_from_mat4(EditBone *ebone, const float mat[4][4])
void ED_armature_to_edit(bArmature *arm)
BMesh const char void * data
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
StringRefNull copy_string(StringRef str)
const Value * lookup_ptr(const Key &key) const
bool add(const Key &key, const Value &value)
void add_new(const Key &key, const Value &value)
ItemIterator items() const &
void reserve(const int64_t n)
bool contains(const Key &key) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
void append(const T &value)
void reserve(const int64_t min_capacity)
Span< T > as_span() const
void append_n_times(const T &value, const int64_t n)
Vector< FCurve * > fcurve_create_many(Main *bmain, Span< FCurveDescriptor > fcurve_descriptors)
ccl_device_inline float interp(const float a, const float b, const float t)
bAction * id_action_ensure(Main *bmain, ID *id)
Channelbag & action_channelbag_ensure(bAction &dna_action, ID &animated_id)
void vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode)
Map< const Object *, pxr::SdfPath > ObjExportMap
void shape_key_export_chaser(pxr::UsdStageRefPtr stage, const ObjExportMap &shape_key_mesh_export_map)
void import_mesh_skel_bindings(Object *mesh_obj, const pxr::UsdPrim &prim, ReportList *reports)
void set_fcurve_sample(FCurve *fcu, int64_t sample_index, const float frame, const float value)
FCurve * create_fcurve(blender::animrig::Channelbag &channelbag, const blender::animrig::FCurveDescriptor &fcurve_descriptor, const int sample_count)
void skel_export_chaser(pxr::UsdStageRefPtr stage, const ObjExportMap &armature_export_map, const ObjExportMap &skinned_mesh_export_map, const ObjExportMap &shape_key_mesh_export_map, const Depsgraph *depsgraph)
void export_deform_verts(const Mesh *mesh, const pxr::UsdSkelBindingAPI &skel_api, const Span< StringRef > bone_names)
void remap_blend_shape_anim(pxr::UsdStageRefPtr stage, const pxr::SdfPath &skel_path, const pxr::SdfPathSet &mesh_paths)
const pxr::TfToken BlenderBoneLengths("blender:bone_lengths", pxr::TfToken::Immortal)
void import_blendshapes(Main *bmain, Object *mesh_obj, const pxr::UsdPrim &prim, ReportList *reports, const bool import_anim)
void skinned_mesh_export_chaser(pxr::UsdStageRefPtr stage, const ObjExportMap &armature_export_map, const ObjExportMap &skinned_mesh_export_map, pxr::UsdGeomXformCache &xf_cache, const Depsgraph *depsgraph)
void ensure_blend_shape_skeleton(pxr::UsdStageRefPtr stage, pxr::UsdPrim &mesh_prim)
pxr::TfToken TempBlendShapeWeightsPrimvarName
void import_skeleton(Main *bmain, Object *arm_obj, const pxr::UsdSkelSkeleton &skel, ReportList *reports, const bool import_anim)
const Object * get_armature_modifier_obj(const Object &obj, const Depsgraph *depsgraph)
static void set_rest_pose(Main *bmain, Object *arm_obj, bArmature *arm, const pxr::VtArray< pxr::GfMatrix4d > &bind_xforms, const pxr::VtTokenArray &joint_order, const blender::Map< pxr::TfToken, std::string > &joint_to_bone_map, const pxr::UsdSkelTopology &skel_topology, const pxr::UsdSkelSkeletonQuery &skel_query)
ListBase vertex_group_names