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)
    stage.SetStartTimeCode(1)
    stage.SetEndTimeCode(192)
    top = AddReferenceToGeometry(stage, "/Top")
    return stage


def AddReferenceToGeometry(stage, new_prim, reference_path='top.geom.usd'):
    geom = UsdGeom.Xform.Define(stage, new_prim)
    geom.GetPrim().GetReferences().AddReference(reference_path)
    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
    camera.CreateFocusDistanceAttr().Set(0)
    camera.CreateHorizontalApertureAttr().Set(0)
    camera.CreateVerticalApertureAttr().Set(0)

    # Set the initial transform of the camera
    camXForm.ClearXformOpOrder()
    camXForm.AddRotateXOp().Set(90)
    camXForm.AddTranslateOp().Set(Gf.Vec3f(0,0,distance))

    # Center the camera about the origin at the given distance
    camera.GetFocusDistanceAttr().Set(distance)

    # Set the "resolution" of the camera
    camera.GetHorizontalApertureAttr().Set(aperture[0])
    camera.GetVerticalApertureAttr().Set(aperture[1])

    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
    transform.SetMatrix(
        camXForm.ComputeLocalToWorldTransform(Usd.TimeCode.Default()))
    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.Save()
    return

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.

Thanks!