Fix USD camera orbit pivot — use scene bbox centroid instead of focus distance

When switching to a USD camera, the orbit pivot was set from
GfCamera::GetFocusDistance() which is a depth-of-field attribute
that defaults to 5 scene units regardless of scene scale.

InitCameraNavigation() now computes the scene bounding box centroid,
projects it onto the camera view ray to get a proper orbit distance,
and calls SetFocalPoint/SetDist to place the pivot correctly.
Added SetDist() setter on ViewportCamera to support this.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 04:46:20 +08:00
parent 8f309e5440
commit ee1b750f8c
2 changed files with 35 additions and 0 deletions
+27
View File
@@ -120,6 +120,33 @@ void ViewportTile::InitCameraNavigation()
pxr::UsdGeomCamera usdCam(prim);
pxr::GfCamera gfCam = usdCam.GetCamera(m_displayTime);
m_camera.SwitchToFreeCamera(&gfCam);
// PullFromCameraTransform() sets m_dist from the USD camera's focus-distance
// attribute, which is a depth-of-field parameter (default 5 scene units) —
// not the distance to scene content. Override both the orbit center and
// distance using the scene bounding box so tumbling pivots on visible geometry.
{
pxr::TfTokenVector purposes = {
pxr::UsdGeomTokens->default_, pxr::UsdGeomTokens->proxy };
pxr::UsdGeomBBoxCache bboxCache(m_displayTime, purposes, true);
pxr::GfBBox3d stageBBox =
bboxCache.ComputeWorldBound(m_stage->GetPseudoRoot());
if (!stageBBox.GetRange().IsEmpty()) {
pxr::GfVec3d sceneCenter = stageBBox.ComputeCentroid();
pxr::GfVec3d camEye = gfCam.GetFrustum().GetPosition();
pxr::GfVec3d viewDir = gfCam.GetFrustum().ComputeViewDirection();
// Project the scene centre onto the view ray to get the orbit
// distance; this keeps the camera at its current position while
// placing the pivot at the closest on-axis approach to the scene.
double dist = pxr::GfDot(sceneCenter - camEye, viewDir);
if (dist > 0.01) {
m_camera.SetFocalPoint(camEye + dist * viewDir);
m_camera.SetDist(dist);
}
}
}
m_isDrivingUsdCamPrim = true;
m_drivenUsdCamPath = camPath;
}