[Bf-blender-cvs] [8ca67ef025c] universal-scene-description: USD export: Skel Root validation.
Michael Kowalski
noreply at git.blender.org
Tue Dec 7 18:53:51 CET 2021
Commit: 8ca67ef025c097f05478e7005eeb387bd1bb0c4b
Author: Michael Kowalski
Date: Tue Dec 7 12:42:42 2021 -0500
Branches: universal-scene-description
https://developer.blender.org/rB8ca67ef025c097f05478e7005eeb387bd1bb0c4b
USD export: Skel Root validation.
Added function for verifying that skinned prims
and skeletons are properly grouped under a common
SkelRoot. Also added a Fix Skel Root export
option to attempt to fix the hierarchy if the Skel
Root is invalid.
===================================================================
M source/blender/editors/io/io_usd.c
M source/blender/io/usd/intern/usd_capi_export.cc
M source/blender/io/usd/intern/usd_writer_skel_root.cc
M source/blender/io/usd/intern/usd_writer_skel_root.h
M source/blender/io/usd/usd.h
===================================================================
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index dd5f28e253a..0a1441b3dd1 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -313,6 +313,8 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
const eUSDXformOpMode xform_op_mode = RNA_enum_get(op->ptr, "xform_op_mode");
+ const bool fix_skel_root = RNA_boolean_get(op->ptr, "fix_skel_root");;
+
struct USDExportParams params = {RNA_int_get(op->ptr, "start"),
RNA_int_get(op->ptr, "end"),
export_animation,
@@ -366,7 +368,8 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
convert_world_material,
generate_cycles_shaders,
export_armatures,
- xform_op_mode};
+ xform_op_mode,
+ fix_skel_root};
/* Take some defaults from the scene, if not specified explicitly. */
Scene *scene = CTX_data_scene(C);
@@ -513,6 +516,7 @@ static void wm_usd_export_draw(bContext *C, wmOperator *op)
box = uiLayoutBox(layout);
uiItemL(box, IFACE_("Experimental:"), ICON_NONE);
uiItemR(box, ptr, "use_instancing", 0, NULL, ICON_NONE);
+ uiItemR(box, ptr, "fix_skel_root", 0, NULL, ICON_NONE);
}
void WM_OT_usd_export(struct wmOperatorType *ot)
@@ -648,6 +652,13 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
"When checked, instanced objects are exported as references in USD. "
"When unchecked, instanced objects are exported as real objects");
+ RNA_def_boolean(ot->srna,
+ "fix_skel_root",
+ false,
+ "Fix Skel Root",
+ "If exporting armatures, attempt to automatically "
+ "correct invalid USD Skel Root hierarchies");
+
RNA_def_enum(ot->srna,
"evaluation_mode",
rna_enum_usd_export_evaluation_mode_items,
diff --git a/source/blender/io/usd/intern/usd_capi_export.cc b/source/blender/io/usd/intern/usd_capi_export.cc
index a7c1f57095c..3a5c191131b 100644
--- a/source/blender/io/usd/intern/usd_capi_export.cc
+++ b/source/blender/io/usd/intern/usd_capi_export.cc
@@ -23,6 +23,7 @@
#include "usd_light_convert.h"
#include "usd_umm.h"
#include "usd_writer_material.h"
+#include "usd_writer_skel_root.h"
#include <pxr/base/plug/registry.h>
#include <pxr/pxr.h>
@@ -336,6 +337,10 @@ static void export_startjob(void *customdata,
iter.release_writers();
+ if (data->params.export_armatures) {
+ validate_skel_roots(usd_stage, data->params);
+ }
+
// Set Stage Default Prim Path
if (strlen(data->params.default_prim_path) > 0) {
std::string valid_default_prim_path = pxr::TfMakeValidIdentifier(
diff --git a/source/blender/io/usd/intern/usd_writer_skel_root.cc b/source/blender/io/usd/intern/usd_writer_skel_root.cc
index ee241b9d18c..ea9dcde5570 100644
--- a/source/blender/io/usd/intern/usd_writer_skel_root.cc
+++ b/source/blender/io/usd/intern/usd_writer_skel_root.cc
@@ -18,8 +18,14 @@
*/
#include "usd_writer_skel_root.h"
+#include "WM_api.h"
+
+#include <pxr/usd/usd/primRange.h>
+#include <pxr/usd/usdSkel/bindingAPI.h>
#include <pxr/usd/usdSkel/root.h>
+#include <iostream>
+
namespace blender::io::usd {
bool USDSkelRootWriter::is_under_skel_root() const
@@ -34,14 +40,13 @@ bool USDSkelRootWriter::is_under_skel_root() const
pxr::UsdPrim prim = usd_export_context_.stage->GetPrimAtPath(parent_path);
- while (prim.IsValid()) {
- if (prim.IsA<pxr::UsdSkelRoot>()) {
- return true;
- }
- prim = prim.GetParent();
+ if (!prim.IsValid()) {
+ return false;
}
- return false;
+ pxr::UsdSkelRoot root = pxr::UsdSkelRoot::Find(prim);
+
+ return static_cast<bool>(root);
}
pxr::UsdGeomXformable USDSkelRootWriter::create_xformable() const
@@ -67,4 +72,107 @@ pxr::UsdGeomXformable USDSkelRootWriter::create_xformable() const
return root;
}
+static pxr::UsdGeomXform get_xform_ancestor(const pxr::UsdPrim &prim1,
+ const pxr::UsdPrim &prim2)
+{
+ if (!prim1 || !prim2) {
+ return pxr::UsdGeomXform();
+ }
+
+ pxr::SdfPath prefix = prim1.GetPath().GetCommonPrefix(prim2.GetPath());
+
+ if (prefix.IsEmpty()) {
+ return pxr::UsdGeomXform();
+ }
+
+ pxr::UsdPrim ancestor = prim1.GetStage()->GetPrimAtPath(prefix);
+
+ if (!ancestor.IsA<pxr::UsdGeomXform>()) {
+ ancestor = ancestor.GetParent();
+ }
+
+ if (ancestor.IsA<pxr::UsdGeomXform>()) {
+ return pxr::UsdGeomXform(ancestor);
+ }
+
+ return pxr::UsdGeomXform();
+}
+
+void validate_skel_roots(pxr::UsdStageRefPtr stage, const USDExportParams ¶ms)
+{
+ if (!params.export_armatures || !stage) {
+ return;
+ }
+
+ bool created_skel_root = false;
+
+ pxr::UsdPrimRange it = stage->Traverse();
+ for (pxr::UsdPrim prim : it) {
+ if (prim.HasAPI<pxr::UsdSkelBindingAPI>() && !prim.IsA<pxr::UsdSkelSkeleton>()) {
+
+ pxr::UsdSkelBindingAPI skel_bind_api(prim);
+ if (skel_bind_api) {
+ pxr::UsdSkelSkeleton skel;
+ if (skel_bind_api.GetSkeleton(&skel)) {
+
+ if (!skel.GetPrim().IsValid()) {
+ std::cout << "WARNING in validate_skel_roots(): invalid skeleton for prim " << prim.GetPath() << std::endl;
+ continue;
+ }
+
+ pxr::UsdSkelRoot prim_root = pxr::UsdSkelRoot::Find(prim);
+ pxr::UsdSkelRoot arm_root = pxr::UsdSkelRoot::Find(skel.GetPrim());
+
+ bool common_root = false;
+
+ if (prim_root && arm_root && prim_root.GetPath() == arm_root.GetPath()) {
+ common_root = true;
+ }
+
+ if (!common_root) {
+ WM_reportf(RPT_WARNING, "USD Export: skinned prim %s and skeleton %s do not share a common SkelRoot and may not bind correctly. See the documentation for possible solutions.\n",
+ prim.GetPath().GetAsString().c_str(), skel.GetPrim().GetPath().GetAsString().c_str());
+ std::cout << "WARNING: skinned prim " << prim.GetPath() << " and skeleton " << skel.GetPrim().GetPath()
+ << " do not share a common SkelRoot and may not bind correctly. See the documentation for possible solutions." << std::endl;
+
+ if (params.fix_skel_root) {
+ std::cout << "Attempting to fix the Skel Root hierarchy." << std::endl;
+ WM_reportf(RPT_WARNING, "Attempting to fix the Skel Root hierarchy. See the console for information");
+
+ if (pxr::UsdGeomXform xf = get_xform_ancestor(prim, skel.GetPrim())) {
+ /* Enable skeletal processing by setting the type to UsdSkelRoot. */
+ std::cout << "Converting Xform prim " << xf.GetPath() << " to a SkelRoot" << std::endl;
+
+ pxr::UsdSkelRoot::Define(stage, xf.GetPath());
+ created_skel_root = true;
+ }
+ else {
+ std::cout << "Couldn't find a commone Xform ancestor for skinned prim " << prim.GetPath()
+ << " and skeleton " << skel.GetPrim().GetPath() << " to convert to a USDSkelRoot\n";
+ std::cout << "You might wish to group these objects under an Empty in the Blender scene.\n";
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!created_skel_root) {
+ return;
+ }
+
+ it = stage->Traverse();
+ for (pxr::UsdPrim prim : it) {
+ if (prim.IsA<pxr::UsdSkelRoot>()) {
+ if (pxr::UsdSkelRoot root = pxr::UsdSkelRoot::Find(prim.GetParent())) {
+ /* This is a nested SkelRoot, so convert it to an Xform. */
+ std::cout << "Converting nested SkelRoot " << prim.GetPath() << " to an Xform." << std::endl;
+ pxr::UsdGeomXform::Define(stage, prim.GetPath());
+ }
+ }
+ }
+
+}
+
} // namespace blender::io::usd
diff --git a/source/blender/io/usd/intern/usd_writer_skel_root.h b/source/blender/io/usd/intern/usd_writer_skel_root.h
index 7a33721a79e..4686374bb40 100644
--- a/source/blender/io/usd/intern/usd_writer_skel_root.h
+++ b/source/blender/io/usd/intern/usd_writer_skel_root.h
@@ -24,6 +24,8 @@
namespace blender::io::usd {
+void validate_skel_roots(pxr::UsdStageRefPtr stage, const USDExportParams ¶ms);
+
class USDSkelRootWriter : public USDTransformWriter {
public:
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index 99e99ab34d6..c0441e2eace 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -132,6 +132,7 @@ struct USDExportParams {
bool generate_cycles_shaders;
bool export_armatures;
eUSDXformOpMode xform_op_mode;
+ bool fix_skel_root;
};
struct USDImportParams {
More information about the Bf-blender-cvs
mailing list