/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2019 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #ifndef __OPENSPACE_CORE___ORBITALNAVIGATOR___H__ #define __OPENSPACE_CORE___ORBITALNAVIGATOR___H__ #include #include #include #include #include #include #include #include #include #include #include namespace openspace { class SceneGraphNode; class Camera; struct SurfacePositionHandle; } // namespace namespace openspace::interaction { class InputState; class OrbitalNavigator : public properties::PropertyOwner { public: OrbitalNavigator(); void updateStatesFromInput(const InputState& inputState, double deltaTime); void updateCameraStateFromStates(double deltaTime); Camera* camera() const; void setCamera(Camera* camera); void setFocusNode(const std::string& focusNode); void setAnchorNode(const std::string& anchorNode); void setAimNode(const std::string& aimNode); void startRetargetAnchor(); void startRetargetAim(); float retargetInterpolationTime() const; void setRetargetInterpolationTime(float durationInSeconds); JoystickCameraStates& joystickStates(); bool followingNodeRotation() const; const SceneGraphNode* anchorNode() const; const SceneGraphNode* aimNode() const; bool hasRotationalFriction() const; bool hasZoomFriction() const; bool hasRollFriction() const; glm::dvec3 anchorNodeToCameraVector() const; glm::quat anchorNodeToCameraRotation() const; private: struct CameraRotationDecomposition { glm::dquat localRotation; glm::dquat globalRotation; }; struct CameraPose { glm::dvec3 position; glm::dquat rotation; }; using Displacement = std::pair; struct Friction : public properties::PropertyOwner { Friction(); properties::BoolProperty roll; properties::BoolProperty rotational; properties::BoolProperty zoom; properties::FloatProperty friction; }; void setFocusNode(const SceneGraphNode* focusNode); void setAnchorNode(const SceneGraphNode* anchorNode); void setAimNode(const SceneGraphNode* aimNode); Camera* _camera; Friction _friction; // Anchor: Node to follow and orbit. properties::StringProperty _anchor; // Aim: Node to look at (when camera direction is reset), // Empty string means same as anchor. // If these are the same node we call it the `focus` node. properties::StringProperty _aim; // Reset camera direction to the anchor node. properties::TriggerProperty _retargetAnchor; // Reset camera direction to the aim node. properties::TriggerProperty _retargetAim; properties::FloatProperty _followAnchorNodeRotationDistance; properties::FloatProperty _minimumAllowedDistance; properties::FloatProperty _mouseSensitivity; properties::FloatProperty _joystickSensitivity; properties::BoolProperty _useAdaptiveStereoscopicDepth; properties::FloatProperty _stereoscopicDepthOfFocusSurface; properties::FloatProperty _staticViewScaleExponent; properties::FloatProperty _retargetInterpolationTime; properties::FloatProperty _stereoInterpolationTime; properties::FloatProperty _followRotationInterpolationTime; MouseCameraStates _mouseStates; JoystickCameraStates _joystickStates; const SceneGraphNode* _anchorNode = nullptr; const SceneGraphNode* _aimNode = nullptr; glm::dvec3 _previousAnchorNodePosition; glm::dquat _previousAnchorNodeRotation; glm::dvec3 _previousAimNodePosition; glm::dquat _previousAimNodeRotation; double _currentCameraToSurfaceDistance = 0.0; bool _directlySetStereoDistance = false; Interpolator _retargetAimInterpolator; Interpolator _retargetAnchorInterpolator; Interpolator _cameraToSurfaceDistanceInterpolator; Interpolator _followRotationInterpolator; /** * Decomposes the camera's rotation in to a global and a local rotation defined by * CameraRotationDecomposition. The global rotation defines the rotation so that the * camera points towards the reference node in the direction opposite to the direction * out from the surface of the object. The local rotation defines the differential * from the global to the current total rotation so that * cameraRotation = globalRotation * localRotation. */ CameraRotationDecomposition decomposeCameraRotationSurface(const CameraPose pose, const SceneGraphNode& reference); /** * Decomposes the camera's rotation in to a global and a local rotation defined by * CameraRotationDecomposition. The global rotation defines the rotation so that the * camera points towards the reference node's origin. * The local rotation defines the differential from the global to the current total * rotation so that cameraRotation = globalRotation * localRotation. */ CameraRotationDecomposition decomposeCameraRotation(const CameraPose pose, glm::dvec3 reference); /** * Composes a pair of global and local rotations into a quaternion that can be used * as the world rotation for a camera. */ glm::dquat composeCameraRotation(const CameraRotationDecomposition& composition); /* * Moves and rotates the camera around the anchor node in order to maintain the * screen space position of the aim node. Also interpolates to the aim node, when * retargeting the aim. */ CameraPose followAim(CameraPose pose, glm::dvec3 cameraToAnchor, Displacement anchorToAim); /* * Perform a camera roll on the local camera rotation * \returns a local camera rotation modified with a roll. */ glm::dquat roll(double deltaTime, const glm::dquat& localCameraRotation) const; /** * Performs rotation around the cameras x and y axes. * \returns a local camera rotation modified with two degrees of freedom. */ glm::dquat rotateLocally(double deltaTime, const glm::dquat& localCameraRotation) const; /** * Interpolates the camera rotation based on active interpolators. * \returns a new rotation quaternion */ glm::dquat interpolateLocalRotation(double deltaTime, const glm::dquat& localCameraRotation); Displacement interpolateRetargetAim(double deltaTime, CameraPose pose, glm::dvec3 cameraToAnchor, Displacement anchorToAim); double interpolateCameraToSurfaceDistance(double deltaTime, double currentDistance, double targetDistance); /** * Translates the horizontal direction. If far from the anchor object, this will * result in an orbital rotation around the object. This function does not affect the * rotation but only the position. * \returns a position vector adjusted in the horizontal direction. */ glm::dvec3 translateHorizontally(double deltaTime, const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition, const glm::dquat& globalCameraRotation, const SurfacePositionHandle& positionHandle) const; /* * Adds rotation to the camera position so that it follows the rotation of the anchor * node defined by the differential anchorNodeRotationDiff. * \returns a position updated with the rotation defined by anchorNodeRotationDiff */ glm::dvec3 followAnchorNodeRotation(const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition, const glm::dquat& anchorNodeRotationDiff) const; /** * Updates the global rotation so that it points towards the anchor node. * \returns a global rotation quaternion defining a rotation towards the anchor node. */ glm::dquat rotateGlobally(const glm::dquat& globalCameraRotation, const glm::dquat& aimNodeRotationDiff, const SurfacePositionHandle& positionHandle) const; /** * Translates the camera position towards or away from the anchor node. * \returns a position vector adjusted in the vertical direction. */ glm::dvec3 translateVertically(double deltaTime, const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition, const SurfacePositionHandle& positionHandle) const; /** * Rotates the camera around the out vector of the surface. * \returns a quaternion adjusted to rotate around the out vector of the surface. */ glm::dquat rotateHorizontally(double deltaTime, const glm::dquat& globalCameraRotation, const SurfacePositionHandle& positionHandle) const; /** * Push the camera out to the surface of the object. * \returns a position vector adjusted to be at least minHeightAboveGround meters * above the actual surface of the object */ glm::dvec3 pushToSurface(double minHeightAboveGround, const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition, const SurfacePositionHandle& positionHandle) const; /** * Interpolates between rotationDiff and a 0 rotation. */ glm::dquat interpolateRotationDifferential(double deltaTime, double interpolationTime, const glm::dquat& rotationDiff, const glm::dvec3& objectPosition, const glm::dvec3& cameraPosition, const SurfacePositionHandle& positionHandle); /** * Get the vector from the camera to the surface of the anchor object in world space. */ glm::dvec3 cameraToSurfaceVector(const glm::dvec3& cameraPos, const glm::dvec3& centerPos, const SurfacePositionHandle& posHandle); /** * Calculates a SurfacePositionHandle given a camera position in world space. */ SurfacePositionHandle calculateSurfacePositionHandle(const SceneGraphNode& node, const glm::dvec3 cameraPositionWorldSpace); }; } // namespace openspace::interaction #endif // __OPENSPACE_CORE___ORBITALNAVIGATOR___H__