Transform Prim When Switching Camera?

Hi all,

I’m pretty new to USD and am wondering how to transform my prim so that no matter which camera I switch to, my object of interest is always centered and scaled to fit inside the scene?

Right now my process is:

  • Make a stage
  • Reference a Geometry to it
  • Set up a camera (Mostly default except for a custom horiz/vert aperture, focus distance, and z-translation)
  • Find the bounding box of my geometry as well as the world coordinates of my camera
  • Set the horizontal and vertical translation of my geometry to match the camera
  • Scale the geometry by the minimum between either the horizontal viewport size divided by the bounding box width or the vertical viewport size divided by the bounding box height.

On paper this should work but I could very well be doing things wrong. Here’s the code

def MakeInitialStage(path):
    stage = Usd.Stage.CreateNew(path)
    UsdGeom.SetStageUpAxis(stage, UsdGeom.Tokens.z)
    top = AddReferenceToGeometry(stage, "/Top")
    return stage

def AddReferenceToGeometry(stage, new_prim, reference_path='top.geom.usd'):
    geom = UsdGeom.Xform.Define(stage, new_prim)
    return geom

def CameraInit(stage, aperture, distance, camPath="/Camera"):

    # Create the initial camera
    camera = UsdGeom.Camera.Define(stage, camPath)
    camXForm = UsdGeom.Xformable(camera)
    # Distance between camera and object of interest

    # Set the initial transform of the camera

    # Center the camera about the origin at the given distance

    # Set the "resolution" of the camera

    return camera.GetPrim().GetPrimPath(), camera

def PrepScene(stage, scenePath, camera, imgSize, background=None, backgroundPath=None):

    # Get the scene and make it transformable
    scene = UsdGeom.Xform(stage.GetPrimAtPath(scenePath))

    # Get the size of the scene
    bbox = scene.ComputeWorldBound(0, UsdGeom.Tokens.default_).GetBox()
    bboxSize = bbox.GetSize()

    # Get the necessary properties from the camera
    camXForm = UsdGeom.Xformable(camera)
    transform = Gf.Transform()

    # Find the location of the camera in the world frame
    camPos = transform.GetTranslation()

    # Scale and translate the scene to be centered in the camera
    scaleFactor = min(imgSize[0] / bboxSize[1], imgSize[1] / bboxSize[0])
    scene.AddScaleOp().Set(Gf.Vec3f(scaleFactor, scaleFactor, scaleFactor))
    scene.AddTranslateOp().Set(Gf.Vec3f(camPos[2], 0, camPos[1]))

    # If a background is included, center and scale it as well
    if backgroundPath != None:
        backgroundScale = scaleFactor * 1000

        background = UsdGeom.Xform(stage.GetPrimAtPath(backgroundPath))
        background.AddScaleOp().Set(Gf.Vec3f(backgroundScale, backgroundScale, backgroundScale))
        background.AddTranslateOp().Set(Gf.Vec3f(camPos[0], 0, camPos[2]))


stage = MakeInitialStage("Test.usda")
camera = CameraInit(stage, [20.955,15.2908], 30 * 1000 / 64)[1]
PrepScene(stage, "/Top", camera, [800,600])

For reference, the geometry I’m using is the spinning top file found in the tutorial

Out of curiosity, why are you translating your scene ? If it’s centered and scaled for one camera, it wouldn’t be for the others, and mass modifying an entire scene hierarchy is fairly expensive .

It seems like it would be more efficient to just move the cameras to frame your scene instead, but I’m probably not understanding the problem at hand.

Hi Dhruv,

Thanks for the quick reply! So for the needs of the project we have essentially a single object and we want to control the single camera (put it in different places, move it in an arc, etc.) around the object. I may have a background which would need to scale accordingly but thats a secondary issue. We would like to simply set the scale and translation of the object so that no matter where I were to define a camera, the object would be scaled and centred accordingly. We can assume (at least for now) that there will only be a single camera.