Skip to content

Commit 1d0c608

Browse files
authored
Add a setting to control whether gotoSurface preserve initial orientation or not (CelestiaProject#2363)
The current implementation preserves orientation, so after you land you might be looking up or down, not necessarily looking parallel to the surface. adding this for VR/game controller, because in VR/AR you would want the planet surface to be matching the actual environment when you land, the landing orientation should be consistent.
1 parent 33ceae7 commit 1d0c608

File tree

9 files changed

+110
-23
lines changed

9 files changed

+110
-23
lines changed

celestia.cfg.in

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,15 @@ StarTextures
289289
# FocusZooming true
290290

291291

292+
#------------------------------------------------------------------------
293+
# AlignCameraToSurfaceOnLand enables aligning the camera orientation
294+
# to be parallel with the planetary surface when landing. If false,
295+
# the current camera orientation is preserved during landing.
296+
# The default value is false.
297+
#------------------------------------------------------------------------
298+
# AlignCameraToSurfaceOnLand true
299+
300+
292301
#------------------------------------------------------------------------
293302
# The following parameter is used in Lua (.celx) scripting.
294303
#

src/celengine/observer.cpp

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,9 @@ createFrame(ObserverFrame::CoordinateSystem _coordSys,
408408
* updates due to an active goto operation.
409409
*/
410410

411-
Observer::Observer() :
412-
frame(std::make_shared<ObserverFrame>())
411+
Observer::Observer(const std::shared_ptr<celestia::engine::ObserverSettings>& settings) :
412+
frame(std::make_shared<ObserverFrame>()),
413+
settings(settings)
413414
{
414415
updateUniversal();
415416
}
@@ -438,6 +439,7 @@ Observer::Observer(const Observer& o) :
438439
zoom(o.zoom),
439440
alternateZoom(o.alternateZoom),
440441
reverseFlag(o.reverseFlag),
442+
settings(o.settings),
441443
locationFilter(o.locationFilter),
442444
displayedSurface(o.displayedSurface)
443445
{
@@ -470,6 +472,7 @@ Observer& Observer::operator=(const Observer& o)
470472
zoom = o.zoom;
471473
alternateZoom = o.alternateZoom;
472474
reverseFlag = o.reverseFlag;
475+
settings = o.settings;
473476
locationFilter = o.locationFilter;
474477
displayedSurface = o.displayedSurface;
475478

@@ -1505,26 +1508,53 @@ Observer::getSelectionLongLat(const Selection& selection,
15051508
void
15061509
Observer::gotoSurface(const Selection& sel, double duration)
15071510
{
1508-
Eigen::Vector3d v = getPosition().offsetFromKm(sel.getPosition(getTime()));
1509-
v.normalize();
1510-
1511-
Eigen::Vector3d viewDir = originalOrientationUniv.conjugate() * -Eigen::Vector3d::UnitZ();
1512-
Eigen::Vector3d up = originalOrientationUniv.conjugate() * Eigen::Vector3d::UnitY();
1513-
Eigen::Quaterniond q = originalOrientationUniv;
1514-
if (v.dot(viewDir) < 0.0)
1515-
{
1516-
q = math::LookAt<double>(Eigen::Vector3d::Zero(), up, v);
1517-
}
1518-
15191511
ObserverFrame selFrame(ObserverFrame::CoordinateSystem::BodyFixed, sel);
15201512
UniversalCoord bfPos = selFrame.convertFromUniversal(positionUniv, getTime());
1521-
q = selFrame.convertFromUniversal(q, getTime());
15221513

1514+
// Calculate the surface normal at the landing point (radial direction from center)
1515+
Eigen::Vector3d surfaceNormal = bfPos.offsetFromKm(UniversalCoord::Zero()).normalized();
1516+
1517+
// Position the observer just above the surface
15231518
double height = 1.0001 * sel.radius();
1524-
Eigen::Vector3d dir = bfPos.offsetFromKm(UniversalCoord::Zero()).normalized() * height;
1525-
UniversalCoord nearSurfacePoint = UniversalCoord::Zero().offsetKm(dir);
1519+
UniversalCoord nearSurfacePoint = UniversalCoord::Zero().offsetKm(surfaceNormal * height);
1520+
1521+
Eigen::Quaterniond toOrientation;
1522+
if (celestia::util::is_set(settings->flags, celestia::engine::ObserverFlags::AlignCameraToSurfaceOnLand))
1523+
{
1524+
// Get the current orientation in the body-fixed frame
1525+
Eigen::Quaterniond currentOrientation = selFrame.convertFromUniversal(originalOrientationUniv, getTime());
1526+
1527+
// Use the window's up direction (UnitY) as the forward direction
1528+
Eigen::Vector3d windowUp = currentOrientation.conjugate() * Eigen::Vector3d::UnitY();
1529+
1530+
// Project the window's up direction onto the surface plane to get the tangent direction
1531+
Eigen::Vector3d tangentDirection = windowUp - surfaceNormal * surfaceNormal.dot(windowUp);
15261532

1527-
gotoLocation(nearSurfacePoint, q, duration);
1533+
// Fallback if the projection is too small. In this case the planet is
1534+
// below or above us (likely not within viewport) so we can just use an
1535+
// arbitrary orientation.
1536+
if (tangentDirection.norm() < 0.1)
1537+
{
1538+
Eigen::Vector3d reference = (std::abs(surfaceNormal.dot(Eigen::Vector3d::UnitY())) < 0.9) ? Eigen::Vector3d::UnitY() : Eigen::Vector3d::UnitX();
1539+
tangentDirection = surfaceNormal.cross(reference);
1540+
}
1541+
1542+
tangentDirection.normalize();
1543+
toOrientation = math::LookAt<double>(Eigen::Vector3d::Zero(), tangentDirection, surfaceNormal);
1544+
}
1545+
else
1546+
{
1547+
Eigen::Vector3d v = getPosition().offsetFromKm(sel.getPosition(getTime()));
1548+
Eigen::Vector3d viewDir = originalOrientationUniv.conjugate() * -Eigen::Vector3d::UnitZ();
1549+
Eigen::Vector3d up = originalOrientationUniv.conjugate() * Eigen::Vector3d::UnitY();
1550+
toOrientation = originalOrientationUniv;
1551+
if (v.dot(viewDir) < 0.0)
1552+
{
1553+
toOrientation = math::LookAt<double>(Eigen::Vector3d::Zero(), up, v);
1554+
}
1555+
toOrientation = selFrame.convertFromUniversal(toOrientation, getTime());
1556+
}
1557+
gotoLocation(nearSurfacePoint, toOrientation, duration);
15281558
}
15291559

15301560
void

src/celengine/observer.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include <Eigen/Geometry>
2828

2929
#include <celcompat/numbers.h>
30+
#include <celutil/flag.h>
31+
3032
#include "selection.h"
3133
#include "shared.h"
3234
#include "univcoord.h"
@@ -37,6 +39,19 @@ namespace celestia::engine
3739
constexpr inline double MIN_SIG_ANGULAR_SPEED = 1.0e-10;
3840
constexpr inline double MIN_SIG_LINEAR_SPEED = 1.0e-12;
3941

42+
enum class ObserverFlags : unsigned int
43+
{
44+
None = 0x0,
45+
AlignCameraToSurfaceOnLand = 0x1,
46+
};
47+
48+
struct ObserverSettings
49+
{
50+
ObserverFlags flags{ ObserverFlags::None };
51+
};
52+
53+
ENUM_CLASS_BITWISE_OPS(ObserverFlags);
54+
4055
}
4156

4257
class ReferenceFrame;
@@ -127,7 +142,7 @@ class Observer
127142
static constexpr const double EndInterpolation = 0.75;
128143
static constexpr const double AccelerationTime = 0.5;
129144

130-
Observer();
145+
explicit Observer(const std::shared_ptr<celestia::engine::ObserverSettings>&);
131146
Observer(const Observer &o);
132147
~Observer() = default;
133148

@@ -351,6 +366,8 @@ class Observer
351366

352367
bool reverseFlag{ false };
353368

369+
std::shared_ptr<celestia::engine::ObserverSettings> settings;
370+
354371
std::uint64_t locationFilter{ DefaultLocationFilter };
355372
std::string displayedSurface;
356373
};

src/celengine/simulation.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
#include "render.h"
2222

2323

24-
Simulation::Simulation(Universe* _universe) :
25-
universe(_universe)
24+
Simulation::Simulation(Universe* universe, const std::shared_ptr<celestia::engine::ObserverSettings>& observerSettings) :
25+
universe(universe)
2626
{
27-
activeObserver = new Observer();
27+
activeObserver = new Observer(observerSettings);
2828
observers.push_back(activeObserver);
2929
}
3030

src/celengine/simulation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class Renderer;
3333
class Simulation
3434
{
3535
public:
36-
explicit Simulation(Universe*);
36+
Simulation(Universe*, const std::shared_ptr<celestia::engine::ObserverSettings>&);
3737
~Simulation();
3838

3939
double getTime() const; // Julian date

src/celestia/celestiacore.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2090,6 +2090,16 @@ void CelestiaCore::setInteractionFlags(InteractionFlags flags)
20902090
interactionFlags = flags;
20912091
}
20922092

2093+
celestia::engine::ObserverFlags CelestiaCore::getObserverFlags() const
2094+
{
2095+
return observerSettings->flags;
2096+
}
2097+
2098+
void CelestiaCore::setObserverFlags(celestia::engine::ObserverFlags flags)
2099+
{
2100+
observerSettings->flags = flags;
2101+
}
2102+
20932103
// Return true if anything changed that requires re-rendering. Otherwise, we
20942104
// can skip rendering, keep the GPU idle, and save power.
20952105
bool CelestiaCore::viewUpdateRequired() const
@@ -2563,7 +2573,9 @@ bool CelestiaCore::initSimulation(const std::filesystem::path& configFileName,
25632573
set_or_unset(interactionFlags, InteractionFlags::RayBasedDragging, config->mouse.rayBasedDragging);
25642574
set_or_unset(interactionFlags, InteractionFlags::FocusZooming, config->mouse.focusZooming);
25652575

2566-
sim = new Simulation(universe);
2576+
set_or_unset(observerSettings->flags, celestia::engine::ObserverFlags::AlignCameraToSurfaceOnLand, config->observer.alignCameraToSurfaceOnLand);
2577+
2578+
sim = new Simulation(universe, observerSettings);
25672579
if (!util::is_set(renderer->getRenderFlags(), RenderFlags::ShowAutoMag))
25682580
{
25692581
sim->setFaintestVisible(config->renderDetails.faintestVisible);

src/celestia/celestiacore.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,9 @@ class CelestiaCore // : public Watchable<CelestiaCore>
319319
InteractionFlags getInteractionFlags() const;
320320
void setInteractionFlags(InteractionFlags);
321321

322+
celestia::engine::ObserverFlags getObserverFlags() const;
323+
void setObserverFlags(celestia::engine::ObserverFlags);
324+
322325
void setFOVFromZoom();
323326
void setZoomFromFOV();
324327

@@ -436,6 +439,8 @@ class CelestiaCore // : public Watchable<CelestiaCore>
436439
Simulation* sim{ nullptr };
437440
Renderer* renderer{ nullptr };
438441

442+
std::shared_ptr<celestia::engine::ObserverSettings> observerSettings{ std::make_shared<celestia::engine::ObserverSettings>() };
443+
439444
static std::locale loc;
440445

441446
celestia::WindowMetrics metrics;

src/celestia/configfile.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,13 @@ applyMouse(CelestiaConfig::Mouse& mouse, const AssociativeArray& hash)
178178
}
179179

180180

181+
void
182+
applyObserver(CelestiaConfig::Observer& observer, const AssociativeArray& hash)
183+
{
184+
applyBoolean(observer.alignCameraToSurfaceOnLand, hash, "AlignCameraToSurfaceOnLand"sv);
185+
}
186+
187+
181188
void
182189
applyRenderDetails(CelestiaConfig::RenderDetails& renderDetails, const AssociativeArray& hash)
183190
{
@@ -280,6 +287,7 @@ bool ReadCelestiaConfig(const std::filesystem::path& filename, CelestiaConfig& c
280287
applyPaths(config.paths, *configParams);
281288
applyFonts(config.fonts, *configParams);
282289
applyMouse(config.mouse, *configParams);
290+
applyObserver(config.observer, *configParams);
283291
applyRenderDetails(config.renderDetails, *configParams);
284292
applyStarTextures(config.starTextures, *configParams, "StarTextures"sv);
285293

src/celestia/configfile.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ struct CelestiaConfig
6363
bool focusZooming{ false };
6464
};
6565

66+
struct Observer
67+
{
68+
bool alignCameraToSurfaceOnLand{ false };
69+
};
70+
6671
struct RenderDetails
6772
{
6873
double orbitWindowEnd{ 0.5 };
@@ -96,6 +101,7 @@ struct CelestiaConfig
96101
Paths paths{ };
97102
Fonts fonts{ };
98103
Mouse mouse{ };
104+
Observer observer{ };
99105
RenderDetails renderDetails{ };
100106
StarDetails::StarTextureSet starTextures{ };
101107

0 commit comments

Comments
 (0)