diff --git a/include/openspace/navigation/orbitalnavigator.h b/include/openspace/navigation/orbitalnavigator.h index 96e48d2ccf..5093677481 100644 --- a/include/openspace/navigation/orbitalnavigator.h +++ b/include/openspace/navigation/orbitalnavigator.h @@ -182,7 +182,8 @@ private: struct IdleBehavior : public properties::PropertyOwner { enum Behavior { - Orbit = 0 + Orbit = 0, + OrbitAtConstantLat }; IdleBehavior(); @@ -351,11 +352,21 @@ private: glm::dquat& localRotation, glm::dquat& globalRotation); /** + * IdleBehavior::Behavior::Orbit * Orbit the current anchor node, in a right-bound orbit, by updating the position * and global rotation of the camera */ void orbitAnchor(double deltaTime, glm::dvec3& position, glm::dquat& globalRotation, double speedScale); + + /** + * IdleBehavior::Behavior::OrbitAtConstantLat + * Orbit the current anchor node, but stay on the current latitude band. Note that + * this creates a rolling motion if looking at any of the anchor's poles, and should + * be used with care + */ + void orbitAtConstantLatitude(double deltaTime, glm::dvec3& position, + glm::dquat& globalRotation, double speedScale); }; } // namespace openspace::interaction diff --git a/src/navigation/orbitalnavigator.cpp b/src/navigation/orbitalnavigator.cpp index c574ed8d84..0021966261 100644 --- a/src/navigation/orbitalnavigator.cpp +++ b/src/navigation/orbitalnavigator.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -277,7 +278,8 @@ OrbitalNavigator::IdleBehavior::IdleBehavior() { addProperty(apply); chosenBehavior.addOptions({ - { IdleBehavior::Behavior::Orbit, "Orbit" } + { IdleBehavior::Behavior::Orbit, "Orbit" }, + { IdleBehavior::Behavior::OrbitAtConstantLat, "OrbitAtConstantLatitude" } }); chosenBehavior = IdleBehavior::Behavior::Orbit; addProperty(chosenBehavior); @@ -1174,7 +1176,6 @@ OrbitalNavigator::interpolateRetargetAim(double deltaTime, CameraPose pose, glm::dvec3 prevCameraToAnchor, Displacement anchorToAim) { - if (_retargetAimInterpolator.isInterpolating()) { double t = _retargetAimInterpolator.value(); _retargetAimInterpolator.setDeltaTime(static_cast(deltaTime)); @@ -1547,6 +1548,9 @@ void OrbitalNavigator::applyIdleBehavior(double deltaTime, glm::dvec3& position, case IdleBehavior::Behavior::Orbit: orbitAnchor(deltaTime, position, globalRotation, speedScale); break; + case IdleBehavior::Behavior::OrbitAtConstantLat: + orbitAtConstantLatitude(deltaTime, position, globalRotation, speedScale); + break; default: throw ghoul::MissingCaseException(); } @@ -1570,10 +1574,40 @@ void OrbitalNavigator::orbitAnchor(double deltaTime, glm::dvec3& position, // Rotate to find the difference in position const glm::dvec3 anchorCenterToCamera = position - _anchorNode->worldPosition(); const glm::dvec3 rotationDiffVec3 = - anchorCenterToCamera * rotationDiffWorldSpace - - anchorCenterToCamera; + anchorCenterToCamera * rotationDiffWorldSpace - anchorCenterToCamera; position += rotationDiffVec3; } +void OrbitalNavigator::orbitAtConstantLatitude(double deltaTime, glm::dvec3& position, + glm::dquat& globalRotation, + double speedScale) +{ + ghoul_assert(_anchorNode != nullptr, "Node to orbit must be set!"); + + const glm::dmat4 modelTransform = _anchorNode->modelTransform(); + + // Assume north coincides with the local z-direction + // @TODO (2021-07-09, emmbr) Make each scene graph node aware of its own north/up, so + // that we can query this information rather than assuming it + const glm::dvec3 northInWorldCoords = + glm::dmat3(modelTransform) * glm::dvec3(0.0, 0.0, 1.0); + + // Compute rotation around the north axis to be applied + double angle = deltaTime * speedScale; + const glm::dquat spinRotation = + glm::angleAxis(angle, glm::normalize(northInWorldCoords)); + + // Rotate the position vector from the center to camera and update position + const glm::dvec3 anchorCenterToCamera = position - _anchorNode->worldPosition(); + const glm::dvec3 rotationDiffVec3 = + spinRotation * anchorCenterToCamera - anchorCenterToCamera; + + position += rotationDiffVec3; + + // Also apply the rotation to the global rotation, so the camera up vector is + // rotated around the axis as well + globalRotation = spinRotation * globalRotation; +} + } // namespace openspace::interaction