Move rotation logic into its own class

This commit is contained in:
Emma Broman
2020-02-27 13:30:39 -05:00
parent d606a569bc
commit d704c95ca0
7 changed files with 192 additions and 65 deletions
+2
View File
@@ -33,6 +33,7 @@ set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/pathspecification.h
${CMAKE_CURRENT_SOURCE_DIR}/pathsegment.h
${CMAKE_CURRENT_SOURCE_DIR}/pathcurves.h
${CMAKE_CURRENT_SOURCE_DIR}/rotationinterpolator.h
)
source_group("Header Files" FILES ${HEADER_FILES})
@@ -45,6 +46,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/pathspecification.cpp
${CMAKE_CURRENT_SOURCE_DIR}/pathsegment.cpp
${CMAKE_CURRENT_SOURCE_DIR}/pathcurves.cpp
${CMAKE_CURRENT_SOURCE_DIR}/rotationinterpolator.cpp
)
source_group("Source Files" FILES ${SOURCE_FILES})
+10 -1
View File
@@ -68,6 +68,10 @@ double PathCurve::arcLength(double limit) {
return (h / 3.0) * (endPoints + 4.0 * times4 + 2.0 *times2);
}
glm::dquat PathCurve::rotationAt(double u) {
return _rotationInterpolator.rotationAt(u);
}
// TODO: remove when not needed
// Created for debugging
std::vector<glm::dvec3> PathCurve::getPoints() {
@@ -75,6 +79,9 @@ std::vector<glm::dvec3> PathCurve::getPoints() {
}
Bezier3Curve::Bezier3Curve(const CameraState& start, const CameraState& end) {
// default rotation interpolation
_rotationInterpolator = RotationInterpolator{ start, end, this, PiecewiseSlerp };
glm::dvec3 startNodePos = sceneGraphNode(start.referenceNode)->worldPosition();
glm::dvec3 endNodePos = sceneGraphNode(end.referenceNode)->worldPosition();
double startNodeRadius = sceneGraphNode(start.referenceNode)->boundingSphere();
@@ -206,6 +213,7 @@ LinearCurve::LinearCurve(const CameraState& start, const CameraState& end) {
_points.push_back(start.position);
_points.push_back(end.position);
_length = glm::distance(end.position, start.position);
_rotationInterpolator = RotationInterpolator{ start, end, this, Slerp };
}
glm::dvec3 LinearCurve::positionAt(double u) {
@@ -214,9 +222,10 @@ glm::dvec3 LinearCurve::positionAt(double u) {
}
// TODO: Iprove handling of pauses
PauseCurve::PauseCurve(CameraState& state) {
PauseCurve::PauseCurve(const CameraState& state) {
_points.push_back(state.position);
_length = 1.0; // OBS! Length of a pause curve makes no sense, but it also doesn't matter
_rotationInterpolator = RotationInterpolator{ state, state, this, Fixed };
}
glm::dvec3 PauseCurve::positionAt(double u) {
+6 -7
View File
@@ -26,6 +26,7 @@
#define __OPENSPACE_MODULE_AUTONAVIGATION___PATHCURVE___H__
#include <modules/autonavigation/camerastate.h>
#include <modules/autonavigation/rotationinterpolator.h>
#include <ghoul/glm.h>
#include <vector>
@@ -44,18 +45,17 @@ public:
const double length() const;
double arcLength(double limit = 1.0);
// comppute the value at the relative length s [0,1]
// u is interpolation parameter in [0,1] (relative length)
virtual glm::dvec3 positionAt(double u) = 0;
glm::dquat rotationAt(double u);
std::vector<glm::dvec3> getPoints(); // for debugging
protected:
// the points used for creating the curve (e.g. control points of a Bezier curve)
std::vector<glm::dvec3> _points;
double _length; // the total length of the curve (approximated)
// the total length of the curve (approximated)
double _length;
RotationInterpolator _rotationInterpolator;
};
class Bezier3Curve : public PathCurve {
@@ -74,14 +74,13 @@ class LinearCurve : public PathCurve {
public:
LinearCurve(const CameraState& start, const CameraState& end);
glm::dvec3 positionAt(double u);
};
// OBS! This is a temporary class specialised for handling pauses.
// TODO: handle better in the future.
class PauseCurve : public PathCurve {
public:
PauseCurve(CameraState& state);
PauseCurve(const CameraState& state);
glm::dvec3 positionAt(double u);
};
+1 -56
View File
@@ -99,62 +99,7 @@ glm::dvec3 PathSegment::getPositionAt(double u) const {
}
glm::dquat PathSegment::getRotationAt(double u) const {
// TODO: improve how rotation is computed
switch (_curveType) {
case CurveType::Bezier3:
{
return piecewiseSlerpRotation(u);
break;
}
default:
{
double uSlerp = helpers::shiftAndScale(u, 0.1, 0.9);
uSlerp = ghoul::cubicEaseInOut(uSlerp);
return glm::slerp(_start.rotation, _end.rotation, uSlerp);
}
}
}
// Interpolate between a number of keyframes for orientation using SLERP
const glm::dquat PathSegment::piecewiseSlerpRotation(double u) const {
// breakpoints for subintervals
const double u1 = 0.3;
const double u2 = 0.8; // TODO: these should probably be based on distance
glm::dvec3 startNodePos = sceneGraphNode(_start.referenceNode)->worldPosition();
glm::dvec3 endNodePos = sceneGraphNode(_end.referenceNode)->worldPosition();
glm::dvec3 startUpVec = _start.rotation * glm::dvec3(0.0, 1.0, 0.0);
glm::dvec3 endUpVec = _end.rotation * glm::dvec3(0.0, 1.0, 0.0);
glm::dquat lookAtStartQ =
helpers::getLookAtQuaternion(getPositionAt(u1), startNodePos, startUpVec);
glm::dquat lookAtEndQ =
helpers::getLookAtQuaternion(getPositionAt(u2), endNodePos, endUpVec);
std::vector<std::pair<glm::dquat, double>> keyframes{
{_start.rotation, 0.0},
{lookAtStartQ, u1},
{lookAtEndQ, u2},
{_end.rotation, 1.0},
};
// Find the current segment and compute interpolation
glm::dquat result;
for (int i = 0; i < keyframes.size() - 1; ++i) {
double ui = keyframes[i].second;
double uNext = keyframes[i + 1].second;
if (u <= uNext) {
double uScaled = (u - ui) / (uNext - ui);
uScaled = ghoul::quadraticEaseInOut(uScaled);
result = glm::slerp(keyframes[i].first, keyframes[i + 1].first, uScaled);
break;
}
}
return result;
return _curve->rotationAt(u);
}
// Initialise the curve, based on the start, end state and curve type
-1
View File
@@ -57,7 +57,6 @@ public:
glm::dquat getRotationAt(double u) const;
private:
const glm::dquat piecewiseSlerpRotation(double u) const;
void initCurve();
// The speed function describing the shape of the speed curve. Values in [0,1].
@@ -0,0 +1,113 @@
/*****************************************************************************************
* *
* 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. *
****************************************************************************************/
#include <modules/autonavigation/pathcurves.h>
#include <modules/autonavigation/helperfunctions.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/logging/logmanager.h>
namespace {
constexpr const char* _loggerCat = "RotationInterpolator";
} // namespace
namespace openspace::autonavigation {
RotationInterpolator::RotationInterpolator(
const CameraState& start, const CameraState& end, PathCurve* curve, RotationMethod method)
: _start(start), _end(end), _method(method)
{
_curve = curve;
}
glm::dquat RotationInterpolator::rotationAt(double u) {
switch (_method)
{
case Slerp:
return easedSlerp(u);
break;
case PiecewiseSlerp:
return piecewiseSlerp(u);
break;
case Fixed:
return _start.rotation;
break;
default:
LERROR("Non-implemented orientation interpolation method!");
return _start.rotation;
break;
}
}
glm::dquat RotationInterpolator::easedSlerp(double u) {
double uScaled = helpers::shiftAndScale(u, 0.1, 0.9);
uScaled = ghoul::cubicEaseInOut(uScaled);
return glm::slerp(_start.rotation, _end.rotation, uScaled);
}
// Interpolate between a number of keyframes for orientation using SLERP
glm::dquat RotationInterpolator::piecewiseSlerp(double u) {
ghoul_assert(_curve, "Rotation interpolation requires access to curve positions.");
// breakpoints for subintervals
const double u1 = 0.3;
const double u2 = 0.8; // TODO: these should probably be based on distance
glm::dvec3 startNodePos = sceneGraphNode(_start.referenceNode)->worldPosition();
glm::dvec3 endNodePos = sceneGraphNode(_end.referenceNode)->worldPosition();
glm::dvec3 startUpVec = _start.rotation * glm::dvec3(0.0, 1.0, 0.0);
glm::dvec3 endUpVec = _end.rotation * glm::dvec3(0.0, 1.0, 0.0);
glm::dquat lookAtStartQ =
helpers::getLookAtQuaternion(_curve->positionAt(u1), startNodePos, startUpVec);
glm::dquat lookAtEndQ =
helpers::getLookAtQuaternion(_curve->positionAt(u2), endNodePos, endUpVec);
std::vector<std::pair<glm::dquat, double>> keyframes{
{_start.rotation, 0.0},
{lookAtStartQ, u1},
{lookAtEndQ, u2},
{_end.rotation, 1.0}
};
// Find the current segment and compute interpolation
glm::dquat result;
for (int i = 0; i < keyframes.size() - 1; ++i) {
double ui = keyframes[i].second;
double uNext = keyframes[i + 1].second;
if (u <= uNext) {
double uScaled = (u - ui) / (uNext - ui);
uScaled = ghoul::quadraticEaseInOut(uScaled);
result = glm::slerp(keyframes[i].first, keyframes[i + 1].first, uScaled);
break;
}
}
return result;
}
} // namespace openspace::autonavigation
@@ -0,0 +1,60 @@
/*****************************************************************************************
* *
* 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_MODULE_AUTONAVIGATION___ROTATIONINTERPOLATOR___H__
#define __OPENSPACE_MODULE_AUTONAVIGATION___ROTATIONINTERPOLATOR___H__
#include <modules/autonavigation/camerastate.h>
namespace openspace::autonavigation {
enum RotationMethod {
Slerp,
PiecewiseSlerp,
Fixed
};
class PathCurve;
class RotationInterpolator {
public:
RotationInterpolator() = default;
RotationInterpolator(const CameraState& start, const CameraState& end,
PathCurve* curve, RotationMethod method);
glm::dquat rotationAt(double u);
private:
CameraState _start;
CameraState _end;
PathCurve* _curve = nullptr;
RotationMethod _method;
glm::dquat easedSlerp(double u);
glm::dquat piecewiseSlerp(double u);
};
} // namespace openspace::autonavigation
#endif // __OPENSPACE_MODULE_AUTONAVIGATION___ROTATIONINTERPOLATOR___H__