USD export: prototype invoking Python chasers #108823
@ -297,6 +297,7 @@ static void export_startjob(void *customdata,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
register_export_hook_converters();
|
||||||
call_export_hooks(usd_stage, data->depsgraph);
|
call_export_hooks(usd_stage, data->depsgraph);
|
||||||
|
|
||||||
usd_stage->GetRootLayer()->Save();
|
usd_stage->GetRootLayer()->Save();
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
#include <boost/python/object.hpp>
|
#include <boost/python/object.hpp>
|
||||||
#include <boost/python/call_method.hpp>
|
#include <boost/python/call_method.hpp>
|
||||||
|
#include <boost/python/class.hpp>
|
||||||
|
#include <boost/python/return_value_policy.hpp>
|
||||||
|
#include <boost/python/to_python_converter.hpp>
|
||||||
|
|
||||||
#include "BLI_listbase.h"
|
#include "BLI_listbase.h"
|
||||||
|
|
||||||
@ -57,6 +60,71 @@ USDHook *USD_find_hook_name(const char name[])
|
|||||||
|
|
||||||
namespace blender::io::usd {
|
namespace blender::io::usd {
|
||||||
|
|
||||||
|
/* Convert PointerRNA to a PyObject*. */
|
||||||
|
struct PointerRNAToPython {
|
||||||
|
|
||||||
|
static PyObject *convert(const PointerRNA &pRNA)
|
||||||
|
{
|
||||||
|
return pyrna_struct_CreatePyObject(const_cast<PointerRNA*>(&pRNA));
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Encapsulate arguments for scene export. */
|
||||||
|
struct USDSceneExportContext {
|
||||||
|
|
||||||
|
USDSceneExportContext() : depsgraph_ptr({})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
USDSceneExportContext(pxr::UsdStageRefPtr in_stage, Depsgraph *depsgraph) : stage(in_stage)
|
||||||
|
{
|
||||||
|
RNA_pointer_create(NULL, &RNA_Depsgraph, depsgraph, &depsgraph_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pxr::UsdStageRefPtr GetStage()
|
||||||
|
{
|
||||||
|
return stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PointerRNA &GetDepsgraph()
|
||||||
|
{
|
||||||
|
return depsgraph_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pxr::UsdStageRefPtr stage;
|
||||||
|
PointerRNA depsgraph_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
void register_export_hook_converters()
|
||||||
|
{
|
||||||
|
static bool registered = false;
|
||||||
|
|
||||||
|
/* No need to register if there are no hooks. */
|
||||||
|
if (g_usd_hooks.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
registered = true;
|
||||||
|
|
||||||
makowalski marked this conversation as resolved
Outdated
|
|||||||
|
PyGILState_STATE gilstate = PyGILState_Ensure();
|
||||||
|
|
||||||
|
python::to_python_converter<PointerRNA, PointerRNAToPython>();
|
||||||
|
|
||||||
|
python::class_<USDSceneExportContext>("USDSceneExportContext")
|
||||||
|
.def("GetStage", &USDSceneExportContext::GetStage)
|
||||||
|
.def("GetDepsgraph",
|
||||||
|
&USDSceneExportContext::GetDepsgraph,
|
||||||
|
python::return_value_policy<python::return_by_value>())
|
||||||
|
;
|
||||||
|
|
||||||
|
PyGILState_Release(gilstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph)
|
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph)
|
||||||
{
|
{
|
||||||
@ -69,9 +137,6 @@ void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph)
|
|||||||
/* The chaser function name. */
|
/* The chaser function name. */
|
||||||
const char *func_name = "on_export";
|
const char *func_name = "on_export";
|
||||||
|
|
||||||
PointerRNA depsgraph_ptr;
|
|
||||||
PyObject *depsgraph_obj = nullptr;
|
|
||||||
|
|
||||||
/* Iterate over the hooks and invoke the hook function, if it's defined. */
|
/* Iterate over the hooks and invoke the hook function, if it's defined. */
|
||||||
USDHookList::const_iterator hook_iter = g_usd_hooks.begin();
|
USDHookList::const_iterator hook_iter = g_usd_hooks.begin();
|
||||||
while (hook_iter != g_usd_hooks.end()) {
|
while (hook_iter != g_usd_hooks.end()) {
|
||||||
@ -95,22 +160,11 @@ void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!depsgraph_obj) {
|
USDSceneExportContext hook_context(stage, depsgraph);
|
||||||
RNA_pointer_create(NULL, &RNA_Depsgraph, depsgraph, &depsgraph_ptr);
|
|
||||||
depsgraph_obj = pyrna_struct_CreatePyObject(&depsgraph_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!depsgraph_obj) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Invoke the chaser. Additional arguments could be
|
|
||||||
* provided, e.g., a dictionary mapping Blender objects
|
|
||||||
* to USD prims. */
|
|
||||||
python::call_method<void>(hook_obj,
|
python::call_method<void>(hook_obj,
|
||||||
func_name,
|
func_name,
|
||||||
python::object(python::handle<>(depsgraph_obj)),
|
hook_context);
|
||||||
stage);
|
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
@ -119,10 +173,6 @@ void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (depsgraph_obj) {
|
|
||||||
Py_DECREF(depsgraph_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyGILState_Release(gilstate);
|
PyGILState_Release(gilstate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,9 @@ struct USDExportParams;
|
|||||||
|
|
||||||
namespace blender::io::usd {
|
namespace blender::io::usd {
|
||||||
|
|
||||||
|
/* Ensure classes and type converters necessary for invoking export hook are registered. */
|
||||||
|
void register_export_hook_converters();
|
||||||
|
|
||||||
/* Call the 'on_export' chaser function defined in the registred USDHook classes. */
|
/* Call the 'on_export' chaser function defined in the registred USDHook classes. */
|
||||||
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph);
|
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user
Would it make sense to pass in a struct or object with the stage as a field instead of the stage directly?
I'm not sure how much work it would be, but it would have the advantage that when you add extra parameters, they could simply be added as fields on the struct/object.
Maya does something similar where chasers are passed a
factoryContext
, and you dofactoryContext.GetStage()
to get the stage.The reason I suggest that is because if in the future we add more arguments, it changes the function signature, thereby potentially breaking existing add-ons unless they also specify
*args, **kwargs
to capture unknowns. Whereas if they simply accept a singular object as the argument, then new parameters can be passed in on that object, keeping the signature of the function intact.Thanks for the suggestion, Dhruv. What you propose definitely makes sense. I'm guessing falling back on
*args, **kwargs
for arbitrary arguments would be the least amount of work, but a custom struct would be a much cleaner API. We can discuss further. I'm currently finishing up the changes requested by Brecht as well as a simple example of material conversion. I should be done with this in the next couple of days. In the meantime, I'll give some thought to this issue.Dhruv, I've determined that providing a struct as an argument isn't much extra work, so I'll update the prototype to use this approach in the next day or so. Thanks, again, for suggesting this.
That's great to hear, and thank you for doing that. I think it'll help long term with API stability.
That's great to hear, and thank you for doing that. I think it'll help long term with API stability.