mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-20 03:49:31 -06:00
Move StopBehavior to OrbitalNavigator and rename to IdleBehavior
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
#include <openspace/interaction/mousecamerastates.h>
|
||||
#include <openspace/interaction/scriptcamerastates.h>
|
||||
#include <openspace/interaction/websocketcamerastates.h>
|
||||
#include <openspace/properties/optionproperty.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
@@ -56,6 +57,10 @@ class InputState;
|
||||
|
||||
class OrbitalNavigator : public properties::PropertyOwner {
|
||||
public:
|
||||
enum IdleBehavior {
|
||||
Orbit = 0
|
||||
};
|
||||
|
||||
OrbitalNavigator();
|
||||
|
||||
void updateStatesFromInput(const InputState& inputState, double deltaTime);
|
||||
@@ -144,6 +149,9 @@ private:
|
||||
properties::DoubleProperty _flightDestinationFactor;
|
||||
properties::BoolProperty _applyLinearFlight;
|
||||
|
||||
properties::BoolProperty _applyIdleBehavior;
|
||||
properties::OptionProperty _idleBehavior;
|
||||
|
||||
properties::FloatProperty _velocitySensitivity;
|
||||
properties::FloatProperty _mouseSensitivity;
|
||||
properties::FloatProperty _joystickSensitivity;
|
||||
@@ -193,7 +201,7 @@ private:
|
||||
/**
|
||||
* 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.
|
||||
* camera points towards the reference position.
|
||||
* The local rotation defines the differential from the global to the current total
|
||||
* rotation so that <code>cameraRotation = globalRotation * localRotation</code>.
|
||||
*/
|
||||
@@ -328,6 +336,21 @@ private:
|
||||
*/
|
||||
SurfacePositionHandle calculateSurfacePositionHandle(const SceneGraphNode& node,
|
||||
const glm::dvec3 cameraPositionWorldSpace);
|
||||
|
||||
/**
|
||||
* IdleBehavior
|
||||
* Apply the currently selected idle behavior to the position and rotations
|
||||
*/
|
||||
void applyIdleBehavior(double deltaTime, glm::dvec3& position,
|
||||
glm::dquat& localRotation, glm::dquat& globalRotation);
|
||||
|
||||
/**
|
||||
* IdleBehavior
|
||||
* 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);
|
||||
};
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
@@ -50,11 +50,6 @@ class Path;
|
||||
|
||||
class PathNavigator : public properties::PropertyOwner {
|
||||
public:
|
||||
enum StopBehavior {
|
||||
None = 0,
|
||||
Orbit
|
||||
};
|
||||
|
||||
PathNavigator();
|
||||
~PathNavigator();
|
||||
|
||||
@@ -86,12 +81,12 @@ public:
|
||||
static scripting::LuaLibrary luaLibrary();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Populate list of nodes that are relevant for collision checks, etc
|
||||
*/
|
||||
void findRelevantNodes();
|
||||
|
||||
void removeRollRotation(CameraPose& pose, double deltaTime);
|
||||
void applyStopBehavior(double deltaTime);
|
||||
|
||||
void orbitAnchorNode(double deltaTime);
|
||||
|
||||
std::unique_ptr<Path> _currentPath = nullptr;
|
||||
bool _isPlaying = false;
|
||||
@@ -99,11 +94,6 @@ private:
|
||||
properties::OptionProperty _defaultCurveOption;
|
||||
properties::BoolProperty _includeRoll;
|
||||
properties::FloatProperty _speedScale;
|
||||
properties::FloatProperty _orbitSpeedFactor;
|
||||
|
||||
properties::BoolProperty _applyStopBehaviorWhenIdle;
|
||||
properties::OptionProperty _stopBehavior;
|
||||
|
||||
properties::DoubleProperty _minValidBoundingSphere;
|
||||
properties::StringListProperty _relevantNodeTags;
|
||||
|
||||
|
||||
@@ -152,6 +152,20 @@ namespace {
|
||||
"'FlightDestinationDistance' while facing the anchor"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo ApplyIdleBehaviorInfo = {
|
||||
"ApplyIdleBehavior",
|
||||
"Apply Idle Behavior",
|
||||
"When set to true, the chosen idle behavior will be applied to the camera, "
|
||||
"moving the camera accordingly. "
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo IdleBehaviorInfo = {
|
||||
"IdleBehvaior",
|
||||
"Idle Behavior",
|
||||
"The chosen camera behavior that will be applied when 'ApplyIdleBehavior' is "
|
||||
"set to true. Each option represents a predefined camera behavior."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo FlightDestinationDistInfo = {
|
||||
"FlightDestinationDistance",
|
||||
"Flight Destination Distance",
|
||||
@@ -250,6 +264,8 @@ OrbitalNavigator::OrbitalNavigator()
|
||||
, _flightDestinationDistance(FlightDestinationDistInfo, 2e8f, 10.f, 1e10f)
|
||||
, _flightDestinationFactor(FlightDestinationFactorInfo, 1E-4, 1E-6, 0.5, 1E-3)
|
||||
, _applyLinearFlight(ApplyLinearFlightInfo, false)
|
||||
, _applyIdleBehavior(ApplyIdleBehaviorInfo, false)
|
||||
, _idleBehavior(IdleBehaviorInfo)
|
||||
, _velocitySensitivity(VelocityZoomControlInfo, 3.5f, 0.001f, 20.f)
|
||||
, _mouseSensitivity(MouseSensitivityInfo, 15.f, 1.f, 50.f)
|
||||
, _joystickSensitivity(JoystickSensitivityInfo, 10.f, 1.0f, 50.f)
|
||||
@@ -388,6 +404,14 @@ OrbitalNavigator::OrbitalNavigator()
|
||||
addProperty(_flightDestinationFactor);
|
||||
addProperty(_applyLinearFlight);
|
||||
|
||||
addProperty(_applyIdleBehavior);
|
||||
|
||||
_idleBehavior.addOptions({
|
||||
{ IdleBehavior::Orbit, "Orbit" }
|
||||
});
|
||||
_idleBehavior = IdleBehavior::Orbit;
|
||||
addProperty(_idleBehavior);
|
||||
|
||||
addProperty(_useAdaptiveStereoscopicDepth);
|
||||
addProperty(_staticViewScaleExponent);
|
||||
_stereoscopicDepthOfFocusSurface.setExponent(3.f);
|
||||
@@ -569,6 +593,18 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) {
|
||||
posHandle
|
||||
);
|
||||
|
||||
// Apply any automatic idle behavior. Note that the idle behavior is aborted if there
|
||||
// is no input from interaction. So, it assumes that all the previous effects from
|
||||
// user input resulted in no change
|
||||
if (_applyIdleBehavior) {
|
||||
applyIdleBehavior(
|
||||
deltaTime,
|
||||
pose.position,
|
||||
camRot.localRotation,
|
||||
camRot.globalRotation
|
||||
);
|
||||
}
|
||||
|
||||
// Horizontal translation by focus node rotation
|
||||
pose.position = followAnchorNodeRotation(
|
||||
pose.position,
|
||||
@@ -1234,7 +1270,7 @@ glm::dvec3 OrbitalNavigator::translateHorizontally(double deltaTime,
|
||||
const glm::dquat websocketRotationDiffCamSpace = glm::dquat(glm::dvec3(
|
||||
-_websocketStates.globalRotationVelocity().y * deltaTime,
|
||||
-_websocketStates.globalRotationVelocity().x * deltaTime,
|
||||
0) * speedScale
|
||||
0.0) * speedScale
|
||||
);
|
||||
|
||||
// Transform to world space
|
||||
@@ -1434,4 +1470,74 @@ const ScriptCameraStates& OrbitalNavigator::scriptStates() const {
|
||||
return _scriptStates;
|
||||
}
|
||||
|
||||
void OrbitalNavigator::applyIdleBehavior(double deltaTime, glm::dvec3& position,
|
||||
glm::dquat& localRotation,
|
||||
glm::dquat& globalRotation)
|
||||
{
|
||||
const glm::dvec3 posDiff = position - _anchorNode->worldPosition();
|
||||
|
||||
SurfacePositionHandle posHandle =
|
||||
calculateSurfacePositionHandle(*_anchorNode, position);
|
||||
|
||||
const glm::dvec3 centerToActualSurfaceModelSpace =
|
||||
posHandle.centerToReferenceSurface +
|
||||
posHandle.referenceSurfaceOutDirection * posHandle.heightToSurface;
|
||||
|
||||
const glm::dvec3 centerToActualSurface = glm::dmat3(_anchorNode->modelTransform()) *
|
||||
centerToActualSurfaceModelSpace;
|
||||
const glm::dvec3 actualSurfaceToCamera = posDiff - centerToActualSurface;
|
||||
|
||||
const double distFromSurfaceToCamera = glm::length(actualSurfaceToCamera);
|
||||
const double distFromCenterToSurface = glm::length(centerToActualSurface);
|
||||
|
||||
double speedScale =
|
||||
distFromCenterToSurface > 0.0 ?
|
||||
glm::clamp(distFromSurfaceToCamera / distFromCenterToSurface, 0.0, 1.0) :
|
||||
1.0;
|
||||
|
||||
speedScale *= 0.1; // without this scaleing, the motion is way too fast
|
||||
|
||||
// Apply the chosen behavior
|
||||
const IdleBehavior chosen = static_cast<IdleBehavior>(_idleBehavior.value());
|
||||
switch (chosen) {
|
||||
case IdleBehavior::Orbit:
|
||||
orbitAnchor(deltaTime, position, globalRotation, speedScale);
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
|
||||
void OrbitalNavigator::orbitAnchor(double deltaTime, glm::dvec3& position,
|
||||
glm::dquat& globalRotation, double speedScale)
|
||||
{
|
||||
ghoul_assert(_anchorNode != nullptr, "Node to orbit must be set!");
|
||||
|
||||
// Get position on the surface of the node corresponding to current camera position
|
||||
SurfacePositionHandle posHandle = calculateSurfacePositionHandle(
|
||||
*_anchorNode, position);
|
||||
|
||||
const glm::dmat4 modelTransform = _anchorNode->modelTransform();
|
||||
const glm::dvec3 outDirection = glm::normalize(glm::dmat3(modelTransform) *
|
||||
posHandle.referenceSurfaceOutDirection);
|
||||
|
||||
// Apply a rotation to the right
|
||||
// (Note that we could also let the user decide which direction to rotate)
|
||||
const glm::dvec3 eulerAngles = glm::dvec3(0.0, -1.0, 0.0) * deltaTime * speedScale;
|
||||
const glm::dquat rotationDiffCameraSpace = glm::dquat(eulerAngles);
|
||||
|
||||
const glm::dquat rotationDiffWorldSpace = globalRotation *
|
||||
rotationDiffCameraSpace *
|
||||
glm::inverse(globalRotation);
|
||||
|
||||
// Rotate to find the difference in position
|
||||
const glm::dvec3 anchorPos = _anchorNode->worldPosition();
|
||||
const double distFromCenterToCamera = glm::length(position - anchorPos);
|
||||
const glm::dvec3 rotationDiffVec3 =
|
||||
(distFromCenterToCamera * outDirection) * rotationDiffWorldSpace -
|
||||
(distFromCenterToCamera * outDirection);
|
||||
|
||||
position += rotationDiffVec3;
|
||||
}
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
@@ -54,21 +54,6 @@ namespace {
|
||||
"If disabled, roll is removed from the interpolation of camera orientation"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo StopBehaviorInfo = {
|
||||
"StopBehavior",
|
||||
"Stop Behavior",
|
||||
"A camera motion behavior that is applied when no path is being played"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo
|
||||
ApplyStopBehaviorWhenIdleInfo =
|
||||
{
|
||||
"ApplyStopBehaviorWhenIdle",
|
||||
"Apply Stop Behavior When Idle",
|
||||
"If enabled, the camera is controlled using the set stop behavior when "
|
||||
"no path is playing"
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo SpeedScaleInfo = {
|
||||
"SpeedScale",
|
||||
"Speed Scale",
|
||||
@@ -77,12 +62,6 @@ namespace {
|
||||
"value is larger than or smaller than one."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo OrbitSpeedFactorInfo = {
|
||||
"OrbitSpeedFactor",
|
||||
"Orbit Speed Factor",
|
||||
"Controls the speed of the orbiting around an anchor."
|
||||
};
|
||||
|
||||
constexpr const openspace::properties::Property::PropertyInfo MinBoundingSphereInfo = {
|
||||
"MinimalValidBoundingSphere",
|
||||
"Minimal Valid Bounding Sphere",
|
||||
@@ -110,13 +89,7 @@ PathNavigator::PathNavigator()
|
||||
properties::OptionProperty::DisplayType::Dropdown
|
||||
)
|
||||
, _includeRoll(IncludeRollInfo, false)
|
||||
, _stopBehavior(
|
||||
StopBehaviorInfo,
|
||||
properties::OptionProperty::DisplayType::Dropdown
|
||||
)
|
||||
, _applyStopBehaviorWhenIdle(ApplyStopBehaviorWhenIdleInfo, false)
|
||||
, _speedScale(SpeedScaleInfo, 1.f, 0.01f, 2.f)
|
||||
, _orbitSpeedFactor(OrbitSpeedFactorInfo, 0.5, 0.0, 20.0)
|
||||
, _minValidBoundingSphere(MinBoundingSphereInfo, 10.0, 1.0, 3e10)
|
||||
, _relevantNodeTags(RelevantNodeTagsInfo)
|
||||
{
|
||||
@@ -129,20 +102,6 @@ PathNavigator::PathNavigator()
|
||||
|
||||
addProperty(_includeRoll);
|
||||
addProperty(_speedScale);
|
||||
|
||||
// OBS! Stop behavior is broken as of core merge
|
||||
//addProperty(_applyStopBehaviorWhenIdle);
|
||||
|
||||
//// Must be listed in the same order as in enum definition
|
||||
//_stopBehavior.addOptions({
|
||||
// { StopBehavior::None, "None" },
|
||||
// { StopBehavior::Orbit, "Orbit" }
|
||||
//});
|
||||
//_stopBehavior = StopBehavior::None;
|
||||
//addProperty(_stopBehavior);
|
||||
|
||||
//addProperty(_orbitSpeedFactor);
|
||||
|
||||
addProperty(_minValidBoundingSphere);
|
||||
|
||||
_relevantNodeTags = std::vector<std::string>{
|
||||
@@ -194,11 +153,6 @@ void PathNavigator::updateCamera(double deltaTime) {
|
||||
}
|
||||
|
||||
if (!_isPlaying) {
|
||||
//// TODO: Determine how this should work
|
||||
//// OBS! Stop behavior is broken as of core merge
|
||||
//if (hasFinished() && _applyStopBehaviorWhenIdle) {
|
||||
// applyStopBehavior(deltaTime);
|
||||
//}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -395,62 +349,6 @@ void PathNavigator::removeRollRotation(CameraPose& pose, double deltaTime) {
|
||||
pose.rotation = rollFreeRotation;
|
||||
}
|
||||
|
||||
void PathNavigator::applyStopBehavior(double deltaTime) {
|
||||
switch (_stopBehavior) {
|
||||
case StopBehavior::None:
|
||||
// Do nothing
|
||||
break;
|
||||
case StopBehavior::Orbit:
|
||||
orbitAnchorNode(deltaTime);
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
}
|
||||
|
||||
void PathNavigator::orbitAnchorNode(double deltaTime) {
|
||||
ghoul_assert(anchor() != nullptr, "Node to orbit must be set!");
|
||||
|
||||
const glm::dvec3 prevPosition = camera()->positionVec3();
|
||||
const glm::dquat prevRotation = camera()->rotationQuaternion();
|
||||
const glm::dvec3 nodeCenter = anchor()->worldPosition();
|
||||
|
||||
const double speedFactor = 0.1 * _orbitSpeedFactor;
|
||||
|
||||
// Compute orbit speed based on factor and distance to surface
|
||||
const double orbitRadius = glm::distance(prevPosition, nodeCenter);
|
||||
const double distanceToSurface = orbitRadius - anchor()->boundingSphere();
|
||||
const double orbitSpeed = distanceToSurface * speedFactor;
|
||||
|
||||
// Compute a new position along the orbit
|
||||
const glm::dvec3 up = camera()->lookUpVectorWorldSpace();
|
||||
const glm::dquat lookAtNodeRotation = ghoul::lookAtQuaternion(
|
||||
prevPosition,
|
||||
nodeCenter,
|
||||
up
|
||||
);
|
||||
const glm::dvec3 targetForward = lookAtNodeRotation * glm::dvec3(0.0, 0.0, -1.0);
|
||||
const glm::dvec3 rightOrbitTangent = glm::normalize(glm::cross(targetForward, up));
|
||||
|
||||
glm::dvec3 newPosition = prevPosition + orbitSpeed * deltaTime * rightOrbitTangent;
|
||||
|
||||
// Adjust for numerical error - make sure we stay at the same height
|
||||
const glm::dvec3 nodeToNewPos = newPosition - nodeCenter;
|
||||
const double targetHeight = glm::distance(prevPosition, nodeCenter);
|
||||
const double heightDiff = glm::length(nodeToNewPos) - targetHeight;
|
||||
newPosition -= heightDiff * glm::normalize(nodeToNewPos);
|
||||
|
||||
// Rotate along the orbit, but keep relative orientation with regards to the anchor
|
||||
const glm::dquat localRotation = glm::inverse(lookAtNodeRotation) * prevRotation;
|
||||
const glm::dquat newLookAtRotation =
|
||||
ghoul::lookAtQuaternion(newPosition, nodeCenter, up);
|
||||
|
||||
const glm::dquat newRotation = newLookAtRotation * localRotation;
|
||||
|
||||
camera()->setPositionVec3(newPosition);
|
||||
camera()->setRotation(newRotation);
|
||||
}
|
||||
|
||||
scripting::LuaLibrary PathNavigator::luaLibrary() {
|
||||
return {
|
||||
"pathnavigation",
|
||||
|
||||
Reference in New Issue
Block a user