mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-22 19:29:04 -05:00
Move rotation logic into its own class
This commit is contained in:
@@ -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})
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
Reference in New Issue
Block a user