diff --git a/data/assets/scene/solarsystem/sun/light_source.asset b/data/assets/scene/solarsystem/sun/light_source.asset index d96585a138..3f483eaf3d 100644 --- a/data/assets/scene/solarsystem/sun/light_source.asset +++ b/data/assets/scene/solarsystem/sun/light_source.asset @@ -21,4 +21,4 @@ asset.onDeinitialize(function() openspace.removeSceneGraphNode(LightSource) end) -asset.export("LightSource", LightSource) \ No newline at end of file +asset.export("LightSource", LightSource) diff --git a/modules/base/rendering/directionallightsource.cpp b/modules/base/rendering/directionallightsource.cpp index e9a2b794fa..cd8c1a4897 100644 --- a/modules/base/rendering/directionallightsource.cpp +++ b/modules/base/rendering/directionallightsource.cpp @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2024 * + * Copyright (c) 2014-2025 * * * * 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 * @@ -22,26 +22,27 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include #include -#include +#include +#include #include +#include #include #include -#include - #include #include - #include namespace { constexpr std::string_view _loggerCat = "DirectionalLightsource"; - + + constexpr int DepthMapResolutionMultiplier = 4; + constexpr double ShadowFrustumDistanceMultiplier = 500.0; + struct [[codegen::Dictionary(DirectionalLightsource)]] Parameters { - + }; #include "DirectionalLightsource_codegen.cpp" } // namespace @@ -49,7 +50,7 @@ namespace { namespace openspace { documentation::Documentation DirectionalLightSource::Documentation() { - return codegen::doc("base_renderable_cartesianaxes"); + return codegen::doc("base_renderable_directionallightsource"); } DirectionalLightSource::DirectionalLightSource(const ghoul::Dictionary& dictionary) @@ -63,7 +64,8 @@ bool DirectionalLightSource::isReady() const { } void DirectionalLightSource::initialize() { - _depthMapResolution = global::renderEngine->renderingResolution() * 4; + _depthMapResolution = + global::renderEngine->renderingResolution() * DepthMapResolutionMultiplier; } void DirectionalLightSource::initializeGL() { @@ -126,7 +128,12 @@ void DirectionalLightSource::render(const RenderData& data, RendererTasks&){ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, glm::value_ptr(glm::vec4(1.f, 1.f, 1.f, 1.f))); + const glm::vec4 borderColor(1.f, 1.f, 1.f, 1.f); + glTexParameterfv( + GL_TEXTURE_2D, + GL_TEXTURE_BORDER_COLOR, + glm::value_ptr(borderColor) + ); glBindTexture(GL_TEXTURE_2D, 0); _depthMaps[key] = tex; @@ -161,9 +168,16 @@ void DirectionalLightSource::render(const RenderData& data, RendererTasks&){ } double sz = glm::length(vmax - vmin); - double d = sz * 500.; + double d = sz * ShadowFrustumDistanceMultiplier; glm::dvec3 center = vmin + (vmax - vmin) * 0.5; - glm::dvec3 light = parent()->modelTransform() * glm::dvec4(0.0, 0.0, 0.0, 1.0); + + SceneGraphNode* parentNode = parent(); + if (!parentNode) { + LERROR("DirectionalLightSource must have a parent node"); + continue; + } + + glm::dvec3 light = parentNode->modelTransform() * glm::dvec4(0.0, 0.0, 0.0, 1.0); glm::dvec3 light_dir = glm::normalize(center - light); glm::dvec3 right = glm::normalize(glm::cross(glm::dvec3(0, 1, 0), light_dir)); glm::dvec3 eye = center - light_dir * d; diff --git a/modules/base/rendering/directionallightsource.h b/modules/base/rendering/directionallightsource.h index add95f16ad..0999d90b10 100644 --- a/modules/base/rendering/directionallightsource.h +++ b/modules/base/rendering/directionallightsource.h @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2024 * + * Copyright (c) 2014-2025 * * * * 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 * @@ -41,10 +41,19 @@ namespace openspace::documentation { struct Documentation; } namespace openspace { +/** + * DirectionalLightSource is a Renderable that manages shadow mapping for directional + * light sources. It creates depth maps from the light's perspective and manages shadow + * groups to optimize rendering when multiple objects cast shadows. + * + * Shadow groups allow models near each other to share a shadow map, reducing memory + * usage and improving performance by grouping shadow casters that should render into + * the same depth buffer. + */ class DirectionalLightSource : public Renderable { public: struct DepthMapData { - glm::dmat4 viewProjecion; + glm::dmat4 viewProjection; GLuint depthMap; }; @@ -75,7 +84,6 @@ private: std::map _depthMaps; std::map _FBOs; std::map _vps; - std::unique_ptr _lightSource; ghoul::opengl::ProgramObject* _depthMapProgram = nullptr; }; diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index 022ac81e9a..2ef77285b9 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -1330,7 +1330,7 @@ void RenderableModel::update(const UpdateData& data) { } } -const bool RenderableModel::isCastingShadow() const { +bool RenderableModel::isCastingShadow() const { return _castShadow; } @@ -1362,14 +1362,15 @@ glm::dvec3 RenderableModel::center() const { return model * glm::dvec4(0, 0, 0, 1); } -const std::string RenderableModel::lightsource() const { +const std::string& RenderableModel::lightSource() const { return _lightSource; } -const std::string RenderableModel::shadowGroup() const { +const std::string& RenderableModel::shadowGroup() const { return _shadowGroup; } -const double RenderableModel::shadowFrustumSize() const { + +double RenderableModel::shadowFrustumSize() const { return _frustumSize; } diff --git a/modules/base/rendering/renderablemodel.h b/modules/base/rendering/renderablemodel.h index f4b1a273f6..df4db089ad 100644 --- a/modules/base/rendering/renderablemodel.h +++ b/modules/base/rendering/renderablemodel.h @@ -71,15 +71,15 @@ public: void render(const RenderData& data, RendererTasks& rendererTask) override; void update(const UpdateData& data) override; - const bool isCastingShadow() const; + bool isCastingShadow() const; void renderForDepthMap(const glm::dmat4& vp) const; glm::dvec3 center() const; - const std::string lightsource() const; - const std::string shadowGroup() const; - const double shadowFrustumSize() const; + const std::string& lightSource() const; + const std::string& shadowGroup() const; + double shadowFrustumSize() const; static documentation::Documentation Documentation(); diff --git a/modules/base/rendering/renderabletrailtrajectory.cpp b/modules/base/rendering/renderabletrailtrajectory.cpp index a587f0d8f8..ea1af54bf5 100644 --- a/modules/base/rendering/renderabletrailtrajectory.cpp +++ b/modules/base/rendering/renderabletrailtrajectory.cpp @@ -76,8 +76,8 @@ namespace { "The factor that is used to create subsamples along the trajectory. This value " "(together with 'SampleInterval') determines how far apart (in seconds) the " "samples are spaced along the trajectory. Subsamples are rendered as smaller " - "points compared to normal samples (from 'SampleInterval') when rendering the " - "trail as points.", + "points compared to normal samples (from 'SampleInterval') when rendering the " + "trail as points.", openspace::properties::Property::Visibility::AdvancedUser }; @@ -192,7 +192,7 @@ RenderableTrailTrajectory::RenderableTrailTrajectory(const ghoul::Dictionary& di _timeStampSubsamplingFactor = p.timeStampSubsampleFactor.value_or(_timeStampSubsamplingFactor); - _timeStampSubsamplingFactor.onChange([this]() { reset(); }); + _timeStampSubsamplingFactor.onChange([this]() { reset(); }); addProperty(_timeStampSubsamplingFactor); // We store the vertices with ascending temporal order diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 6b99b94d1e..54ccd73a48 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -1077,8 +1077,12 @@ void RenderableGlobe::update(const UpdateData& data) { _shadowersOk = false; _shadowSpec.clear(); - for (const auto model : _shadowers) { - _shadowSpec[model->lightsource()].push_back(model->shadowGroup()); + for (const RenderableModel* model : _shadowers) { + const std::string& modelLightSource = model->lightSource(); + if (!_shadowSpec.contains(modelLightSource)) { + _shadowSpec.emplace(modelLightSource, std::vector{}); + } + _shadowSpec.at(modelLightSource).push_back(model->shadowGroup()); } } break; @@ -1376,7 +1380,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, bool renderGeomOnly) for (const auto& grp : groups) { depthMapData.push_back( { - .viewProjecion = src->viewProjectionMatrix(grp), + .viewProjection = src->viewProjectionMatrix(grp), .depthMap = src->depthMap(grp) } ); @@ -1518,7 +1522,7 @@ void RenderableGlobe::renderChunkGlobally(const Chunk& chunk, const RenderData& std::vector light_vps; std::vector> depthmapTextureUnits; for (const DirectionalLightSource::DepthMapData& depthData : depthMapData) { - light_vps.push_back(depthData.viewProjecion); + light_vps.push_back(depthData.viewProjection); depthmapTextureUnits.emplace_back(ghoul::opengl::TextureUnit(), depthData.depthMap); } @@ -1742,7 +1746,7 @@ void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& d std::vector light_vps; std::vector> depthmapTextureUnits; for (const DirectionalLightSource::DepthMapData& depthData : depthMapData) { - light_vps.push_back(depthData.viewProjecion); + light_vps.push_back(depthData.viewProjection); depthmapTextureUnits.emplace_back(ghoul::opengl::TextureUnit(), depthData.depthMap); } @@ -2751,21 +2755,21 @@ void RenderableGlobe::freeChunkNode(Chunk* n) { } std::vector RenderableGlobe::getShadowers(const SceneGraphNode* node) { - std::vector shadowers; + std::vector shadowers; - if (node) { - const RenderableModel* model = dynamic_cast(node->renderable()); - if (model && model->isCastingShadow()) { - shadowers.push_back(model); - } + if (node) { + const RenderableModel* model = dynamic_cast(node->renderable()); + if (model && model->isCastingShadow()) { + shadowers.push_back(model); + } - for (const SceneGraphNode* child : node->children()) { - std::vector res = getShadowers(child); - shadowers.insert(shadowers.end(), res.begin(), res.end()); - } - } + for (const SceneGraphNode* child : node->children()) { + std::vector res = getShadowers(child); + shadowers.insert(shadowers.end(), res.begin(), res.end()); + } + } - return shadowers; + return shadowers; } void RenderableGlobe::mergeChunkNode(Chunk& cn) {