diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c index e6426732584..e8e44e853db 100644 --- a/source/blender/editors/io/io_usd.c +++ b/source/blender/editors/io/io_usd.c @@ -137,6 +137,7 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op) const bool export_textures = RNA_boolean_get(op->ptr, "export_textures"); const bool overwrite_textures = RNA_boolean_get(op->ptr, "overwrite_textures"); const bool relative_paths = RNA_boolean_get(op->ptr, "relative_paths"); + const bool add_root_node = RNA_boolean_get(op->ptr, "add_root_node"); struct USDExportParams params = { export_animation, @@ -152,6 +153,7 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op) export_textures, overwrite_textures, relative_paths, + add_root_node, }; bool ok = USD_export(C, filename, ¶ms, as_background_job); @@ -179,6 +181,7 @@ static void wm_usd_export_draw(bContext *UNUSED(C), wmOperator *op) uiItemR(col, ptr, "export_uvmaps", 0, NULL, ICON_NONE); uiItemR(col, ptr, "export_normals", 0, NULL, ICON_NONE); uiItemR(col, ptr, "export_materials", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "add_root_node", 0, NULL, ICON_NONE); col = uiLayoutColumn(box, true); uiItemR(col, ptr, "evaluation_mode", 0, NULL, ICON_NONE); @@ -334,6 +337,13 @@ void WM_OT_usd_export(struct wmOperatorType *ot) "Relative Paths", "Use relative paths to reference external files (i.e. textures, volumes) in " "USD, otherwise use absolute paths"); + + RNA_def_boolean(ot->srna, + "add_root_node", + false, + "Add Root Node", + "Add a Root 'Xform' node to the stage that can be used in other applications" + "to transform all the primitives in the stage"); } /* ====== USD Import ====== */ diff --git a/source/blender/io/usd/intern/usd_capi_export.cc b/source/blender/io/usd/intern/usd_capi_export.cc index 7ab244f18f0..6367e8dd093 100644 --- a/source/blender/io/usd/intern/usd_capi_export.cc +++ b/source/blender/io/usd/intern/usd_capi_export.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include "MEM_guardedalloc.h" @@ -111,6 +112,10 @@ static void export_startjob(void *customdata, usd_stage->SetEndTimeCode(scene->r.efra); } + if (data->params.add_root_node) { + pxr::UsdGeomXform::Define(usd_stage, pxr::SdfPath("/Root")); + } + USDHierarchyIterator iter(data->bmain, data->depsgraph, usd_stage, data->params); if (data->params.export_animation) { diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc index abf6c0cb0f9..c0ae2f78d9f 100644 --- a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc +++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc @@ -77,8 +77,15 @@ const pxr::UsdTimeCode &USDHierarchyIterator::get_export_time_code() const USDExporterContext USDHierarchyIterator::create_usd_export_context(const HierarchyContext *context) { + pxr::SdfPath path; + if (params_.add_root_node) { + path = pxr::SdfPath("/Root" + context->export_path); + } else { + path = pxr::SdfPath(context->export_path); + } + return USDExporterContext{ - bmain_, depsgraph_, stage_, pxr::SdfPath(context->export_path), this, params_}; + bmain_, depsgraph_, stage_, path, this, params_}; } AbstractHierarchyWriter *USDHierarchyIterator::create_transform_writer( diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h index 36ad857c57e..975d1f84dd0 100644 --- a/source/blender/io/usd/usd.h +++ b/source/blender/io/usd/usd.h @@ -50,6 +50,7 @@ struct USDExportParams { bool export_textures; bool overwrite_textures; bool relative_paths; + bool add_root_node; }; struct USDImportParams {