Move camera path code into core and refactor navigation code a bit

This commit is contained in:
Emma Broman
2021-06-21 14:04:21 +02:00
parent 6c50b2a134
commit 77bdfaefd6
73 changed files with 3476 additions and 292 deletions

View File

@@ -1,91 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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___KEYFRAMENAVIGATOR___H__
#define __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__
#include <openspace/util/timeline.h>
#include <openspace/network/messagestructures.h>
#include <ghoul/glm.h>
#include <ghoul/misc/boolean.h>
#include <glm/gtx/quaternion.hpp>
namespace openspace {
class Camera;
class TimeManager;
} // namespace openspace
namespace openspace::interaction {
enum class KeyframeTimeRef {
Relative_applicationStart,
Relative_recordedStart,
Absolute_simTimeJ2000
};
class KeyframeNavigator {
public:
BooleanType(Inclusive);
struct CameraPose {
glm::dvec3 position = glm::dvec3(0.0);
glm::quat rotation = glm::quat(0.f, 0.f, 0.f, 0.f);
std::string focusNode;
float scale = 1.f;
bool followFocusNodeRotation = false;
CameraPose() = default;
CameraPose(datamessagestructures::CameraKeyframe&& kf);
};
/**
* Update camera position using the next camera pose keyframe from the timeline.
* Returns true if camera was set to a pose from the next keyframe.
* Returns false if no keyframes are available after the current time.
* \param camera A reference to the camera object to have its pose updated.
* \param ignoreFutureKeyframes true if only past keyframes are to be used.
* \returns true only if a new future keyframe is available to set camera pose.
*/
bool updateCamera(Camera& camera, bool ignoreFutureKeyframes);
static bool updateCamera(Camera* camera, const CameraPose prevPose,
const CameraPose nextPose, double t, bool ignoreFutureKeyframes);
Timeline<CameraPose>& timeline();
void addKeyframe(double timestamp, KeyframeNavigator::CameraPose pose);
void removeKeyframesAfter(double timestamp, Inclusive inclusive = Inclusive::No);
void clearKeyframes();
size_t nKeyframes() const;
const std::vector<datamessagestructures::CameraKeyframe>& keyframes() const;
double currentTime() const;
void setTimeReferenceMode(KeyframeTimeRef refType, double referenceTimestamp);
private:
Timeline<CameraPose> _cameraPoseTimeline;
KeyframeTimeRef _timeframeMode = KeyframeTimeRef::Relative_applicationStart;
double _referenceTimestamp = 0.0;
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__

View File

@@ -1,177 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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___NAVIGATIONHANDLER___H__
#define __OPENSPACE_CORE___NAVIGATIONHANDLER___H__
#include <openspace/documentation/documentation.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/joystickcamerastates.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/interaction/websocketcamerastates.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/util/mouse.h>
#include <openspace/util/keys.h>
#include <optional>
namespace openspace {
class Camera;
class SceneGraphNode;
} // namespace openspace
namespace openspace::scripting { struct LuaLibrary; }
namespace openspace::interaction {
struct JoystickInputStates;
struct WebsocketInputStates;
class KeyframeNavigator;
class OrbitalNavigator;
class NavigationHandler : public properties::PropertyOwner {
public:
struct NavigationState {
NavigationState() = default;
NavigationState(const ghoul::Dictionary& dictionary);
NavigationState(std::string anchor, std::string aim, std::string referenceFrame,
glm::dvec3 position, std::optional<glm::dvec3> up = std::nullopt,
double yaw = 0.0, double pitch = 0.0);
ghoul::Dictionary dictionary() const;
static documentation::Documentation Documentation();
std::string anchor;
std::string aim;
std::string referenceFrame;
glm::dvec3 position = glm::dvec3(0.0);
std::optional<glm::dvec3> up;
double yaw = 0.0;
double pitch = 0.0;
};
NavigationHandler();
~NavigationHandler();
void initialize();
void deinitialize();
// Mutators
void setFocusNode(SceneGraphNode* node);
void resetCameraDirection();
void setNavigationStateNextFame(NavigationState state);
void setCamera(Camera* camera);
void setInterpolationTime(float durationInSeconds);
void updateCamera(double deltaTime);
void setEnableKeyFrameInteraction();
void setDisableKeyFrameInteraction();
void triggerPlaybackStart();
void stopPlayback();
// Accessors
Camera* camera() const;
const SceneGraphNode* anchorNode() const;
const InputState& inputState() const;
const OrbitalNavigator& orbitalNavigator() const;
OrbitalNavigator& orbitalNavigator();
KeyframeNavigator& keyframeNavigator();
bool isKeyFrameInteractionEnabled() const;
float interpolationTime() const;
// Callback functions
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
void mouseButtonCallback(MouseButton button, MouseAction action);
void mousePositionCallback(double x, double y);
void mouseScrollWheelCallback(double pos);
void setJoystickAxisMapping(int axis, JoystickCameraStates::AxisType mapping,
JoystickCameraStates::AxisInvert shouldInvert =
JoystickCameraStates::AxisInvert::No,
JoystickCameraStates::AxisNormalize shouldNormalize =
JoystickCameraStates::AxisNormalize::No,
bool isSticky = false, double sensitivity = 0.0
);
JoystickCameraStates::AxisInformation joystickAxisMapping(int axis) const;
void setJoystickAxisDeadzone(int axis, float deadzone);
float joystickAxisDeadzone(int axis) const;
void bindJoystickButtonCommand(int button, std::string command, JoystickAction action,
JoystickCameraStates::ButtonCommandRemote remote, std::string documentation);
void clearJoystickButtonCommand(int button);
std::vector<std::string> joystickButtonCommand(int button) const;
// Websockets
void setWebsocketAxisMapping(int axis, WebsocketCameraStates::AxisType mapping,
WebsocketCameraStates::AxisInvert shouldInvert =
WebsocketCameraStates::AxisInvert::No,
WebsocketCameraStates::AxisNormalize shouldNormalize =
WebsocketCameraStates::AxisNormalize::No);
NavigationState navigationState() const;
NavigationState navigationState(const SceneGraphNode& referenceFrame) const;
void saveNavigationState(const std::string& filepath,
const std::string& referenceFrameIdentifier);
void loadNavigationState(const std::string& filepath);
void setNavigationStateNextFrame(NavigationState state);
/**
* \return The Lua library that contains all Lua functions available to affect the
* interaction
*/
static scripting::LuaLibrary luaLibrary();
private:
void applyNavigationState(const NavigationHandler::NavigationState& ns);
bool _playbackModeEnabled = false;
InputState _inputState;
Camera* _camera = nullptr;
std::function<void()> _playbackEndCallback;
OrbitalNavigator _orbitalNavigator;
KeyframeNavigator _keyframeNavigator;
std::optional<NavigationState> _pendingNavigationState;
properties::BoolProperty _disableMouseInputs;
properties::BoolProperty _disableJoystickInputs;
properties::BoolProperty _useKeyFrameInteraction;
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___NAVIGATIONHANDLER___H__

View File

@@ -1,339 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* 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 <openspace/properties/propertyowner.h>
#include <openspace/interaction/delayedvariable.h>
#include <openspace/interaction/interpolator.h>
#include <openspace/interaction/joystickcamerastates.h>
#include <openspace/interaction/mousecamerastates.h>
#include <openspace/interaction/scriptcamerastates.h>
#include <openspace/interaction/websocketcamerastates.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/properties/scalar/doubleproperty.h>
#include <openspace/properties/triggerproperty.h>
#include <ghoul/glm.h>
#include <glm/gtx/quaternion.hpp>
#include <optional>
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);
void resetVelocities();
Camera* camera() const;
void setCamera(Camera* camera);
void clearPreviousState();
void setFocusNode(const SceneGraphNode* focusNode,
bool resetVelocitiesOnChange = true);
void setFocusNode(const std::string& focusNode, bool resetVelocitiesOnChange = true);
void setAnchorNode(const std::string& anchorNode);
void setAimNode(const std::string& aimNode);
void startRetargetAnchor();
void startRetargetAim();
float retargetInterpolationTime() const;
void setRetargetInterpolationTime(float durationInSeconds);
void resetNodeMovements();
JoystickCameraStates& joystickStates();
const JoystickCameraStates& joystickStates() const;
WebsocketCameraStates& websocketStates();
const WebsocketCameraStates& websocketStates() const;
ScriptCameraStates& scriptStates();
const ScriptCameraStates& scriptStates() const;
bool shouldFollowAnchorRotation(const glm::dvec3& cameraPosition) const;
bool followingAnchorRotation() 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(1.0, 0.0, 0.0, 0.0);
glm::dquat globalRotation = glm::dquat(1.0, 0.0, 0.0, 0.0);
};
struct CameraPose {
glm::dvec3 position = glm::dvec3(0.0);
glm::dquat rotation = glm::dquat(1.0, 0.0, 0.0, 0.0);
};
using Displacement = std::pair<glm::dvec3, glm::dvec3>;
struct Friction : public properties::PropertyOwner {
Friction();
properties::BoolProperty roll;
properties::BoolProperty rotational;
properties::BoolProperty zoom;
properties::FloatProperty friction;
};
void setAnchorNode(const SceneGraphNode* anchorNode,
bool resetVelocitiesOnChange = true);
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 _flightDestinationDistance;
properties::DoubleProperty _flightDestinationFactor;
properties::BoolProperty _applyLinearFlight;
properties::FloatProperty _velocitySensitivity;
properties::FloatProperty _mouseSensitivity;
properties::FloatProperty _joystickSensitivity;
properties::FloatProperty _websocketSensitivity;
properties::BoolProperty _useAdaptiveStereoscopicDepth;
properties::FloatProperty _stereoscopicDepthOfFocusSurface;
properties::FloatProperty _staticViewScaleExponent;
properties::FloatProperty _retargetInterpolationTime;
properties::FloatProperty _stereoInterpolationTime;
properties::FloatProperty _followRotationInterpolationTime;
properties::BoolProperty _invertMouseButtons;
MouseCameraStates _mouseStates;
JoystickCameraStates _joystickStates;
WebsocketCameraStates _websocketStates;
ScriptCameraStates _scriptStates;
const SceneGraphNode* _anchorNode = nullptr;
const SceneGraphNode* _aimNode = nullptr;
std::optional<glm::dvec3>_previousAnchorNodePosition;
std::optional<glm::dquat> _previousAnchorNodeRotation;
std::optional<glm::dvec3> _previousAimNodePosition;
double _currentCameraToSurfaceDistance = 0.0;
bool _directlySetStereoDistance = false;
Interpolator<double> _retargetAimInterpolator;
Interpolator<double> _retargetAnchorInterpolator;
Interpolator<double> _cameraToSurfaceDistanceInterpolator;
Interpolator<double> _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
* <code>cameraRotation = globalRotation * localRotation</code>.
*/
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 <code>cameraRotation = globalRotation * localRotation</code>.
*/
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.
*
* \return 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;
/**
* Moves the camera along a vector, camPosToCenterPosDiff, until it reaches the
* focusLimit. The velocity of the zooming depend on distFromCameraToFocus and the
* final frame where the camera stops moving depends on the distance set in the
* variable focusLimit. The bool determines whether to move/fly towards the focus node
* or away from it.
*
* \return a new position of the camera, closer to the focusLimit than the previous
* position
*/
glm::dvec3 moveCameraAlongVector(const glm::dvec3& camPos,
double distFromCameraToFocus, const glm::dvec3& camPosToCenterPosDiff,
double destination, double deltaTime) const;
/*
* Adds rotation to the camera position so that it follows the rotation of the anchor
* node defined by the differential anchorNodeRotationDiff.
*
* \return 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.
*
* \return 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.
*
* \return 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.
*
* \return 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::dvec3 cameraPosition, const glm::dquat& rotationDiff);
/**
* 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__

View File

@@ -26,7 +26,7 @@
#define __OPENSPACE_CORE___SESSIONRECORDING___H__
#include <openspace/interaction/externinteraction.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/navigation/keyframenavigator.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/scripting/lualibrary.h>
#include <vector>