#pragma once #include #include #include #include #include #include #include #include #include namespace UsdLayerManager { /// Free camera ported from Pixar's usdview FreeCamera (freeCamera.py). /// Supports Tumble/Truck/AdjustDistance with Z-up stage handling, /// automatic near/far clipping plane computation from scene bbox, /// and USD prim-camera passthrough mode. class ViewportCamera { public: enum class CameraMode { Free, UsdCamera }; static constexpr double kDefaultNear = 1.0; static constexpr double kDefaultFar = 2000000.0; static constexpr double kMaxSafeZResolution = 1e6; static constexpr double kMaxGoodZResolution = 5e4; ViewportCamera(); // ----------------------------------------------------------------------- // Stage (sets Z-up flag and YZUp matrices) // ----------------------------------------------------------------------- void SetStage(pxr::UsdStageRefPtr stage); // ----------------------------------------------------------------------- // Free Camera Operations (mirrors FreeCamera.py) // ----------------------------------------------------------------------- /// Orbit (tumble) around center by dTheta (horizontal) and dPhi (vertical) degrees. void Tumble(double dTheta, double dPhi); /// Scale distance from center by scaleFactor. Prevents getting stuck near zero. void AdjustDistance(double scaleFactor); /// Pan (truck) in camera-local right/up directions, world-unit deltas. void Truck(double deltaRight, double deltaUp); /// Returns pixels-to-world factor for correct Truck() scaling. double ComputePixelsToWorldFactor(double viewportHeight); /// Frame a bounding box. frameFit=1.1 gives ~10% margin (usdview default). void FrameSelection(const pxr::GfBBox3d& selBBox, double frameFit = 1.1); // ----------------------------------------------------------------------- // Camera Resolution: returns GfCamera with updated transform + clipping // ----------------------------------------------------------------------- /// Returns the GfCamera with up-to-date transform. /// If autoClip=true, near/far are computed from stageBBox for best precision. pxr::GfCamera ComputeGfCamera(const pxr::GfBBox3d& stageBBox, bool autoClip = false); // ----------------------------------------------------------------------- // Convenience Matrix Accessors // ----------------------------------------------------------------------- pxr::GfMatrix4d GetViewMatrix(); pxr::GfMatrix4d GetProjectionMatrix(); // ----------------------------------------------------------------------- // Camera Mode // ----------------------------------------------------------------------- CameraMode GetMode() const { return m_mode; } const pxr::SdfPath& GetUsdCameraPath() const { return m_usdCameraPath; } /// Switch to USD prim camera mode (renderer will call SetCameraPath). void SetUsdCamera(const pxr::SdfPath& cameraPath); /// Switch back to free camera, optionally initializing state from lastGfCamera. void SwitchToFreeCamera(const pxr::GfCamera* lastGfCamera = nullptr); // ----------------------------------------------------------------------- // Camera Settings // ----------------------------------------------------------------------- double GetFOV() const; ///< Vertical FOV in degrees void SetFOV(double fov); double GetAspectRatio() const; void SetAspectRatio(double aspect); /// Hint for autoClip: the closest visible geometry point from pick result. void SetClosestVisibleDistFromPoint(const pxr::GfVec3d& point); // ----------------------------------------------------------------------- // State Queries // ----------------------------------------------------------------------- double GetDist() const { return m_dist; } bool IsZUp() const { return m_isZUp; } // ----------------------------------------------------------------------- // Compatibility accessors (for tests and legacy callers) // ----------------------------------------------------------------------- /// Returns camera position in world space. pxr::GfVec3d GetEye(); /// Returns the look-at focal point (center of orbit). const pxr::GfVec3d& GetFocalPoint() const { return m_center; } /// Set the look-at focal point directly. /// Used by orthographic view panning to move the center in correct /// view-space directions without going through the perspective Truck() path. void SetFocalPoint(const pxr::GfVec3d& center) { m_center = center; 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; } /// Set orbital state from eye position and orbit center without Euler decomposition. /// Computes theta/phi directly from the eye→center vector in the Y-up orbital frame; /// zeroes roll. Use this after SwitchToFreeCamera() when initialising from a USD /// camera prim to avoid gimbal-lock artifacts from the Decompose() path. void InitOrbitFromEyeAndCenter(const pxr::GfVec3d& eye, const pxr::GfVec3d& center, double dist); /// Returns the current near-clip distance. double GetNearClip() const { return static_cast(m_camera.GetClippingRange().GetMin()); } /// Returns the current far-clip distance. double GetFarClip() const { return static_cast(m_camera.GetClippingRange().GetMax()); } /// Legacy: frame a GfRange3d (wraps it in a unit-matrix GfBBox3d). void FrameBoundingBox(const pxr::GfRange3d& range, double frameFit = 1.1) { FrameSelection(pxr::GfBBox3d(range), frameFit); } /// Legacy: orbit alias (matches old Orbit(deltaYaw, deltaPitch) signature). void Orbit(double deltaYaw, double deltaPitch) { Tumble(deltaYaw, deltaPitch); } private: void PushToCameraTransform(); void PullFromCameraTransform(); void SetClippingPlanes(const pxr::GfBBox3d& stageBBox); void ResetClippingPlanes(); std::pair RangeOfBoxAlongRay( const pxr::GfRay& camRay, const pxr::GfBBox3d& bbox) const; // Core camera object (owns aperture/projection/clipping/transform state) pxr::GfCamera m_camera; bool m_cameraTransformDirty; // Orbital / tumble state double m_rotTheta; // horizontal orbit (degrees, around Y) double m_rotPhi; // vertical orbit (degrees, around X) double m_rotPsi; // roll (degrees, usually 0) pxr::GfVec3d m_center; // look-at center in world space double m_dist; // distance camera → center double m_selSize; // extent of last framed selection // Stage up-axis handling bool m_isZUp; pxr::GfMatrix4d m_YZUpMatrix; // Y-up → Z-up (rotate -90° around X) pxr::GfMatrix4d m_YZUpInvMatrix; // Z-up → Y-up (inverse) // Auto-clip state bool m_hasClosestVisibleDist; double m_closestVisibleDist; double m_lastFramedDist; double m_lastFramedClosestDist; double m_overrideNear; // ≤0 means "no override" double m_overrideFar; // ≤0 means "no override" // Camera mode CameraMode m_mode; pxr::SdfPath m_usdCameraPath; pxr::UsdStageRefPtr m_stage; }; } // namespace UsdLayerManager