Blender V4.3
usd_skel_root_utils.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 NVIDIA Corporation. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include <pxr/usd/usd/primRange.h>
8#include <pxr/usd/usdGeom/xform.h>
9#include <pxr/usd/usdSkel/bindingAPI.h>
10#include <pxr/usd/usdSkel/root.h>
11
12#include "BKE_report.hh"
13
14#include "WM_types.hh"
15
16#include "CLG_log.h"
17static CLG_LogRef LOG = {"io.usd"};
18
19/* Utility: return the common Xform ancestor of the given prims. Is no such ancestor can
20 * be found, return an in valid Xform. */
21static pxr::UsdGeomXform get_xform_ancestor(const pxr::UsdPrim &prim1, const pxr::UsdPrim &prim2)
22{
23 if (!prim1 || !prim2) {
24 return pxr::UsdGeomXform();
25 }
26
27 pxr::SdfPath prefix = prim1.GetPath().GetCommonPrefix(prim2.GetPath());
28
29 if (prefix.IsEmpty()) {
30 return pxr::UsdGeomXform();
31 }
32
33 pxr::UsdPrim ancestor = prim1.GetStage()->GetPrimAtPath(prefix);
34
35 if (!ancestor) {
36 return pxr::UsdGeomXform();
37 }
38
39 while (ancestor && !ancestor.IsA<pxr::UsdGeomXform>()) {
40 ancestor = ancestor.GetParent();
41 }
42
43 if (ancestor && ancestor.IsA<pxr::UsdGeomXform>()) {
44 return pxr::UsdGeomXform(ancestor);
45 }
46
47 return pxr::UsdGeomXform();
48}
49
50namespace blender::io::usd {
51
52void create_skel_roots(pxr::UsdStageRefPtr stage, const USDExportParams &params)
53{
54 if (!stage || !(params.export_armatures || params.export_shapekeys)) {
55 return;
56 }
57
58 ReportList *reports = params.worker_status ? params.worker_status->reports : nullptr;
59
60 /* Whether we converted any prims to UsdSkel. */
61 bool converted_to_usdskel = false;
62
63 pxr::UsdPrimRange it = stage->Traverse();
64 for (pxr::UsdPrim prim : it) {
65
66 if (!prim) {
67 continue;
68 }
69
70 if (prim.IsA<pxr::UsdSkelSkeleton>() || !prim.HasAPI<pxr::UsdSkelBindingAPI>()) {
71 continue;
72 }
73
74 pxr::UsdSkelBindingAPI skel_bind_api(prim);
75
76 if (!skel_bind_api) {
78 "Couldn't apply UsdSkelBindingAPI to prim %s",
79 prim.GetPath().GetAsString().c_str());
80 continue;
81 }
82
83 /* If we got here, then this prim has the skel binding API. */
84
85 /* Get this prim's bound skeleton. */
86 pxr::UsdSkelSkeleton skel;
87 if (!skel_bind_api.GetSkeleton(&skel)) {
88 continue;
89 }
90
91 if (!skel.GetPrim().IsValid()) {
92 CLOG_WARN(&LOG, "Invalid skeleton for prim %s", prim.GetPath().GetAsString().c_str());
93 continue;
94 }
95
96 /* Try to find a common ancestor of the skinned prim and its bound skeleton. */
97 pxr::UsdSkelRoot prim_skel_root = pxr::UsdSkelRoot::Find(prim);
98 pxr::UsdSkelRoot skel_skel_root = pxr::UsdSkelRoot::Find(skel.GetPrim());
99
100 if (prim_skel_root && skel_skel_root && prim_skel_root.GetPath() == skel_skel_root.GetPath()) {
101 continue;
102 }
103
104 if (pxr::UsdGeomXform xf = get_xform_ancestor(prim, skel.GetPrim())) {
105 /* We found a common Xform ancestor, so we set its type to UsdSkelRoot. */
106 CLOG_INFO(
107 &LOG, 2, "Converting Xform prim %s to a SkelRoot", prim.GetPath().GetAsString().c_str());
108
109 pxr::UsdSkelRoot::Define(stage, xf.GetPath());
110 converted_to_usdskel = true;
111 }
112 else {
113 BKE_reportf(reports,
115 "%s: Couldn't find a common Xform ancestor for skinned prim %s "
116 "and skeleton %s to convert to a USD SkelRoot. "
117 "This can be addressed by setting a root primitive in the export options",
118 __func__,
119 prim.GetPath().GetAsString().c_str(),
120 skel.GetPath().GetAsString().c_str());
121 }
122 }
123
124 if (!converted_to_usdskel) {
125 return;
126 }
127
128 /* Check for nested SkelRoots, i.e., SkelRoots beneath other SkelRoots, which we want to avoid.
129 */
130 it = stage->Traverse();
131 for (pxr::UsdPrim prim : it) {
132 if (prim.IsA<pxr::UsdSkelRoot>()) {
133 if (pxr::UsdSkelRoot root = pxr::UsdSkelRoot::Find(prim.GetParent())) {
134 /* This is a nested SkelRoot, so convert it to an Xform. */
135 pxr::UsdGeomXform::Define(stage, prim.GetPath());
136 }
137 }
138 }
139}
140
141} // namespace blender::io::usd
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
EvaluationStage stage
Definition deg_eval.cc:83
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define LOG(severity)
Definition log.h:33
void create_skel_roots(pxr::UsdStageRefPtr stage, const USDExportParams &params)
static CLG_LogRef LOG
static pxr::UsdGeomXform get_xform_ancestor(const pxr::UsdPrim &prim1, const pxr::UsdPrim &prim2)