Remove rotation state variables from interaction mode and enable more freely local rotation.

This commit is contained in:
Kalle Bladin
2016-06-28 22:28:56 -04:00
parent fcaee68424
commit e5ccf185cd
7 changed files with 179 additions and 108 deletions

View File

@@ -60,7 +60,7 @@ return {
FilePath = "map_service_configs/ESRI_Imagery_World_2D.wms",
Enabled = false,
},
{
{
Name = "MARS_Viking_MDIM21",
FilePath = "map_service_configs/MARS_Viking_MDIM21.xml",
Enabled = true,

View File

@@ -188,7 +188,7 @@ public:
*/
static scripting::ScriptEngine::LuaLibrary luaLibrary();
// Callback functions
// Callback functions
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
void mouseButtonCallback(MouseButton button, MouseAction action);
void mousePositionCallback(double x, double y);
@@ -209,6 +209,7 @@ private:
std::shared_ptr<InteractionMode> _currentInteractionMode;
std::shared_ptr<OrbitalInteractionMode::MouseStates> _mouseStates;
std::shared_ptr<OrbitalInteractionMode> _orbitalInteractionMode;
std::shared_ptr<GlobeBrowsingInteractionMode> _globebrowsingInteractionMode;

View File

@@ -96,8 +96,6 @@ public:
SceneGraphNode* focusNode();
virtual void update(Camera& camera, const InputState& inputState, double deltaTime) = 0;
virtual void initialize(const Camera& camera) = 0;
protected:
/**
Inner class that acts as a smoothing filter to a variable. The filter has a step
@@ -115,6 +113,10 @@ protected:
_currentValue = _currentValue + (_targetValue - _currentValue) *
min(_scale * dt, 1.0); // less or equal to 1.0 keeps it stable
}
void setHard(T value) {
_targetValue = value;
_currentValue = value;
}
T get() {
return _currentValue;
}
@@ -142,46 +144,53 @@ public:
~KeyframeInteractionMode();
virtual void update(double deltaTime);
virtual void initialize(const Camera& camera);
private:
double _currentKeyframeTime;
};
class GlobeBrowsingInteractionMode;
class OrbitalInteractionMode : public InteractionMode
{
public:
/*!
class MouseStates
{
public:
/*!
\param inputState
\param sensitivity
\param velocityScalefactor can be set to 60 to remove the inertia of the
interaction. Lower value will make it harder to move the camera.
*/
OrbitalInteractionMode(double sensitivity, double velocityScaleFactor);
interaction. Lower value will make it harder to move the camera.
*/
MouseStates(double sensitivity, double velocityScaleFactor);
void updateMouseStatesFromInput(const InputState& inputState, double deltaTime);
private:
friend class OrbitalInteractionMode;
friend class GlobeBrowsingInteractionMode;
double _sensitivity;
MouseState _globalRotationMouseState;
MouseState _localRotationMouseState;
MouseState _truckMovementMouseState;
MouseState _localRollMouseState;
MouseState _globalRollMouseState;
};
OrbitalInteractionMode(std::shared_ptr<MouseStates> mouseStates);
~OrbitalInteractionMode();
virtual void update(Camera& camera, const InputState& inputState, double deltaTime);
virtual void initialize(const Camera& camera);
protected:
void updateMouseStatesFromInput(const InputState& inputState, double deltaTime);
void updateCameraStateFromMouseStates(Camera& camera);
double _sensitivity;
MouseState _globalRotationMouseState;
MouseState _localRotationMouseState;
MouseState _truckMovementMouseState;
MouseState _rollMouseState;
glm::dquat _localCameraRotation;
glm::dquat _globalCameraRotation;
std::shared_ptr<MouseStates> _mouseStates;
};
class GlobeBrowsingInteractionMode : public OrbitalInteractionMode
{
public:
GlobeBrowsingInteractionMode(double sensitivity, double velocityScaleFactor);
GlobeBrowsingInteractionMode(std::shared_ptr<MouseStates> mouseStates);
~GlobeBrowsingInteractionMode();
virtual void setFocusNode(SceneGraphNode* focusNode);

View File

@@ -209,6 +209,7 @@ namespace openspace {
// Cached data
mutable Cached<Vec3> _cachedViewDirection;
mutable Cached<Vec3> _cachedLookupVector;
mutable Cached<Mat4> _cachedViewRotationMatrix;
mutable Cached<Mat4> _cachedCombinedViewMatrix;
mutable Cached<float> _cachedSinMaxFov;

View File

@@ -639,8 +639,10 @@ InteractionHandler::InteractionHandler()
// Create the interactionModes
_inputState = std::make_unique<InputState>();
_orbitalInteractionMode = std::make_shared<OrbitalInteractionMode>(0.002, 1);
_globebrowsingInteractionMode = std::make_shared<GlobeBrowsingInteractionMode>(0.002, 1);
// Inject the same mouse states to both orbital and global interaction mode
_mouseStates = std::make_unique<OrbitalInteractionMode::MouseStates>(0.002, 1);
_orbitalInteractionMode = std::make_shared<OrbitalInteractionMode>(_mouseStates);
_globebrowsingInteractionMode = std::make_shared<GlobeBrowsingInteractionMode>(_mouseStates);
// Set the interactionMode
_currentInteractionMode = _orbitalInteractionMode;
@@ -673,7 +675,7 @@ void InteractionHandler::setInteractionModeToOrbital() {
setInteractionMode(_orbitalInteractionMode);
}
void InteractionHandler::setInteractionModeToGlobeBrowsing() {
void InteractionHandler::setInteractionModeToGlobeBrowsing() {
setInteractionMode(_globebrowsingInteractionMode);
}
@@ -763,7 +765,6 @@ void InteractionHandler::restoreCameraPosition(const std::string& filepath) {
_camera->setPositionVec3(p);
_camera->setRotation(r);
_currentInteractionMode->initialize(*_camera);
_cameraUpdatedFromScript = true;
}
}

View File

@@ -169,26 +169,19 @@ KeyframeInteractionMode::~KeyframeInteractionMode() {
void KeyframeInteractionMode::update(double deltaTime) {
// TODO : Get keyframes from input state and use them to position and rotate the camera
}
void KeyframeInteractionMode::initialize(const Camera& camera) {
LWARNING("KeyframeInteractionMode::initialize not implemented yet");
}
// OrbitalInteractionMode
OrbitalInteractionMode::OrbitalInteractionMode(double sensitivity, double velocityScaleFactor)
OrbitalInteractionMode::MouseStates::MouseStates(double sensitivity, double velocityScaleFactor)
: _sensitivity(sensitivity)
, _globalRotationMouseState(velocityScaleFactor)
, _localRotationMouseState(velocityScaleFactor)
, _truckMovementMouseState(velocityScaleFactor)
, _rollMouseState(velocityScaleFactor) {
, _globalRollMouseState(velocityScaleFactor)
, _localRollMouseState(velocityScaleFactor) {
}
OrbitalInteractionMode::~OrbitalInteractionMode() {
}
void OrbitalInteractionMode::updateMouseStatesFromInput(const InputState& inputState, double deltaTime) {
void OrbitalInteractionMode::MouseStates::updateMouseStatesFromInput(const InputState& inputState, double deltaTime) {
glm::dvec2 mousePosition = inputState.getMousePosition();
bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1);
@@ -233,89 +226,132 @@ void OrbitalInteractionMode::updateMouseStatesFromInput(const InputState& inputS
_truckMovementMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
if (button3Pressed) {
glm::dvec2 mousePositionDelta =
_rollMouseState.previousPosition - mousePosition;
_rollMouseState.velocity.set(mousePositionDelta * deltaTime * _sensitivity, deltaTime);
if (keyCtrlPressed) {
glm::dvec2 mousePositionDelta =
_localRollMouseState.previousPosition - mousePosition;
_localRollMouseState.velocity.set(mousePositionDelta * deltaTime * _sensitivity, deltaTime);
_globalRollMouseState.previousPosition = mousePosition;
_globalRollMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
else {
glm::dvec2 mousePositionDelta =
_globalRollMouseState.previousPosition - mousePosition;
_globalRollMouseState.velocity.set(mousePositionDelta * deltaTime * _sensitivity, deltaTime);
_localRollMouseState.previousPosition = mousePosition;
_localRollMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
}
else { // !button3Pressed
_rollMouseState.previousPosition = mousePosition;
_rollMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
_globalRollMouseState.previousPosition = mousePosition;
_globalRollMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
_localRollMouseState.previousPosition = mousePosition;
_localRollMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
}
OrbitalInteractionMode::OrbitalInteractionMode(std::shared_ptr<MouseStates> mouseStates)
: _mouseStates(mouseStates){
}
OrbitalInteractionMode::~OrbitalInteractionMode() {
}
void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera) {
using namespace glm;
if (_focusNode) {
// Declare variables to use in interaction calculations
dvec3 centerPos = _focusNode->worldPosition().dvec3();
// Read the current state of the camera and focus node
dvec3 camPos = camera.positionVec3();
dvec3 posDiff = camPos - centerPos;
dvec3 newPosition = camPos;
dvec3 centerPos = _focusNode->worldPosition().dvec3();
dquat totalRotation = camera.rotationQuaternion();
dvec3 directionToCenter = normalize(centerPos - camera.positionVec3());
dvec3 lookUp = camera.lookUpVectorWorldSpace();
double boundingSphere = _focusNode->boundingSphere().lengthf();
dvec3 camDirection = camera.viewDirectionWorldSpace();
// Declare other variables used in interaction calculations
double minHeightAboveBoundingSphere = 10;
dvec3 centerToCamera = camPos - centerPos;
dvec3 centerToBoundingSphere;
// Create the internal representation of the local and global camera rotations
dmat4 lookAtMat = lookAt(
dvec3(0, 0, 0),
directionToCenter,
normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction
dquat globalCameraRotation = normalize(quat_cast(inverse(lookAtMat)));
dquat localCameraRotation = inverse(globalCameraRotation) * totalRotation;
{ // Do local roll
glm::dquat cameraRollRotation =
glm::angleAxis(_mouseStates->_localRollMouseState.velocity.get().x, dvec3(0, 0, 1));
localCameraRotation = localCameraRotation * cameraRollRotation;
}
{ // Do local rotation
dvec3 eulerAngles(_localRotationMouseState.velocity.get().y, 0, 0);
dvec3 eulerAngles(_mouseStates->_localRotationMouseState.velocity.get().y, _mouseStates->_localRotationMouseState.velocity.get().x, 0);
dquat rotationDiff = dquat(eulerAngles);
_localCameraRotation = _localCameraRotation * rotationDiff;
localCameraRotation = localCameraRotation * rotationDiff;
}
{ // Do global rotation
dvec2 smoothMouseVelocity = _globalRotationMouseState.velocity.get();
dvec3 eulerAngles(smoothMouseVelocity.x, smoothMouseVelocity.y, 0);
dvec2 smoothMouseVelocity = _mouseStates->_globalRotationMouseState.velocity.get();
dvec3 eulerAngles(-smoothMouseVelocity.y, -smoothMouseVelocity.x, 0);
dquat rotationDiffCamSpace = dquat(eulerAngles);
dquat newRotationCamspace = _globalCameraRotation * rotationDiffCamSpace;
dquat rotationDiffWorldSpace = newRotationCamspace * inverse(_globalCameraRotation);
dvec3 rotationDiffVec3 = posDiff * rotationDiffWorldSpace - posDiff;
dquat newRotationCamspace = globalCameraRotation * rotationDiffCamSpace;
dquat rotationDiffWorldSpace = newRotationCamspace * inverse(globalCameraRotation);
dvec3 rotationDiffVec3 = centerToCamera * rotationDiffWorldSpace - centerToCamera;
newPosition = camPos + rotationDiffVec3;
dvec3 directionToCenter = normalize(centerPos - newPosition);
camPos += rotationDiffVec3;
dvec3 centerToCamera = camPos - centerPos;
directionToCenter = normalize(-centerToCamera);
dvec3 lookUpWhenFacingCenter =
_globalCameraRotation * dvec3(camera.lookUpVectorCameraSpace());
globalCameraRotation * dvec3(camera.lookUpVectorCameraSpace());
dmat4 lookAtMat = lookAt(
dvec3(0, 0, 0),
directionToCenter,
lookUpWhenFacingCenter);
_globalCameraRotation = normalize(quat_cast(inverse(lookAtMat)));
globalCameraRotation = normalize(quat_cast(inverse(lookAtMat)));
}
{ // Move position towards or away from focus node
double boundingSphere = _focusNode->boundingSphere().lengthf();
dvec3 centerToBoundingSphere =
normalize(posDiff) *
static_cast<double>(_focusNode->boundingSphere().lengthf());
newPosition += -(posDiff - centerToBoundingSphere) *
_truckMovementMouseState.velocity.get().y;
centerToBoundingSphere =
-directionToCenter *
boundingSphere;
camPos += -(centerToCamera - centerToBoundingSphere) *
_mouseStates->_truckMovementMouseState.velocity.get().y;
}
{ // Do roll
{ // Roll around sphere normal
dquat cameraRollRotation =
angleAxis(_rollMouseState.velocity.get().x, normalize(posDiff));
_globalCameraRotation = cameraRollRotation * _globalCameraRotation;
angleAxis(_mouseStates->_globalRollMouseState.velocity.get().x, -directionToCenter);
globalCameraRotation = cameraRollRotation * globalCameraRotation;
}
{ // Push up to surface
dvec3 sphereSurfaceToCamera = camPos - (centerPos + centerToBoundingSphere);
double distFromSphereSurfaceToCamera = length(sphereSurfaceToCamera);
camPos += -directionToCenter *
max(minHeightAboveBoundingSphere - distFromSphereSurfaceToCamera, 0.0);
}
// Update the camera state
camera.setRotation(_globalCameraRotation * _localCameraRotation);
camera.setPositionVec3(newPosition);
camera.setRotation(globalCameraRotation * localCameraRotation);
camera.setPositionVec3(camPos);
}
}
void OrbitalInteractionMode::update(Camera& camera, const InputState& inputState, double deltaTime) {
updateMouseStatesFromInput(inputState, deltaTime);
_mouseStates->updateMouseStatesFromInput(inputState, deltaTime);
updateCameraStateFromMouseStates(camera);
}
void OrbitalInteractionMode::initialize(const Camera& camera) {
LWARNING("Interaction has not implemented sync to camera. I.e. interaction \
mode may contain staate that is not transferred when reading camera state from disk");
// @Todo : extract _localCameraRotation and _globalCameraRotation from camera state
}
GlobeBrowsingInteractionMode::GlobeBrowsingInteractionMode(double sensitivity, double velocityScaleFactor)
: OrbitalInteractionMode(sensitivity, velocityScaleFactor)
GlobeBrowsingInteractionMode::GlobeBrowsingInteractionMode(std::shared_ptr<MouseStates> mouseStates)
: OrbitalInteractionMode(mouseStates)
{
}
GlobeBrowsingInteractionMode::~GlobeBrowsingInteractionMode() {
@@ -336,7 +372,6 @@ void GlobeBrowsingInteractionMode::setFocusNode(SceneGraphNode* focusNode) {
}
void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& camera) {
if (_focusNode && _globe) {
// Declare variables to use in interaction calculations
@@ -344,46 +379,63 @@ void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& came
double ellipsoidShrinkTerm = _globe->interactionDepthBelowEllipsoid();
double minHeightAboveGround = _globe->cameraMinHeight();
glm::dvec3 centerPos = _focusNode->worldPosition().dvec3();
glm::dvec3 camPos = camera.positionVec3();
glm::dvec3 posDiff = camPos - centerPos;
// Read the current state of the camera and focusnode
dvec3 centerPos = _focusNode->worldPosition().dvec3();
dvec3 camPos = camera.positionVec3();
dquat totalRotation = camera.rotationQuaternion();
dvec3 lookUp = camera.lookUpVectorWorldSpace();
dvec3 camDirection = camera.viewDirectionWorldSpace();
glm::dvec3 directionFromSurfaceToCamera =
dvec3 posDiff = camPos - centerPos;
dvec3 directionFromSurfaceToCamera =
_globe->ellipsoid().geodeticSurfaceNormal(
_globe->ellipsoid().cartesianToGeodetic2(camPos));
glm::dvec3 centerToEllipsoidSurface = _globe->projectOnEllipsoid(camPos) -
dvec3 centerToEllipsoidSurface = _globe->projectOnEllipsoid(camPos) -
directionFromSurfaceToCamera * ellipsoidShrinkTerm;
glm::dvec3 ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
dvec3 ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
double distFromCenterToSurface =
glm::length(centerToEllipsoidSurface);
double distFromEllipsoidSurfaceToCamera = glm::length(ellipsoidSurfaceToCamera);
double distFromCenterToCamera = glm::length(posDiff);
length(centerToEllipsoidSurface);
double distFromEllipsoidSurfaceToCamera = length(ellipsoidSurfaceToCamera);
double distFromCenterToCamera = length(posDiff);
// Create the internal representation of the local and global camera rotations
dmat4 lookAtMat = lookAt(
dvec3(0.0, 0.0, 0.0),
-directionFromSurfaceToCamera,
normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction
dquat globalCameraRotation = normalize(quat_cast(inverse(lookAtMat)));
dquat localCameraRotation = inverse(globalCameraRotation) * totalRotation;
{ // Do local roll
glm::dquat cameraRollRotation =
glm::angleAxis(_mouseStates->_localRollMouseState.velocity.get().x, dvec3(0, 0, 1));
localCameraRotation = localCameraRotation * cameraRollRotation;
}
{ // Do local rotation
glm::dvec3 eulerAngles(_localRotationMouseState.velocity.get().y, 0, 0);
glm::dvec3 eulerAngles(_mouseStates->_localRotationMouseState.velocity.get().y, _mouseStates->_localRotationMouseState.velocity.get().x, 0);
glm::dquat rotationDiff = glm::dquat(eulerAngles);
_localCameraRotation = _localCameraRotation * rotationDiff;
localCameraRotation = localCameraRotation * rotationDiff;
}
{ // Do global rotation
glm::dvec3 eulerAngles = glm::dvec3(
-_globalRotationMouseState.velocity.get().y,
-_globalRotationMouseState.velocity.get().x,
-_mouseStates->_globalRotationMouseState.velocity.get().y,
-_mouseStates->_globalRotationMouseState.velocity.get().x,
0) * glm::clamp(distFromEllipsoidSurfaceToCamera / distFromCenterToSurface, 0.0, 1.0);
glm::dquat rotationDiffCamSpace = glm::dquat(eulerAngles);
glm::dquat rotationDiffWorldSpace =
_globalCameraRotation *
globalCameraRotation *
rotationDiffCamSpace *
glm::inverse(_globalCameraRotation);
glm::inverse(globalCameraRotation);
glm::dvec3 rotationDiffVec3 =
(distFromCenterToCamera * directionFromSurfaceToCamera)
* rotationDiffWorldSpace
- (distFromCenterToCamera * directionFromSurfaceToCamera);
camPos = camPos + rotationDiffVec3;
camPos += rotationDiffVec3;
directionFromSurfaceToCamera =
_globe->ellipsoid().geodeticSurfaceNormal(
@@ -393,23 +445,23 @@ void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& came
ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
glm::dvec3 lookUpWhenFacingSurface =
_globalCameraRotation * glm::dvec3(camera.lookUpVectorCameraSpace());
globalCameraRotation * glm::dvec3(camera.lookUpVectorCameraSpace());
glm::dmat4 lookAtMat = glm::lookAt(
glm::dvec3(0, 0, 0),
-directionFromSurfaceToCamera,
lookUpWhenFacingSurface);
_globalCameraRotation =
globalCameraRotation =
glm::normalize(glm::quat_cast(glm::inverse(lookAtMat)));
}
{ // Move position towards or away from focus node
distFromEllipsoidSurfaceToCamera = glm::length(ellipsoidSurfaceToCamera);
camPos += -directionFromSurfaceToCamera * distFromEllipsoidSurfaceToCamera *
_truckMovementMouseState.velocity.get().y;
_mouseStates->_truckMovementMouseState.velocity.get().y;
}
{ // Do roll
{ // Roll around ellipsoid normal
glm::dquat cameraRollRotation =
glm::angleAxis(_rollMouseState.velocity.get().x, directionFromSurfaceToCamera);
_globalCameraRotation = cameraRollRotation * _globalCameraRotation;
glm::angleAxis(_mouseStates->_globalRollMouseState.velocity.get().x, directionFromSurfaceToCamera);
globalCameraRotation = cameraRollRotation * globalCameraRotation;
}
{ // Push up to surface
ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
@@ -421,13 +473,13 @@ void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& came
glm::max(heightToSurfaceAndPadding - distFromEllipsoidSurfaceToCamera, 0.0);
}
// Update the camera state
camera.setRotation(_globalCameraRotation * _localCameraRotation);
camera.setRotation(globalCameraRotation * localCameraRotation);
camera.setPositionVec3(camPos);
}
}
void GlobeBrowsingInteractionMode::update(Camera& camera, const InputState& inputState, double deltaTime) {
updateMouseStatesFromInput(inputState, deltaTime);
_mouseStates->updateMouseStatesFromInput(inputState, deltaTime);
updateCameraStateFromMouseStates(camera);
}

View File

@@ -52,6 +52,7 @@ namespace openspace {
: sgctInternal(o.sgctInternal)
, _focusPosition(o._focusPosition)
, _cachedViewDirection(o._cachedViewDirection)
, _cachedLookupVector(o._cachedLookupVector)
, _rotation(o._rotation)
, _scaling(o._scaling)
, _position(o._position)
@@ -122,7 +123,12 @@ namespace openspace {
}
const Camera::Vec3& Camera::lookUpVectorWorldSpace() const {
return glm::normalize(_rotation.synced * Vec3(_LOOKUP_VECTOR_CAMERA_SPACE));
if (_cachedLookupVector.isDirty) {
_cachedLookupVector.datum =
_rotation.synced * Vec3(_LOOKUP_VECTOR_CAMERA_SPACE);
_cachedLookupVector.datum = glm::normalize(_cachedLookupVector.datum);
}
return _cachedLookupVector.datum;
}
const glm::vec2& Camera::scaling() const {
@@ -188,6 +194,7 @@ namespace openspace {
_scaling.postSynchronizationPreDraw();
_cachedViewDirection.isDirty = true;
_cachedLookupVector.isDirty = true;
}
void Camera::serialize(std::ostream& os) const {