diff --git a/doc/python_api/examples/bpy.types.USDHook.py b/doc/python_api/examples/bpy.types.USDHook.py index 56b4d9c03d0..d7bcd79edc6 100644 --- a/doc/python_api/examples/bpy.types.USDHook.py +++ b/doc/python_api/examples/bpy.types.USDHook.py @@ -3,9 +3,9 @@ USD Hook Example ++++++++++++++++ This example shows an implementation of ``USDHook`` to extend USD -export functionalty. +export and import functionalty. -One may optionally define one or both of the following callback functions +One may optionally define any or all of the following callback functions in the ``USDHook`` subclass. Hook function ``on_export()`` is called before the USD export finalizes, @@ -31,13 +31,21 @@ USD stage to be saved. Note that the target USD material might already have connected shaders created by the USD exporter or by other material export hooks. -The hook functions should return ``True`` on success or ``False`` if the operation was bypasssed or +Hook function ``on_import()`` is called after the USD import finalizes. This function takes +as an argument an instance of an internally defined class ``USDSceneImportContext`` which provides the +following accessors to the scene data: + +- ``get_stage()`` returns the USD stage which was imported. + +The hook functions should return ``True`` on success or ``False`` if the operation was bypassed or otherwise failed to complete. Exceptions raised by these functions will be reported in Blender, with the exception details printed to the console. -The ``USDHookExample`` class in this example impements an ``on_export()`` function to add custom data to -the stage's root layer and an ``on_material_export()`` function to create a simple ``MaterialX`` shader -on the USD material. +The ``USDHookExample`` class in this example impements the fllowing functions: + +- ``on_export()`` function to add custom data to the stage's root layer. +- ``on_material_export()`` function to create a simple ``MaterialX`` shader on the givne USD material. +- ``on_import()`` function to create a text object to display the stage's custom layer data. """ @@ -96,6 +104,45 @@ class USDHookExample(bpy.types.USDHook): return True + @staticmethod + def on_import(import_context): + """ Create a text object to display the stage's custom data. + """ + stage = import_context.get_stage() + + if stage is None: + return False + + # Get the custom data. + rootLayer = stage.GetRootLayer() + customData = rootLayer.customLayerData + + # Create a text object to display the stage path + # and custom data dictionary entries. + + bpy.ops.object.text_add() + ob = bpy.context.view_layer.objects.active + + if (ob is None) or (ob.data is None): + return False + + ob.name = "layer_data" + ob.data.name = "layer_data" + + # The stage root path is the first line. + text = rootLayer.realPath + + # Append key/value strings, enforcing text wrapping. + for item in customData.items(): + print(item) + text += '\n' + line = str(item[0]) + ': ' + str(item[1]) + text += textwrap.fill(line, width=80) + + ob.data.body = text + + return True + def register(): bpy.utils.register_class(USDHookExample) diff --git a/source/blender/io/usd/intern/usd_capi_export.cc b/source/blender/io/usd/intern/usd_capi_export.cc index 64f797d8629..611cd6baa5d 100644 --- a/source/blender/io/usd/intern/usd_capi_export.cc +++ b/source/blender/io/usd/intern/usd_capi_export.cc @@ -255,8 +255,8 @@ pxr::UsdStageRefPtr export_to_stage(const USDExportParams ¶ms, /* For restoring the current frame after exporting animation is done. */ const int orig_frame = scene->r.cfra; - /* Ensure Python types for invoking export hooks are registered. */ - register_export_hook_converters(); + /* Ensure Python types for invoking hooks are registered. */ + register_hook_converters(); usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z)); ensure_root_prim(usd_stage, params); diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc index d8827ebe5f2..9dc20c45f58 100644 --- a/source/blender/io/usd/intern/usd_capi_import.cc +++ b/source/blender/io/usd/intern/usd_capi_import.cc @@ -5,6 +5,7 @@ #include "IO_types.hh" #include "usd.h" #include "usd_hierarchy_iterator.h" +#include "usd_hook.h" #include "usd_reader_geom.h" #include "usd_reader_prim.h" #include "usd_reader_stage.h" @@ -451,6 +452,11 @@ static void import_endjob(void *customdata) if (data->params.import_materials && data->params.import_all_materials) { data->archive->fake_users_for_unused_materials(); } + + /* Ensure Python types for invoking hooks are registered. */ + register_hook_converters(); + + call_import_hooks(data->archive->stage(), data->params.worker_status->reports); } WM_set_locked_interface(data->wm, false); diff --git a/source/blender/io/usd/intern/usd_hook.cc b/source/blender/io/usd/intern/usd_hook.cc index f075bdc7123..44b10aa99bc 100644 --- a/source/blender/io/usd/intern/usd_hook.cc +++ b/source/blender/io/usd/intern/usd_hook.cc @@ -102,6 +102,21 @@ struct USDSceneExportContext { PointerRNA depsgraph_ptr; }; +/* Encapsulate arguments for scene import. */ +struct USDSceneImportContext { + + USDSceneImportContext() {} + + USDSceneImportContext(pxr::UsdStageRefPtr in_stage) : stage(in_stage) {} + + pxr::UsdStageRefPtr get_stage() + { + return stage; + } + + pxr::UsdStageRefPtr stage; +}; + /* Encapsulate arguments for material export. */ struct USDMaterialExportContext { USDMaterialExportContext() {} @@ -116,7 +131,7 @@ struct USDMaterialExportContext { pxr::UsdStageRefPtr stage; }; -void register_export_hook_converters() +void register_hook_converters() { static bool registered = false; @@ -150,6 +165,9 @@ void register_export_hook_converters() python::class_("USDMaterialExportContext") .def("get_stage", &USDMaterialExportContext::get_stage); + python::class_("USDSceneImportContext") + .def("get_stage", &USDSceneImportContext::get_stage); + PyGILState_Release(gilstate); } @@ -287,6 +305,28 @@ class OnMaterialExportInvoker : public USDHookInvoker { } }; +class OnImportInvoker : public USDHookInvoker { + private: + USDSceneImportContext hook_context_; + + public: + OnImportInvoker(pxr::UsdStageRefPtr stage, ReportList *reports) : hook_context_(stage) + { + reports_ = reports; + } + + protected: + const char *function_name() const override + { + return "on_import"; + } + + void call_hook(PyObject *hook_obj) const override + { + python::call_method(hook_obj, function_name(), hook_context_); + } +}; + void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph, ReportList *reports) { if (g_usd_hooks.empty()) { @@ -310,4 +350,14 @@ void call_material_export_hooks(pxr::UsdStageRefPtr stage, on_material_export.call(); } +void call_import_hooks(pxr::UsdStageRefPtr stage, ReportList *reports) +{ + if (g_usd_hooks.empty()) { + return; + } + + OnImportInvoker on_import(stage, reports); + on_import.call(); +} + } // namespace blender::io::usd diff --git a/source/blender/io/usd/intern/usd_hook.h b/source/blender/io/usd/intern/usd_hook.h index e8c3c3a5b32..49af92e4c7a 100644 --- a/source/blender/io/usd/intern/usd_hook.h +++ b/source/blender/io/usd/intern/usd_hook.h @@ -16,8 +16,9 @@ struct USDExportParams; namespace blender::io::usd { -/** Ensure classes and type converters necessary for invoking export hook are registered. */ -void register_export_hook_converters(); +/** Ensure classes and type converters necessary for invoking import and export hooks + * are registered. */ +void register_hook_converters(); /** Call the 'on_export' chaser function defined in the registered USDHook classes. */ void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph, ReportList *reports); @@ -28,4 +29,7 @@ void call_material_export_hooks(pxr::UsdStageRefPtr stage, pxr::UsdShadeMaterial &usd_material, ReportList *reports); +/** Call the 'on_import' chaser function defined in the registered USDHook classes. */ +void call_import_hooks(pxr::UsdStageRefPtr stage, ReportList *reports); + } // namespace blender::io::usd