diff --git a/data/assets/scene/digitaluniverse/milkyway_sphere.asset b/data/assets/scene/digitaluniverse/milkyway_sphere.asset index 2900df69f6..a3b094106c 100644 --- a/data/assets/scene/digitaluniverse/milkyway_sphere.asset +++ b/data/assets/scene/digitaluniverse/milkyway_sphere.asset @@ -24,7 +24,8 @@ local sphere = { RenderBinMode = "PreDeferredTransparent", MirrorTexture = true, FadeOutThreshold = 0.0015, - Background = true + Background = true, + DimInAtmosphere = true, }, GUI = { Name = "Milky Way Sphere", diff --git a/data/assets/scene/digitaluniverse/stars.asset b/data/assets/scene/digitaluniverse/stars.asset index a5a9e60cb0..de84d9a1d6 100644 --- a/data/assets/scene/digitaluniverse/stars.asset +++ b/data/assets/scene/digitaluniverse/stars.asset @@ -47,7 +47,8 @@ local stars = { Vy = "vy", Vz = "vz", Speed = "speed" - } + }, + DimInAtmosphere = true, }, GUI = { Name = "Stars", @@ -84,7 +85,8 @@ local sunstar = { Vy = "vy", Vz = "vz", Speed = "speed", - } + }, + DimInAtmosphere = true, }, GUI = { Name = "Sun Star", diff --git a/include/openspace/camera/camera.h b/include/openspace/camera/camera.h index ee32007c05..10360e27cf 100644 --- a/include/openspace/camera/camera.h +++ b/include/openspace/camera/camera.h @@ -74,6 +74,8 @@ public: void setScaling(float scaling); void setMaxFov(float fov); void setParent(SceneGraphNode* parent); + // Atmosphere dimming factor determines how much an atmosphere dims objects + void setAtmosphereDimmingFactor(float atmosphereDimmingFactor); // Relative mutators void rotate(glm::dquat rotation); @@ -93,6 +95,7 @@ public: float sinMaxFov() const; SceneGraphNode* parent() const; float scaling() const; + float atmosphereDimmingFactor() const; // @TODO this should simply be called viewMatrix! // Or it needs to be changed so that it actually is combined. Right now it is @@ -155,6 +158,8 @@ private: SyncData _scaling = 1.f; SceneGraphNode* _parent = nullptr; + float _atmosphereDimmingFactor = 1.f; + // _focusPosition to be removed glm::dvec3 _focusPosition = glm::dvec3(0.0); float _maxFov = 0.f; diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index b698650698..c9dc788a9e 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -107,6 +107,7 @@ protected: properties::FloatProperty _opacity; properties::FloatProperty _fade; properties::StringProperty _renderableType; + properties::BoolProperty _dimInAtmosphere; void setBoundingSphere(double boundingSphere); void setInteractionSphere(double interactionSphere); diff --git a/modules/atmosphere/rendering/renderableatmosphere.cpp b/modules/atmosphere/rendering/renderableatmosphere.cpp index bfdef0f33a..807f5d5114 100644 --- a/modules/atmosphere/rendering/renderableatmosphere.cpp +++ b/modules/atmosphere/rendering/renderableatmosphere.cpp @@ -25,13 +25,18 @@ #include #include +#include #include #include #include +#include +#include #include #include namespace { + constexpr const float KM_TO_M = 1000.f; + constexpr openspace::properties::Property::PropertyInfo AtmosphereHeightInfo = { "AtmosphereHeight", "Atmosphere Height (KM)", @@ -132,6 +137,18 @@ namespace { "Enable/Disables hard shadows through the atmosphere" }; + constexpr openspace::properties::Property::PropertyInfo AtmosphereDimmingHeightInfo ={ + "AtmosphereDimmingHeight", + "Atmosphere Dimming Height", + "Percentage of the atmosphere where other objects, such as the stars, are faded." + }; + + constexpr openspace::properties::Property::PropertyInfo SunsetAngleInfo = { + "AtmosphereDimmingSunsetAngle", + "Atmosphere Dimming Sunset Angle", + "The angle (degrees) between the Camera and the Sun where the sunset starts, and " + "the atmosphere starts to fade in objects such as the stars." + }; struct [[codegen::Dictionary(RenderableAtmosphere)]] Parameters { struct ShadowGroup { @@ -212,6 +229,12 @@ namespace { std::optional saveCalculatedTextures; }; std::optional debug; + + // [[codegen::verbatim(AtmosphereDimmingHeightInfo.description)]] + std::optional atmosphereDimmingHeight; + + // [[codegen::verbatim(SunsetAngleInfo.description)]] + std::optional sunsetAngle; }; #include "renderableatmosphere_codegen.cpp" @@ -252,6 +275,10 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary) , _sunIntensity(SunIntensityInfo, 5.f, 0.1f, 1000.f) , _sunFollowingCameraEnabled(EnableSunOnCameraPositionInfo, false) , _hardShadowsEnabled(EclipseHardShadowsInfo, false) + , _atmosphereDimmingHeight(AtmosphereDimmingHeightInfo, 0.7f, 0.f, 1.f) + , _atmosphereDimmingSunsetAngle(SunsetAngleInfo, + glm::vec2(95.f, 100.f), glm::vec2(0.f), glm::vec2(180.f) + ) { auto updateWithCalculation = [this]() { _deferredCasterNeedsUpdate = true; @@ -355,6 +382,17 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary) } setBoundingSphere(_planetRadius * 1000.0); + + _atmosphereDimmingHeight = p.atmosphereDimmingHeight.value_or(_atmosphereDimmingHeight); + addProperty(_atmosphereDimmingHeight); + + _atmosphereDimmingSunsetAngle = p.sunsetAngle.value_or( + _atmosphereDimmingSunsetAngle + ); + _atmosphereDimmingSunsetAngle.setViewOption( + properties::Property::ViewOptions::MinMaxRange + ); + addProperty(_atmosphereDimmingSunsetAngle); } void RenderableAtmosphere::deinitializeGL() { @@ -406,6 +444,55 @@ void RenderableAtmosphere::update(const UpdateData& data) { glm::dmat4 modelTransform = computeModelTransformMatrix(data.modelTransform); _deferredcaster->setModelTransform(modelTransform); _deferredcaster->update(data); + + // Calculate atmosphere dimming coefficient + // Calculate if the camera is in the atmosphere and if it is in the fading region + float atmosphereDimming = 1.f; + glm::dvec3 cameraPos = global::navigationHandler->camera()->positionVec3(); + glm::dvec3 planetPos = glm::dvec3(modelTransform * glm::dvec4(0.0, 0.0, 0.0, 1.0)); + float cameraDistance = static_cast(glm::distance(planetPos, cameraPos)); + // Atmosphere height is in KM + float atmosphereEdge = KM_TO_M * (_planetRadius + _atmosphereHeight); + // Height of the atmosphere where the objects will be faded + float atmosphereFadingHeight = KM_TO_M * _atmosphereDimmingHeight * _atmosphereHeight; + float atmosphereInnerEdge = atmosphereEdge - atmosphereFadingHeight; + bool cameraIsInAtmosphere = cameraDistance < atmosphereEdge; + bool cameraIsInFadingRegion = cameraDistance > atmosphereInnerEdge; + + // Check if camera is in sunset + glm::dvec3 normalUnderCamera = glm::normalize(cameraPos - planetPos); + glm::dvec3 vecToSun = glm::normalize(-planetPos); + float cameraSunAngle = glm::degrees(static_cast( + glm::acos(glm::dot(vecToSun, normalUnderCamera)) + )); + float sunsetStart = _atmosphereDimmingSunsetAngle.value().x; + float sunsetEnd = _atmosphereDimmingSunsetAngle.value().y; + // If cameraSunAngle is more than 90 degrees, we are in shaded part of globe + bool cameraIsInSun = cameraSunAngle <= sunsetEnd; + bool cameraIsInSunset = cameraSunAngle > sunsetStart && cameraIsInSun; + + // Fade if camera is inside the atmosphere + if (cameraIsInAtmosphere && cameraIsInSun) { + // If camera is in fading part of the atmosphere + // Fade with regards to altitude + if (cameraIsInFadingRegion) { + // Fading - linear interpolation + atmosphereDimming = (cameraDistance - atmosphereInnerEdge) / + atmosphereFadingHeight; + } + else { + // Camera is below fading region - atmosphere dims objects completely + atmosphereDimming = 0.0; + } + if (cameraIsInSunset) { + // Fading - linear interpolation + atmosphereDimming = (cameraSunAngle - sunsetStart) / + (sunsetEnd - sunsetStart); + } + global::navigationHandler->camera()->setAtmosphereDimmingFactor( + atmosphereDimming + ); + } } void RenderableAtmosphere::updateAtmosphereParameters() { diff --git a/modules/atmosphere/rendering/renderableatmosphere.h b/modules/atmosphere/rendering/renderableatmosphere.h index cbc40ac7b1..6c2f1a1384 100644 --- a/modules/atmosphere/rendering/renderableatmosphere.h +++ b/modules/atmosphere/rendering/renderableatmosphere.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,10 @@ private: properties::BoolProperty _sunFollowingCameraEnabled; properties::BoolProperty _hardShadowsEnabled; + // Atmosphere dimming + properties::FloatProperty _atmosphereDimmingHeight; + properties::Vec2Property _atmosphereDimmingSunsetAngle; + float _planetRadius = 0.f; float _mieScattExtPropCoefProp = 1.f; diff --git a/src/camera/camera.cpp b/src/camera/camera.cpp index fc7c9b951c..8997d2ef37 100644 --- a/src/camera/camera.cpp +++ b/src/camera/camera.cpp @@ -156,6 +156,14 @@ float Camera::sinMaxFov() const { return _cachedSinMaxFov.datum; } +void Camera::setAtmosphereDimmingFactor(float atmosphereDimmingFactor) { + _atmosphereDimmingFactor = atmosphereDimmingFactor; +} + +float Camera::atmosphereDimmingFactor() const { + return _atmosphereDimmingFactor; +} + SceneGraphNode* Camera::parent() const { return _parent; } diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index 72577c5a74..b101f6b509 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -24,11 +24,13 @@ #include +#include #include #include #include #include #include +#include #include #include #include @@ -81,6 +83,14 @@ namespace { openspace::properties::Property::Visibility::Developer }; + constexpr openspace::properties::Property::PropertyInfo DimInAtmosphereInfo = { + "DimInAtmosphere", + "Dim In Atmosphere", + "Enables/Disables if the object should be dimmed if the camera is in an " + "atmosphere.", + openspace::properties::Property::Visibility::Developer + }; + struct [[codegen::Dictionary(Renderable)]] Parameters { // [[codegen::verbatim(EnabledInfo.description)]] std::optional enabled; @@ -106,6 +116,9 @@ namespace { // [[codegen::verbatim(RenderableRenderBinModeInfo.description)]] std::optional renderBinMode; + + // [[codegen::verbatim(DimInAtmosphereInfo.description)]] + std::optional dimInAtmosphere; }; #include "renderable_codegen.cpp" } // namespace @@ -146,6 +159,7 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary) , _opacity(OpacityInfo, 1.f, 0.f, 1.f) , _fade(FadeInfo, 1.f, 0.f, 1.f) , _renderableType(RenderableTypeInfo, "Renderable") + , _dimInAtmosphere(DimInAtmosphereInfo, false) { ZoneScoped @@ -193,6 +207,9 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary) if (p.renderBinMode.has_value()) { setRenderBin(codegen::map(*p.renderBinMode)); } + + _dimInAtmosphere = p.dimInAtmosphere.value_or(_dimInAtmosphere); + addProperty(_dimInAtmosphere); } void Renderable::initialize() {} @@ -292,7 +309,10 @@ void Renderable::registerUpdateRenderBinFromOpacity() { } float Renderable::opacity() const { - return _opacity * _fade; + // Rendering should depend on if camera is in the atmosphere and if camera is at the + // dark part of the globe + return _dimInAtmosphere ? + _opacity * _fade * global::navigationHandler->camera()->atmosphereDimmingFactor() : + _opacity * _fade; } - } // namespace openspace diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index f82ad1c7bd..669e398a9f 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -334,6 +334,7 @@ void Scene::update(const UpdateData& data) { if (_dirtyNodeRegistry) { updateNodeRegistry(); } + _camera->setAtmosphereDimmingFactor(1.f); for (SceneGraphNode* node : _topologicallySortedNodes) { try { node->update(data);