USD: basic support for on_import USD hooks
Added support for defining an on_import() function in bpy.types.USDHook subclasses. If on_import() is defined on a given USD hook, it will be invoked in import_endjob(). The implementation closely follows the existing design of export hooks. USDHook.on_import() takes as an argument an instance of an internally defined USDSceneImportContext class which provides an accessor to the USD stage. Also updated the USDHook documentation with an example on_import() callback implementation. Pull Request: https://projects.blender.org/blender/blender/pulls/117822
This commit is contained in:
parent
a3183fb95f
commit
ecbf3385c5
@ -3,9 +3,9 @@ USD Hook Example
|
|||||||
++++++++++++++++
|
++++++++++++++++
|
||||||
|
|
||||||
This example shows an implementation of ``USDHook`` to extend USD
|
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.
|
in the ``USDHook`` subclass.
|
||||||
|
|
||||||
Hook function ``on_export()`` is called before the USD export finalizes,
|
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
|
Note that the target USD material might already have connected shaders created by the USD exporter or
|
||||||
by other material export hooks.
|
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
|
otherwise failed to complete. Exceptions raised by these functions will be reported in Blender, with
|
||||||
the exception details printed to the console.
|
the exception details printed to the console.
|
||||||
|
|
||||||
The ``USDHookExample`` class in this example impements an ``on_export()`` function to add custom data to
|
The ``USDHookExample`` class in this example impements the fllowing functions:
|
||||||
the stage's root layer and an ``on_material_export()`` function to create a simple ``MaterialX`` shader
|
|
||||||
on the USD material.
|
- ``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
|
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():
|
def register():
|
||||||
bpy.utils.register_class(USDHookExample)
|
bpy.utils.register_class(USDHookExample)
|
||||||
|
@ -255,8 +255,8 @@ pxr::UsdStageRefPtr export_to_stage(const USDExportParams ¶ms,
|
|||||||
/* For restoring the current frame after exporting animation is done. */
|
/* For restoring the current frame after exporting animation is done. */
|
||||||
const int orig_frame = scene->r.cfra;
|
const int orig_frame = scene->r.cfra;
|
||||||
|
|
||||||
/* Ensure Python types for invoking export hooks are registered. */
|
/* Ensure Python types for invoking hooks are registered. */
|
||||||
register_export_hook_converters();
|
register_hook_converters();
|
||||||
|
|
||||||
usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z));
|
usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z));
|
||||||
ensure_root_prim(usd_stage, params);
|
ensure_root_prim(usd_stage, params);
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "IO_types.hh"
|
#include "IO_types.hh"
|
||||||
#include "usd.h"
|
#include "usd.h"
|
||||||
#include "usd_hierarchy_iterator.h"
|
#include "usd_hierarchy_iterator.h"
|
||||||
|
#include "usd_hook.h"
|
||||||
#include "usd_reader_geom.h"
|
#include "usd_reader_geom.h"
|
||||||
#include "usd_reader_prim.h"
|
#include "usd_reader_prim.h"
|
||||||
#include "usd_reader_stage.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) {
|
if (data->params.import_materials && data->params.import_all_materials) {
|
||||||
data->archive->fake_users_for_unused_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);
|
WM_set_locked_interface(data->wm, false);
|
||||||
|
@ -102,6 +102,21 @@ struct USDSceneExportContext {
|
|||||||
PointerRNA depsgraph_ptr;
|
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. */
|
/* Encapsulate arguments for material export. */
|
||||||
struct USDMaterialExportContext {
|
struct USDMaterialExportContext {
|
||||||
USDMaterialExportContext() {}
|
USDMaterialExportContext() {}
|
||||||
@ -116,7 +131,7 @@ struct USDMaterialExportContext {
|
|||||||
pxr::UsdStageRefPtr stage;
|
pxr::UsdStageRefPtr stage;
|
||||||
};
|
};
|
||||||
|
|
||||||
void register_export_hook_converters()
|
void register_hook_converters()
|
||||||
{
|
{
|
||||||
static bool registered = false;
|
static bool registered = false;
|
||||||
|
|
||||||
@ -150,6 +165,9 @@ void register_export_hook_converters()
|
|||||||
python::class_<USDMaterialExportContext>("USDMaterialExportContext")
|
python::class_<USDMaterialExportContext>("USDMaterialExportContext")
|
||||||
.def("get_stage", &USDMaterialExportContext::get_stage);
|
.def("get_stage", &USDMaterialExportContext::get_stage);
|
||||||
|
|
||||||
|
python::class_<USDSceneImportContext>("USDSceneImportContext")
|
||||||
|
.def("get_stage", &USDSceneImportContext::get_stage);
|
||||||
|
|
||||||
PyGILState_Release(gilstate);
|
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<bool>(hook_obj, function_name(), hook_context_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph, ReportList *reports)
|
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph, ReportList *reports)
|
||||||
{
|
{
|
||||||
if (g_usd_hooks.empty()) {
|
if (g_usd_hooks.empty()) {
|
||||||
@ -310,4 +350,14 @@ void call_material_export_hooks(pxr::UsdStageRefPtr stage,
|
|||||||
on_material_export.call();
|
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
|
} // namespace blender::io::usd
|
||||||
|
@ -16,8 +16,9 @@ struct USDExportParams;
|
|||||||
|
|
||||||
namespace blender::io::usd {
|
namespace blender::io::usd {
|
||||||
|
|
||||||
/** Ensure classes and type converters necessary for invoking export hook are registered. */
|
/** Ensure classes and type converters necessary for invoking import and export hooks
|
||||||
void register_export_hook_converters();
|
* are registered. */
|
||||||
|
void register_hook_converters();
|
||||||
|
|
||||||
/** Call the 'on_export' chaser function defined in the registered USDHook classes. */
|
/** Call the 'on_export' chaser function defined in the registered USDHook classes. */
|
||||||
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph, ReportList *reports);
|
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,
|
pxr::UsdShadeMaterial &usd_material,
|
||||||
ReportList *reports);
|
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
|
} // namespace blender::io::usd
|
||||||
|
Loading…
Reference in New Issue
Block a user