Applying transforms to the model - SLOW

Hello,

I am trying to build an interactive application to render USD models and I have translate/rotate parameters that I want to update in real time.
I apply the transformations to the model like this:

auto modelPrim = m_model->GetDefaultPrim();
// Create rotation matrices using GfRotation and GfMatrix4d
GfRotation rotX(GfVec3d(1.0, 0.0, 0.0), orx);
GfRotation rotY(GfVec3d(0.0, 1.0, 0.0), ory);
GfRotation rotZ(GfVec3d(0.0, 0.0, 1.0), orz);

// Initialize transformation matrices
GfMatrix4d rotXMat;
rotXMat.SetRotate(rotX);

GfMatrix4d rotYMat;
rotYMat.SetRotate(rotY);

GfMatrix4d rotZMat;
rotZMat.SetRotate(rotZ);

// Create translation matrix
GfMatrix4d translateMat;
translateMat.SetTranslate(GfVec3d(opx, opy, opz));

GfMatrix4d lt = rotZMat * rotYMat * rotXMat * translateMat;

UsdGeomXformable xf(modelPrim);

// Clear existing transform ops if necessary
xf.ClearXformOpOrder();

// Add a Transform op
UsdGeomXformOp transformOp = xf.AddTransformOp(UsdGeomXformOp::PrecisionDouble);
transformOp.Set(lt);


m_engine->Render(m_model->GetPseudoRoot(), params);

The problem is that for an average size model this takes SECONDS! It’s super slow and I am not sure why… What’s the correct way of doing this?

Hi @hateom That sounds odd. It should update very fast to set transforms.
I have found that this is invaluable to use the trace api to investigate slowdowns. Universal Scene Description: Trace: Performance tracking

I might be wrong here but Isn’t the Render call just suppose to be setup once in the initialisation face of your program? Perhaps that is the reason it is slow?

Have you tried profiling it to see where the performance impact is greatest? Also just to confirm that you’re using a release/O2 build?

I would not recommend calling ClearXformOpOrder and AddTransformOp on every frame update-- that is probably triggering prim resyncs and blowing various caches. Would set up the transformOp once and update just its value.

If you’re updating multiple transforms per frame, you’ll want to use an SdfChangeBlock to batch the change notifications for all of them - USD-Cookbook/features/sdf_change_block at master · ColinKennedy/USD-Cookbook · GitHub

1 Like

To build on Aaron’s suggestion, you can pay attention to the notices that your edits are triggering.

Resync notices indicate a topology change to the scene.

Changed Info Only notices generally indicate a simple value change and listeners can take a more optimal path.

A simple check to see if you’ve already got a transform op that can be overwritten might also be helpful.

    auto op = geom.GetTransformOp();
    if (op.GetOpType() != UsdGeomXformOp::TypeTransform) {
        geom.ClearXformOpOrder(); // clear the local transform stack
        geom.AddTransformOp().Set(localOffset);
    }
    else {
        op.Set(localOffset, tc);
    }
1 Like

Thanks @nporcino - your code helps a little, but still, when I call op.Set(…), the next m_engine->Render(…) takes ~600ms, where it takes less than 1ms otherwise.
I am testing with the Kitchen Set model.
So I guess it invalidates the cache anyway and some recalculation is happening. Will try to check what happens exactly… but will probably need a different way of doing this.

The main reason I am doing this is that I manually add child prim to the model which is a X/Z plane grid. When I apply transforms to the model I want to be able to translate/rotate the model and keep the X/Z grid in place.

Without the grid I could simply modify the camera matrix passed as argument to the Render function.

Perhaps I need to create a separate grid model and render twice with different camera matrices?

Below the result where grid stays in original position/rotation and the Kitchen scene rotated/translated by some arbitrary values.