USD has a callback system that they call "Notices". These can be used to run arbitrary commands whenever USD scene data is changed.
class UpdateNotice : public pxr::TfWeakBase
{
public:
UpdateNotice(const pxr::UsdStageWeakPtr &stage) {
pxr::TfNotice::Register(
pxr::TfCreateWeakPtr(this),
&UpdateNotice::_callback,
stage
);
}
private:
void _callback(
const pxr::UsdNotice::ObjectsChanged ¬ice,
const pxr::UsdStageWeakPtr &sender
) {
}
};
int main() {
// ... more code
{
UpdateNotice updated {stage};
stage->DefinePrim(pxr::SdfPath {"/SomeSphere"});
}
}
# Run `update` whenever an object in `stage` changes
updated = Tf.Notice.Register(Usd.Notice.ObjectsChanged, update, stage)
stage.DefinePrim('/SomeSphere')
stage.GetPrimAtPath("/SomeSphere").SetMetadata("comment", "")
# XXX : `del` revokes the notice
del updated
stage.DefinePrim('/SomeSphere2') # This won't trigger the `update` function
class ObjectNoticeGlobal : public pxr::TfWeakBase
{
public:
ObjectNoticeGlobal() {
pxr::TfNotice::Register(
pxr::TfCreateWeakPtr<ObjectNoticeGlobal>(this),
&ObjectNoticeGlobal::_callback
);
}
private:
void _callback(
const pxr::UsdNotice::ObjectsChanged ¬ice
) {
// TODO : How do you print `notice`?
std::cout << "The triggered stage " << pxr::TfStringify(notice.GetStage()) << '\n';
}
};
int main() {
// ... more code
{
ObjectNoticeGlobal objects;
stage->DefinePrim(pxr::SdfPath {"/Foo"});
}
}
objects = Tf.Notice.RegisterGlobally(Usd.Notice.ObjectsChanged, update)
stage.DefinePrim("/Foo") # This will call `update`
https://graphics.pixar.com/usd/docs/api/page_tf__notification.html
https://graphics.pixar.com/usd/docs/api/class_tf_notice.html