Deinstancing points in a point instancer

Is there any recommend / best practice workflows for extracting a subset of points out of a point instancer into xform prims?

We need to take the point instanced geo and simulate a sub-section of that, but preserve the material bindings / materials that were assigned to the prototype (this must be a common senario?).

Our pipeline is complicated by not using an asset resolver since our stages are build dynamically using abstract prims to respresent our assets. The instancer’s prototype sources are setup in LOPS using the abstract prims as prototype sources.

We’ve made a few HDA’s to help with populating the invisibleIds on the point instancer and taking that array of points and creating new xform prims for each

Question 1:
What is the best way to convert the orientation quat to a rotation for an xform? This is what I am doing:

Gf.Rotation(quat_array).GetAxis()

Question 2:

  • Is it possible to batch create 1000’s of xformOps within an Sdf.ChangeBlock?

In order to preserve the material bindings we inherit the abstract class onto the new xform prim and then deactivate the meshes, mateirals etc and flatten the layer to preserve the material bindings on the geometry under each xform prim. This flatten comes at a cost which ideally I would like to avoid. The problem is leaving a live inherits on the prim will be stronger when composed (since the layer that contains the new mesh / inherits is referenced in).

We slurp the xforms / meshes into SOPs, manipulate then feed that unique geo back into a SOP import LOPs.

This new SOP’s geo is combined with a layer which is pre-flattened to preseve the geo’s material bindingsand the material inherits is layered ontop of the new geo and the whole thing is dumped out to a layer. This preserves the per-xform material bindings.

I suspect being able to use sublayers more directly would reduce this complexity, but that isn’t an option for us right now.

I hope that makes sense - any tricks and tips would be super helpful as I see us hitting a wall pretty quickly if we need to de-instances 10’s of thousands of points for some reason.

Question 1:
Is there a reason you want to convert it to a rotation rather than keep it as an orient op, which uses quaternions directly? Otherwise you would have to decompose your rotation into euler angles and choose the matching ordered op:

rot = Gf.Rotation(quat)
angles = rot.Decompose(Gf.Vec3d.XAxis(), Gf.Vec3d.YAxis(), Gf.Vec3d.ZAxis())
xform.AddRotateXYZOp().Set(angles)

Question 2:

It’s definitely possible to do so, but there’s a safe/hard and an easy/dangerous way. The safe way is to do what you’re supposed to within a ChangeBlock, which is to only use the Sdf API to create the attributes and set the values. Creating the attributes isn’t so bad, but setting them is quite a pain (I can’t even remember how to set the xformOpOrders using Python to give you an example right now).

The easy way is to just trust that the Usd API won’t access stale data, which you can potentially avoid by only creating leaf objects and setting them, but it’s at your own risk to do so (especially if you’re in a DCC environment that may not be fully under your own control):

# This works in usdview.
with Sdf.ChangeBlock():
    for i in range(1000):
        op = xformApi.AddTransformOp(opSuffix=f"op{i}")
        op.Set(Gf.Vec3d(i, 0, 0))

Otherwise, your data setup definitely seems pretty complex, and I don’t think I have any immediate suggestions for how you could improve it, at least not without seeing it more closely.

thanks @lbiasco-sie! I wasn’t aware that an orient op exsited which is much easier. And the suggestion with the Sdf.ChangeBlock() using USD Api seems to be working pretty well so far.

Many thanks!