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>
60inline float max_mag_component(
const pxr::GfVec3d &vec)
62 return pxr::GfMax(pxr::GfAbs(vec[0]), pxr::GfAbs(vec[1]), pxr::GfAbs(vec[2]));
65void resize_fcurve(
FCurve *fcu,
uint bezt_count)
68 if (!fcu || bezt_count == fcu->
totvert) {
86void import_skeleton_curves(
Main *bmain,
88 const pxr::UsdSkelSkeletonQuery &skel_query,
94 if (!(bmain && arm_obj && skel_query)) {
102 const pxr::UsdSkelAnimQuery &anim_query = skel_query.GetAnimQuery();
109 std::vector<double> samples;
110 anim_query.GetJointTransformTimeSamples(&samples);
112 if (samples.empty()) {
116 const size_t num_samples = samples.size();
120 BKE_id_rename(*bmain, act->
id, anim_query.GetPrim().GetName().GetText());
126 const pxr::VtTokenArray joint_order = skel_query.GetJointOrder();
129 constexpr int curves_per_joint = 10;
132 curve_desc.
reserve(joint_order.size() * curves_per_joint);
135 for (
const pxr::TfToken &joint : joint_order) {
137 if (
name ==
nullptr) {
145 std::string rna_path =
"pose.bones[\"" + *
name +
"\"].location";
147 curve_desc.
append({path_desc, 0, {}, {}, *
name});
148 curve_desc.
append({path_desc, 1, {}, {}, *
name});
149 curve_desc.
append({path_desc, 2, {}, {}, *
name});
152 rna_path =
"pose.bones[\"" + *
name +
"\"].rotation_quaternion";
154 curve_desc.
append({path_desc, 0, {}, {}, *
name});
155 curve_desc.
append({path_desc, 1, {}, {}, *
name});
156 curve_desc.
append({path_desc, 2, {}, {}, *
name});
157 curve_desc.
append({path_desc, 3, {}, {}, *
name});
160 rna_path =
"pose.bones[\"" + *
name +
"\"].scale";
162 curve_desc.
append({path_desc, 0, {}, {}, *
name});
163 curve_desc.
append({path_desc, 1, {}, {}, *
name});
164 curve_desc.
append({path_desc, 2, {}, {}, *
name});
169 for (
FCurve *fcu : fcurves) {
170 if (fcu !=
nullptr) {
187 pxr::VtMatrix4dArray usd_bind_xforms;
188 if (!skel_query.GetJointWorldBindTransforms(&usd_bind_xforms)) {
191 "%s: Couldn't get world bind transforms for skeleton %s",
193 skel_query.GetSkeleton().GetPrim().GetPath().GetAsString().c_str());
197 if (usd_bind_xforms.size() != joint_order.size()) {
201 "%s: Number of bind transforms does not match the number of joints for skeleton %s",
203 skel_query.GetSkeleton().GetPrim().GetPath().GetAsString().c_str());
207 const pxr::UsdSkelTopology &skel_topology = skel_query.GetTopology();
209 const pxr::VtMatrix4dArray &bind_xforms = usd_bind_xforms.AsConst();
210 pxr::VtMatrix4dArray joint_local_bind_xforms(bind_xforms.size());
211 for (
int i = 0;
i < bind_xforms.size(); ++
i) {
212 const int parent_id = skel_topology.GetParent(
i);
214 if (parent_id >= 0) {
217 joint_local_bind_xforms[
i] = bind_xforms[
i] * bind_xforms[parent_id].GetInverse();
221 joint_local_bind_xforms[
i] = bind_xforms[
i];
228 for (
const double frame : samples) {
229 pxr::VtMatrix4dArray joint_local_xforms;
230 if (!skel_query.ComputeJointLocalTransforms(&joint_local_xforms, frame)) {
231 CLOG_WARN(&
LOG,
"Couldn't compute joint local transforms on frame %f", frame);
235 if (joint_local_xforms.size() != joint_order.size()) {
238 "Number of joint local transform entries %zu does not match the number of joints %zu",
239 joint_local_xforms.size(),
244 for (
int i = 0;
i < joint_local_xforms.size(); ++
i) {
245 const pxr::GfMatrix4d bone_xform = joint_local_xforms.AsConst()[
i] *
246 joint_local_bind_xforms[
i].GetInverse();
252 if (!pxr::UsdSkelDecomposeTransform(bone_xform, &t, &qrot, &s)) {
253 CLOG_WARN(&
LOG,
"Error decomposing matrix on frame %f", frame);
257 if (bezt_index > 0) {
262 if (pxr::GfDot(prev_rot[
i], qrot) < 0.0f) {
268 const float re = qrot.GetReal();
269 const pxr::GfVec3f &im = qrot.GetImaginary();
271 for (
int j = 0; j < 3; ++j) {
272 const int k = curves_per_joint *
i + j;
273 if (k >= fcurves.size()) {
274 CLOG_ERROR(&
LOG,
"Out of bounds translation curve index %d", k);
277 if (
FCurve *fcu = fcurves[k]) {
282 for (
int j = 0; j < 4; ++j) {
283 const int k = curves_per_joint *
i + j + 3;
284 if (k >= fcurves.size()) {
285 CLOG_ERROR(&
LOG,
"Out of bounds rotation curve index %d", k);
288 if (
FCurve *fcu = fcurves[k]) {
298 for (
int j = 0; j < 3; ++j) {
299 const int k = curves_per_joint *
i + j + 7;
300 if (k >= fcurves.size()) {
304 if (
FCurve *fcu = fcurves[k]) {
314 for (
FCurve *fcu : fcurves) {
315 if (fcu !=
nullptr) {
316 resize_fcurve(fcu, bezt_index);
323void add_skinned_mesh_bindings(
const pxr::UsdSkelSkeleton &skel,
324 const pxr::UsdPrim &mesh_prim,
325 pxr::UsdGeomXformCache &xf_cache)
327 pxr::UsdSkelBindingAPI skel_api = pxr::UsdSkelBindingAPI::Apply(mesh_prim);
331 "Couldn't apply UsdSkelBindingAPI to skinned mesh prim %s",
332 mesh_prim.GetPath().GetAsString().c_str());
337 pxr::SdfPath skel_path = skel.GetPath();
338 skel_api.CreateSkeletonRel().SetTargets(pxr::SdfPathVector({skel_path}));
341 if (pxr::UsdAttribute geom_bind_attr = skel_api.CreateGeomBindTransformAttr()) {
343 pxr::GfMatrix4d mesh_xf = xf_cache.GetLocalToWorldTransform(mesh_prim);
344 pxr::GfMatrix4d skel_xf = xf_cache.GetLocalToWorldTransform(skel.GetPrim());
345 pxr::GfMatrix4d bind_xf = mesh_xf * skel_xf.GetInverse();
346 geom_bind_attr.Set(bind_xf);
350 "Couldn't create geom bind transform attribute for skinned mesh %s",
351 mesh_prim.GetPath().GetAsString().c_str());
361 const pxr::UsdPrim &prim,
363 const bool import_anim)
365 if (!(mesh_obj && mesh_obj->
data && mesh_obj->
type ==
OB_MESH && prim)) {
369 if (prim.IsInstanceProxy()) {
375 pxr::UsdSkelBindingAPI skel_api(prim);
380 if (!skel_api.GetBlendShapeTargetsRel().HasAuthoredTargets()) {
385 pxr::SdfPathVector targets;
386 if (!skel_api.GetBlendShapeTargetsRel().GetTargets(&targets)) {
389 "%s: Couldn't get blendshape targets for prim %s",
391 prim.GetPath().GetAsString().c_str());
395 if (targets.empty()) {
399 if (!skel_api.GetBlendShapesAttr().HasAuthoredValue()) {
404 pxr::VtTokenArray usd_blendshapes;
405 if (!skel_api.GetBlendShapesAttr().Get(&usd_blendshapes)) {
409 if (usd_blendshapes.empty()) {
414 if (targets.size() != usd_blendshapes.size()) {
418 "%s: Number of blendshapes does not match number of blendshape targets for prim %s",
420 prim.GetPath().GetAsString().c_str());
424 pxr::UsdStageRefPtr stage = prim.GetStage();
429 "%s: Couldn't get stage for prim %s",
431 prim.GetPath().GetAsString().c_str());
452 for (
int i = 0;
i < targets.size(); ++
i) {
454 const pxr::SdfPath &path = targets[
i];
455 pxr::UsdSkelBlendShape blendshape(stage->GetPrimAtPath(path));
462 if (!blendshape.GetOffsetsAttr().HasAuthoredValue()) {
467 pxr::VtVec3fArray usd_offsets;
468 if (!blendshape.GetOffsetsAttr().Get(&usd_offsets)) {
471 "%s: Couldn't get offsets for blend shape %s",
473 path.GetAsString().c_str());
477 if (usd_offsets.empty()) {
480 "%s: No offsets for blend shape %s",
482 path.GetAsString().c_str());
486 shapekey_names.
add(blendshapes[
i]);
498 pxr::VtArray<int> point_indices;
499 if (blendshape.GetPointIndicesAttr().HasAuthoredValue()) {
500 blendshape.GetPointIndicesAttr().Get(&point_indices);
503 float *fp =
static_cast<float *
>(kb->
data);
506 if (point_indices.empty()) {
509 for (
int a = 0; a < kb->
totelem; ++a, fp += 3) {
510 if (a >= offsets.
size()) {
514 "%s: Number of offsets greater than number of mesh vertices for blend shape %s",
516 path.GetAsString().c_str());
526 for (
const int point : point_indices.AsConst()) {
527 if (point < 0 || point > kb->
totelem) {
529 "Out of bounds point index %d for blendshape %s",
531 path.GetAsString().c_str());
535 if (a >= offsets.
size()) {
539 "%s: Number of offsets greater than number of mesh vertices for blend shape %s",
541 path.GetAsString().c_str());
557 pxr::UsdSkelSkeleton skel_prim = skel_api.GetInheritedSkeleton();
563 skel_api = pxr::UsdSkelBindingAPI(skel_prim.GetPrim());
565 pxr::UsdPrim anim_prim = skel_api.GetInheritedAnimationSource();
570 skel_api.GetAnimationSource(&anim_prim);
577 pxr::UsdSkelAnimation skel_anim(anim_prim);
584 if (!skel_anim.GetBlendShapesAttr().HasAuthoredValue()) {
588 pxr::UsdAttribute weights_attr = skel_anim.GetBlendShapeWeightsAttr();
590 if (!(weights_attr && weights_attr.HasAuthoredValue())) {
595 std::vector<double> times;
596 if (!weights_attr.GetTimeSamples(×)) {
605 if (!skel_anim.GetBlendShapesAttr().Get(&usd_blendshapes)) {
609 if (usd_blendshapes.empty()) {
620 curves.
reserve(usd_blendshapes.size());
621 processed_shapes.
reserve(usd_blendshapes.size());
623 for (
auto blendshape_name : usd_blendshapes.AsConst()) {
624 if (!shapekey_names.
contains(blendshape_name)) {
631 if (!processed_shapes.
add(blendshape_name)) {
633 "Duplicate blendshape '%s' encountered for %s",
634 blendshape_name.GetText(),
635 skel_anim.GetPath().GetAsString().c_str());
641 const std::string rna_path =
"key_blocks[\"" + blendshape_name.GetString() +
"\"].value";
648 for (
double frame : times) {
649 pxr::VtFloatArray usd_weights;
650 if (!weights_attr.Get(&usd_weights, frame)) {
651 CLOG_WARN(&
LOG,
"Couldn't get blendshape weights for time %f", frame);
655 if (usd_weights.size() != curves.
size()) {
658 "Number of weight samples does not match number of shapekey curve entries for frame %f",
664 for (
int wi = 0; wi < weights.
size(); ++wi) {
665 if (curves[wi] !=
nullptr) {
674 auto recalc_handles = [bezt_index](
FCurve *fcu) {
675 resize_fcurve(fcu, bezt_index);
678 std::for_each(curves.
begin(), curves.
end(), recalc_handles);
684 const pxr::VtArray<pxr::GfMatrix4d> &bind_xforms,
685 const pxr::VtTokenArray &joint_order,
687 const pxr::UsdSkelTopology &skel_topology,
688 const pxr::UsdSkelSkeletonQuery &skel_query)
690 if (!skel_query.HasRestPose()) {
694 pxr::VtArray<pxr::GfMatrix4d> rest_xforms;
695 if (skel_query.ComputeJointLocalTransforms(&rest_xforms, pxr::UsdTimeCode::Default(),
true)) {
699 for (
const pxr::TfToken &joint : joint_order) {
701 if (
name ==
nullptr) {
708 pxr::GfMatrix4d xf = rest_xforms.AsConst()[
i];
709 pxr::GfMatrix4d bind_xf = bind_xforms[
i];
711 const int parent_id = skel_topology.GetParent(
i);
712 if (parent_id >= 0) {
713 bind_xf = bind_xf * bind_xforms[parent_id].GetInverse();
716 xf = xf * bind_xf.GetInverse();
718 pxr::GfMatrix4f mat(xf);
728 const pxr::UsdSkelSkeleton &skel,
730 const bool import_anim)
736 pxr::UsdSkelCache skel_cache;
737 pxr::UsdSkelSkeletonQuery skel_query = skel_cache.GetSkelQuery(skel);
739 if (!skel_query.IsValid()) {
742 "%s: Couldn't query skeleton %s",
744 skel.GetPath().GetAsString().c_str());
748 const pxr::UsdSkelTopology &skel_topology = skel_query.GetTopology();
749 const pxr::VtTokenArray joint_order = skel_query.GetJointOrder();
751 if (joint_order.size() != skel_topology.size()) {
754 "%s: Topology and joint order size mismatch for skeleton %s",
756 skel.GetPath().GetAsString().c_str());
762 unique_joint_paths.
reserve(joint_order.size());
763 const bool all_valid_paths = std::all_of(
764 joint_order.cbegin(), joint_order.cend(), [&unique_joint_paths](
const pxr::TfToken &val) {
765 const bool is_valid = pxr::SdfPath::IsValidPathString(val);
766 return is_valid && unique_joint_paths.add(val);
768 if (!all_valid_paths) {
771 "%s: USD joint order array contains invalid or duplicated paths for skeleton %s",
773 skel.GetPath().GetAsString().c_str());
791 for (
const pxr::TfToken &joint : joint_order) {
792 pxr::SdfPath bone_path(joint);
793 const std::string &bone_name = bone_path.GetName();
798 "%s: Couldn't add bone for joint %s",
800 joint.GetString().c_str());
801 edit_bones.
append(
nullptr);
804 joint_to_bone_map.
add(joint, bone->
name);
809 const size_t num_joints = skel_topology.GetNumJoints();
810 if (edit_bones.
size() != num_joints) {
813 "%s: Mismatch in bone and joint counts for skeleton %s",
815 skel.GetPath().GetAsString().c_str());
820 pxr::VtMatrix4dArray bind_xforms;
821 if (!skel_query.GetJointWorldBindTransforms(&bind_xforms)) {
824 "%s: Couldn't get world bind transforms for skeleton %s",
826 skel.GetPath().GetAsString().c_str());
830 if (bind_xforms.size() != num_joints) {
833 "%s: Mismatch in bind xforms and joint counts for skeleton %s",
835 skel.GetPath().GetAsString().c_str());
849 bool negative_determinant =
false;
852 for (
size_t i = 0;
i < num_joints; ++
i) {
859 pxr::GfMatrix4f mat(bind_xforms.AsConst()[
i]);
864 pxr::GfVec3f head(0.0f, 0.0f, 0.0f);
865 pxr::GfVec3f tail(0.0f, 1.0f, 0.0f);
872 if (mat.GetDeterminant() < 0.0) {
873 negative_determinant =
true;
877 bool valid_skeleton =
true;
878 if (negative_determinant) {
879 valid_skeleton =
false;
883 "USD Skeleton Import: bone matrices with negative determinants detected in prim %s. "
884 "Such matrices may indicate negative scales, possibly due to mirroring operations, "
885 "and cannot currently be converted to Blender's bone representation. "
886 "The skeletal animation won't be imported",
887 skel.GetPath().GetAsString().c_str());
900 for (
size_t i = 0;
i < num_joints; ++
i) {
901 const int parent_idx = skel_topology.GetParent(
i);
902 if (parent_idx < 0) {
905 if (parent_idx >= edit_bones.
size()) {
907 "Out of bounds parent index for bone %s on skeleton %s",
908 pxr::SdfPath(joint_order[
i]).GetAsString().c_str(),
909 skel.GetPath().GetAsString().c_str());
913 child_bones[parent_idx].
append(
i);
914 if (edit_bones[
i] && edit_bones[parent_idx]) {
915 edit_bones[
i]->parent = edit_bones[parent_idx];
920 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(skel.GetPrim());
922 if (pv_lengths.HasValue()) {
923 pxr::VtArray<float> blender_bone_lengths;
924 pv_lengths.ComputeFlattened(&blender_bone_lengths);
926 Span<float> bone_lengths =
Span(blender_bone_lengths.cdata(), blender_bone_lengths.size());
927 for (
size_t i = 0;
i < num_joints; ++
i) {
929 pxr::GfVec3f head(bone->
head);
930 pxr::GfVec3f tail(bone->
tail);
932 tail = head + (tail - head).GetNormalized() * bone_lengths[
i];
937 float avg_len_scale = 0;
938 for (
size_t i = 0;
i < num_joints; ++
i) {
944 if (child_bones[
i].is_empty()) {
953 pxr::GfVec3f avg_child_head(0);
954 for (
int j : child_bones[
i]) {
959 pxr::GfVec3f child_head(child->
head);
960 avg_child_head += child_head;
963 avg_child_head /= child_bones[
i].
size();
965 pxr::GfVec3f parent_head(parent->
head);
966 pxr::GfVec3f parent_tail(parent->
tail);
968 const float new_len = (avg_child_head - parent_head).GetLength();
971 if (new_len > .00001 * max_mag_component(parent_head)) {
972 parent_tail = parent_head + (parent_tail - parent_head).GetNormalized() * new_len;
974 avg_len_scale += new_len;
979 avg_len_scale /= num_joints;
981 for (
size_t i = 0;
i < num_joints; ++
i) {
982 if (!child_bones[
i].is_empty()) {
990 pxr::GfVec3f head(bone->
head);
993 if (avg_len_scale > .00001 * max_mag_component(head)) {
994 pxr::GfVec3f tail(bone->
tail);
995 tail = head + (tail - head).GetNormalized() * avg_len_scale;
1006 bmain, arm_obj, arm, bind_xforms, joint_order, joint_to_bone_map, skel_topology, skel_query);
1008 if (import_anim && valid_skeleton) {
1009 import_skeleton_curves(bmain, arm_obj, skel_query, joint_to_bone_map, reports);
1015 if (!(mesh_obj && mesh_obj->
type ==
OB_MESH && prim)) {
1019 if (prim.IsInstanceProxy()) {
1025 pxr::UsdSkelBindingAPI skel_api(prim);
1027 pxr::UsdSkelSkeleton skel = skel_api.GetInheritedSkeleton();
1035 pxr::VtArray<pxr::TfToken> joints;
1037 if (skel_api.GetJointsAttr().HasAuthoredValue()) {
1038 skel_api.GetJointsAttr().Get(&joints);
1040 else if (skel.GetJointsAttr().HasAuthoredValue()) {
1041 skel.GetJointsAttr().Get(&joints);
1044 if (joints.empty()) {
1049 pxr::UsdGeomPrimvar joint_indices_primvar = skel_api.GetJointIndicesPrimvar();
1050 if (!(joint_indices_primvar && joint_indices_primvar.HasAuthoredValue())) {
1055 pxr::UsdGeomPrimvar joint_weights_primvar = skel_api.GetJointWeightsPrimvar();
1056 if (!(joint_weights_primvar && joint_weights_primvar.HasAuthoredValue())) {
1062 int joint_indices_elem_size = joint_indices_primvar.GetElementSize();
1063 int joint_weights_elem_size = joint_weights_primvar.GetElementSize();
1066 if (joint_indices_elem_size != joint_weights_elem_size) {
1069 "%s: Joint weights and joint indices element size mismatch for prim %s",
1071 prim.GetPath().GetAsString().c_str());
1076 pxr::VtIntArray joint_indices;
1077 joint_indices_primvar.ComputeFlattened(&joint_indices);
1079 pxr::VtFloatArray joint_weights;
1080 joint_weights_primvar.ComputeFlattened(&joint_weights);
1082 if (joint_indices.empty() || joint_weights.empty()) {
1086 if (joint_indices.size() != joint_weights.size()) {
1089 "%s: Joint weights and joint indices size mismatch for prim %s",
1091 prim.GetPath().GetAsString().c_str());
1097 const pxr::TfToken
interp = joint_weights_primvar.GetInterpolation();
1100 if (!
ELEM(
interp, pxr::UsdGeomTokens->vertex, pxr::UsdGeomTokens->constant)) {
1103 "%s: Unexpected joint weights interpolation type %s for prim %s",
1105 interp.GetString().c_str(),
1106 prim.GetPath().GetAsString().c_str());
1111 if (
interp == pxr::UsdGeomTokens->vertex &&
1112 joint_weights.size() != mesh->
verts_num * joint_weights_elem_size)
1116 "%s: Joint weights of unexpected size for vertex interpolation for prim %s",
1118 prim.GetPath().GetAsString().c_str());
1122 if (
interp == pxr::UsdGeomTokens->constant && joint_weights.size() != joint_weights_elem_size) {
1125 "%s: Joint weights of unexpected size for constant interpolation for prim %s",
1127 prim.GetPath().GetAsString().c_str());
1133 for (
int index : joint_indices.AsConst()) {
1134 if (std::find(used_indices.
begin(), used_indices.
end(), index) == used_indices.
end()) {
1136 if (index < 0 || index >= joints.size()) {
1137 CLOG_ERROR(&
LOG,
"Out of bound joint index %d for mesh %s", index, mesh_obj->
id.
name + 2);
1140 used_indices.
append(index);
1151 "%s: Error creating deform group data for mesh %s",
1167 for (
int idx : used_indices) {
1168 std::string joint_name = pxr::SdfPath(joints.AsConst()[idx]).GetName();
1171 joint_def_grps[idx] = def_grp;
1180 if (
interp == pxr::UsdGeomTokens->vertex) {
1181 offset =
i * joint_weights_elem_size;
1183 for (
int j = 0; j < joint_weights_elem_size; ++j) {
1184 const int k = offset + j;
1185 const float w = joint_weights.AsConst()[k];
1190 const int joint_idx = joint_indices.AsConst()[k];
1191 if (
bDeformGroup *def_grp = joint_def_grps[joint_idx]) {
1207 pxr::UsdGeomXformCache xf_cache(1.0);
1209 stage, armature_export_map, skinned_mesh_export_map, xf_cache,
depsgraph);
1216 pxr::UsdGeomXformCache &xf_cache,
1220 for (
const auto &item : skinned_mesh_export_map.
items()) {
1221 const Object *mesh_obj = item.key;
1222 const pxr::SdfPath &mesh_path = item.value;
1225 pxr::UsdPrim mesh_prim = stage->GetPrimAtPath(mesh_path);
1228 "Invalid export map prim path %s for mesh object %s",
1229 mesh_path.GetAsString().c_str(),
1237 CLOG_WARN(&
LOG,
"Invalid armature modifier for skinned mesh %s", mesh_obj->
id.
name + 2);
1241 const pxr::SdfPath *path = armature_export_map.
lookup_ptr(arm_obj);
1243 CLOG_WARN(&
LOG,
"No export map entry for armature object %s", mesh_obj->
id.
name + 2);
1247 pxr::UsdPrim skel_prim = stage->GetPrimAtPath(*path);
1248 pxr::UsdSkelSkeleton skel(skel_prim);
1250 CLOG_WARN(&
LOG,
"Invalid USD skeleton for armature object %s", arm_obj->
id.
name + 2);
1254 add_skinned_mesh_bindings(skel, mesh_prim, xf_cache);
1268 for (
const auto &item : shape_key_mesh_export_map.
items()) {
1269 const Object *mesh_obj = item.key;
1270 const pxr::SdfPath &mesh_path = item.value;
1273 pxr::UsdPrim mesh_prim = stage->GetPrimAtPath(mesh_path);
1276 "Invalid export map prim path %s for mesh object %s",
1277 mesh_path.GetAsString().c_str(),
1283 mesh_prims.
append(mesh_prim);
1285 pxr::UsdSkelBindingAPI skel_api = pxr::UsdSkelBindingAPI::Apply(mesh_prim);
1289 "Couldn't apply UsdSkelBindingAPI to prim %s",
1290 mesh_prim.GetPath().GetAsString().c_str());
1294 pxr::UsdSkelSkeleton skel;
1295 if (skel_api.GetSkeleton(&skel)) {
1297 pxr::SdfPathSet *mesh_paths = skel_to_mesh.
lookup_ptr(skel.GetPath());
1299 skel_to_mesh.
add_new(skel.GetPath(), pxr::SdfPathSet());
1300 mesh_paths = skel_to_mesh.
lookup_ptr(skel.GetPath());
1303 mesh_paths->insert(mesh_prim.GetPath());
1316 for (
const auto &item : skel_to_mesh.
items()) {
1321 for (
const pxr::UsdPrim &prim : mesh_prims) {
1327 const pxr::UsdSkelBindingAPI &skel_api,
1343 for (
int i = 0;
i < bone_names.
size(); ++
i) {
1344 if (bone_names[
i] == def->name) {
1350 joint_index.
append(bone_idx);
1359 int max_totweight = 1;
1362 max_totweight = std::max(vert.
totweight, max_totweight);
1367 const int element_size = max_totweight;
1370 pxr::VtArray<int> joint_indices(num_points * element_size, 0);
1371 pxr::VtArray<float> joint_weights(num_points * element_size, 0.0f);
1379 for (
int j = 0; j < element_size; ++j, ++offset) {
1381 if (offset >= joint_indices.size()) {
1390 int def_nr = int(vert.
dw[j].
def_nr);
1392 if (def_nr >= joint_index.
size()) {
1397 if (joint_index[def_nr] == -1) {
1401 joint_indices[offset] = joint_index[def_nr];
1402 joint_weights[offset] = vert.
dw[j].
weight;
1406 pxr::UsdSkelNormalizeWeights(joint_weights, element_size);
1408 skel_api.CreateJointIndicesPrimvar(
false, element_size).GetAttr().Set(joint_indices);
1409 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,...)
Object is a sort of wrapper for general info.
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