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:
@@ -113,6 +113,14 @@ public:
|
|||||||
m_cameraTransformDirty = true;
|
m_cameraTransformDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the orbit distance directly.
|
||||||
|
/// Used when initialising from a USD camera prim to override the camera's
|
||||||
|
/// authored focus distance (which is a DOF attribute, not an orbit radius).
|
||||||
|
void SetDist(double d) {
|
||||||
|
m_dist = d;
|
||||||
|
m_cameraTransformDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the current near-clip distance.
|
/// Returns the current near-clip distance.
|
||||||
double GetNearClip() const {
|
double GetNearClip() const {
|
||||||
return static_cast<double>(m_camera.GetClippingRange().GetMin());
|
return static_cast<double>(m_camera.GetClippingRange().GetMin());
|
||||||
|
|||||||
@@ -120,6 +120,33 @@ void ViewportTile::InitCameraNavigation()
|
|||||||
pxr::UsdGeomCamera usdCam(prim);
|
pxr::UsdGeomCamera usdCam(prim);
|
||||||
pxr::GfCamera gfCam = usdCam.GetCamera(m_displayTime);
|
pxr::GfCamera gfCam = usdCam.GetCamera(m_displayTime);
|
||||||
m_camera.SwitchToFreeCamera(&gfCam);
|
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_isDrivingUsdCamPrim = true;
|
||||||
m_drivenUsdCamPath = camPath;
|
m_drivenUsdCamPath = camPath;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user