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