From 36fc575ffd90d08a72ecc6e3852d3a0442834aae Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Dec 2025 21:12:01 +0100 Subject: [PATCH] Some more cleanup of the PR --- data/assets/examples/celestial_globe.asset | 11 +- ext/ghoul | 2 +- include/openspace/events/event.h | 2 +- .../openspace/rendering/framebufferrenderer.h | 10 +- include/openspace/rendering/renderengine.h | 10 +- include/openspace/rendering/shadowmapping.h | 7 +- .../lightsource/scenegraphlightsource.cpp | 4 - .../base/lightsource/scenegraphlightsource.h | 1 - modules/base/rendering/renderablemodel.cpp | 29 ++--- modules/base/rendering/renderablemodel.h | 6 +- modules/globebrowsing/src/renderableglobe.cpp | 42 ++----- modules/globebrowsing/src/renderableglobe.h | 1 - src/rendering/framebufferrenderer.cpp | 108 ++++++++++++------ src/rendering/renderengine.cpp | 45 ++++++-- src/rendering/shadowmapping.cpp | 9 ++ src/scene/scene_lua.inl | 83 ++++++++++++++ 16 files changed, 252 insertions(+), 118 deletions(-) diff --git a/data/assets/examples/celestial_globe.asset b/data/assets/examples/celestial_globe.asset index bd9929fc97..02ec619d69 100644 --- a/data/assets/examples/celestial_globe.asset +++ b/data/assets/examples/celestial_globe.asset @@ -5,7 +5,6 @@ local sun = asset.require("scene/solarsystem/sun/sun") local sun_transforms = asset.require("scene/solarsystem/sun/transforms") - -- Model CC0 from https://sketchfab.com/3d-models/celestial-globe-341fa8a777e94883841409438756f747 local celestial_globe_folder = asset.resource({ Name = "Celestial Globe", @@ -14,8 +13,8 @@ local celestial_globe_folder = asset.resource({ Version = 1 }) --- These models are in the same shadow group, so will cast onto and receive --- shadows from each other, as well as the Mars surface +-- These models are in the same shadow group, so will cast onto and receive shadows from +-- each other, as well as the Mars surface local ModelMarsSmall = { Identifier = "celestial-globe-mars1", Parent = mars.Mars.Identifier, @@ -215,12 +214,16 @@ local ModelMoon = { asset.onInitialize(function() openspace.addSceneGraphNode(ModelMarsSmall) openspace.registerShadowcaster(sun.LightSource.Identifier, ModelMarsSmall.Identifier, mars.Mars.Identifier, "mars") - openspace.addSceneGraphNode(ModelMarsLarge) + +openspace.addSceneGraphNode(ModelMarsLarge) openspace.registerShadowcaster(sun.LightSource.Identifier, ModelMarsLarge.Identifier, mars.Mars.Identifier, "mars") + openspace.addSceneGraphNode(ModelMarsOtherGroup) openspace.registerShadowcaster(sun.LightSource.Identifier, ModelMarsOtherGroup.Identifier, mars.Mars.Identifier) + openspace.addSceneGraphNode(ModelEarth) openspace.registerShadowcaster(sun.LightSource.Identifier, ModelEarth.Identifier, earth.Earth.Identifier, "earth") + openspace.addSceneGraphNode(ModelMoon) openspace.registerShadowcaster(sun.LightSource.Identifier, ModelMoon.Identifier, moon.Moon.Identifier, "moon") end) diff --git a/ext/ghoul b/ext/ghoul index c748bc9d41..80947f9bbd 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit c748bc9d416821b46af25d1e23ff4f4c89a75993 +Subproject commit 80947f9bbd76730cc4e35dc7c0035afd84272bc0 diff --git a/include/openspace/events/event.h b/include/openspace/events/event.h index 146e057e5c..585d3c6d1e 100644 --- a/include/openspace/events/event.h +++ b/include/openspace/events/event.h @@ -634,7 +634,7 @@ struct CustomEvent : public Event { * * \pre subtype_ must not be empty */ - CustomEvent(std::string_view subtype_, std::string_view payload_ = ""); + CustomEvent(std::string_view subtype_, std::string_view payload_); const tstring subtype; const tstring payload; diff --git a/include/openspace/rendering/framebufferrenderer.h b/include/openspace/rendering/framebufferrenderer.h index e117828717..feb6c05492 100644 --- a/include/openspace/rendering/framebufferrenderer.h +++ b/include/openspace/rendering/framebufferrenderer.h @@ -178,9 +178,11 @@ public: virtual void deferredcastersChanged(Deferredcaster& deferredcaster, DeferredcasterListener::IsAttached isAttached) override; - void registerShadowCaster(const std::string& shadowgroup, const SceneGraphNode* lightsource, - const SceneGraphNode* target); - std::pair shadowInformation(const SceneGraphNode* node, const std::string& shadowgroup) const; + void registerShadowCaster(const std::string& shadowGroup, + const SceneGraphNode* lightsource, const SceneGraphNode* target); + void removeShadowCaster(const std::string& shadowGroup, const SceneGraphNode* target); + + std::pair shadowInformation(const std::string& shadowgroup) const; private: using RaycasterProgObjMap = std::map< @@ -251,7 +253,7 @@ private: struct ShadowMap { const SceneGraphNode* lightsource = nullptr; - std::vector shadowGroups; + std::vector targets; GLuint depthMap = 0; glm::ivec2 depthMapResolution = glm::ivec2(0); GLuint fbo = 0; diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index 114d7766aa..8162eb5a11 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,7 @@ class Camera; class DeferredcasterManager; class RaycasterManager; class Scene; +class SceneGraphNode; class SceneManager; class ScreenLog; class ScreenSpaceRenderable; @@ -161,8 +163,12 @@ public: uint64_t frameNumber() const; - void registerShadowCaster(const std::string& shadowgroup, const SceneGraphNode* lightsource, SceneGraphNode* shadower, SceneGraphNode* shadowee); - std::pair shadowInformation(const SceneGraphNode* node, const std::string& shadowgroup) const; + void registerShadowCaster(const std::string& shadowgroup, + const SceneGraphNode* lightSource, SceneGraphNode* shadower, + SceneGraphNode* shadowee); + void removeShadowCaster(const std::string& shadowgroup, SceneGraphNode* shadower, + SceneGraphNode* shadowee); + std::pair shadowInformation(const std::string& shadowgroup) const; private: void renderScreenLog(); diff --git a/include/openspace/rendering/shadowmapping.h b/include/openspace/rendering/shadowmapping.h index aa8220f1db..fb7e589d9e 100644 --- a/include/openspace/rendering/shadowmapping.h +++ b/include/openspace/rendering/shadowmapping.h @@ -50,11 +50,13 @@ public: const std::string& shadowGroup() const; double shadowFrustumSize() const; + virtual glm::dvec3 center() const = 0; + + virtual void renderForDepthMap(const glm::dmat4& vp) const = 0; + static documentation::Documentation Documentation(); protected: - virtual void renderForDepthMap(const glm::dmat4& vp) const = 0; - properties::BoolProperty _castShadow; const SceneGraphNode* _lightSource = nullptr; std::string _shadowGroup; @@ -68,6 +70,7 @@ protected: class Shadowee { public: void addShadower(const Shadower* shadower); + void removeShadower(const Shadower* shadower); protected: std::vector _shadowers; diff --git a/modules/base/lightsource/scenegraphlightsource.cpp b/modules/base/lightsource/scenegraphlightsource.cpp index 401fda4d6a..fda3b79e89 100644 --- a/modules/base/lightsource/scenegraphlightsource.cpp +++ b/modules/base/lightsource/scenegraphlightsource.cpp @@ -102,10 +102,6 @@ float SceneGraphLightSource::intensity() const { return _intensity; } -glm::dvec3 SceneGraphLightSource::positionWorldSpace() const { - return _sceneGraphNode->modelTransform() * glm::dvec4(0.0, 0.0, 0.0, 1.0); -} - glm::vec3 SceneGraphLightSource::directionViewSpace(const RenderData& renderData) const { if (!_sceneGraphNode) { return glm::vec3(0.f); diff --git a/modules/base/lightsource/scenegraphlightsource.h b/modules/base/lightsource/scenegraphlightsource.h index a0c8ebcf39..4948b007a1 100644 --- a/modules/base/lightsource/scenegraphlightsource.h +++ b/modules/base/lightsource/scenegraphlightsource.h @@ -43,7 +43,6 @@ public: bool initialize() override; glm::vec3 directionViewSpace(const RenderData& renderData) const override; float intensity() const override; - glm::dvec3 positionWorldSpace() const; private: properties::FloatProperty _intensity; diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index 04985fd4ea..158deefec8 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -25,12 +25,9 @@ #include #include -#include #include #include #include -#include -#include #include #include #include @@ -365,9 +362,9 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary) , _enableDepthTest(EnableDepthTestInfo, true) , _blendingFuncOption(BlendingOptionInfo) , _renderWireframe(RenderWireframeInfo, false) - , _lightSourcePropertyOwner({ "LightSources", "Light Sources" }) , _useOverrideColor(UseOverrideColorInfo, false) , _overrideColor(OverrideColorInfo, glm::vec4(0, 0, 0, 1)) + , _lightSourcePropertyOwner({ "LightSources", "Light Sources" }) { const Parameters p = codegen::bake(dictionary); @@ -526,10 +523,10 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary) setInteractionSphere(boundingSphere() * 0.1); if (_hasFrustumSize) { - const float radius = _geometry->boundingRadius() * _modelScale; - _frustumSize = radius; - _frustumSize.setMinValue(radius * 0.1f); - _frustumSize.setMaxValue(radius * 3.f); + const float r = static_cast(_geometry->boundingRadius() * _modelScale); + _frustumSize = r; + _frustumSize.setMinValue(r * 0.1f); + _frustumSize.setMaxValue(r * 3.f); } }); @@ -568,9 +565,6 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary) else { releaseDepthMapResources(); } - - // To update list of shadowers for our parent - global::eventEngine->publishEvent("Cast Shadow Changed"); }); if (p.rotationVector.has_value()) { @@ -781,10 +775,10 @@ void RenderableModel::initializeGL() { setBoundingSphere(_geometry->boundingRadius() * _modelScale); if (_hasFrustumSize) { - const float radius = _geometry->boundingRadius() * _modelScale; - _frustumSize = radius; - _frustumSize.setMinValue(radius * 0.1f); - _frustumSize.setMaxValue(radius * 3.f); + const float r = static_cast(_geometry->boundingRadius() * _modelScale); + _frustumSize = r; + _frustumSize.setMinValue(r * 0.1f); + _frustumSize.setMaxValue(r * 3.f); } // Set Interaction sphere size to be 10% of the bounding sphere @@ -986,10 +980,7 @@ void RenderableModel::render(const RenderData& data, RendererTasks&) { ghoul::opengl::TextureUnit shadowUnit; if (_castShadow && _lightSource) { - auto [depthMap, vp] = global::renderEngine->shadowInformation( - _lightSource, - _shadowGroup - ); + auto [depthMap, vp] = global::renderEngine->shadowInformation(_shadowGroup); _program->setUniform("model", modelTransform); _program->setUniform("light_vp", vp); diff --git a/modules/base/rendering/renderablemodel.h b/modules/base/rendering/renderablemodel.h index d144588986..4fa663cac9 100644 --- a/modules/base/rendering/renderablemodel.h +++ b/modules/base/rendering/renderablemodel.h @@ -60,9 +60,6 @@ public: void render(const RenderData& data, RendererTasks& rendererTask) override; void update(const UpdateData& data) override; - void renderForDepthMap(const glm::dmat4& vp) const override; - - glm::dvec3 center() const; static documentation::Documentation Documentation(); @@ -75,6 +72,9 @@ private: BounceInfinitely }; + void renderForDepthMap(const glm::dmat4& vp) const override; + glm::dvec3 center() const override; + std::filesystem::path _file; std::unique_ptr _geometry; bool _invertModelScale = false; diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 3c714a2d96..e5afc08022 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -24,7 +24,6 @@ #include -#include #include #include #include @@ -35,8 +34,6 @@ #include #include #include -#include -#include #include #include #include @@ -59,7 +56,6 @@ #include #include #include -#include #include #include #include @@ -73,6 +69,7 @@ namespace { // Global flags to modify the RenderableGlobe constexpr bool LimitLevelByAvailableData = true; + constexpr bool PreformHorizonCulling = true; // Shadow structure struct ShadowRenderingStruct { @@ -133,18 +130,11 @@ namespace { openspace::properties::Property::Visibility::AdvancedUser }; - constexpr openspace::properties::Property::PropertyInfo PerformHorizonCullingInfo = { - "PerformHorizonCulling", - "Perform horizon culling", - "If this value is set to 'true', renderables below the horizon will be culled.", - openspace::properties::Property::Visibility::AdvancedUser - }; - constexpr openspace::properties::Property::PropertyInfo ResetTileProviderInfo = { "ResetTileProviders", "Reset tile providers", "Reset all tile provides for the globe and reload the data.", - openspace::properties::Property::Visibility::AdvancedUser + openspace::properties::Property::Visibility::Developer }; constexpr openspace::properties::Property::PropertyInfo ModelSpaceRenderingInfo = { @@ -301,9 +291,6 @@ namespace { // [[codegen::verbatim(TargetLodScaleFactorInfo.description)]] std::optional targetLodScaleFactor; - // [[codegen::verbatim(ModelSpaceRenderingInfo.description)]] - std::optional modelSpaceRenderingCutoffLevel; - // [[codegen::verbatim(OrenNayarRoughnessInfo.description)]] std::optional orenNayarRoughness; @@ -619,15 +606,14 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) BoolProperty(LevelProjectedAreaInfo, true), TriggerProperty(ResetTileProviderInfo), BoolProperty(PerformFrustumCullingInfo, true), - BoolProperty(PerformHorizonCullingInfo, true), IntProperty(ModelSpaceRenderingInfo, 14, 1, 22), IntProperty(DynamicLodIterationCountInfo, 16, 4, 128) }) , _debugPropertyOwner({ "Debug" }) , _shadowMappingProperties({ - BoolProperty(ShadowMappingInfo, true), + BoolProperty(ShadowMappingInfo, false), FloatProperty(ZFightingPercentageInfo, 0.995f, 0.000001f, 1.f), - IntProperty(NumberShadowSamplesInfo, 4, 1, 256) + IntProperty(NumberShadowSamplesInfo, 5, 1, 7) }) , _shadowMappingPropertyOwner({ "ShadowMapping", "Shadow Mapping" }) , _grid(DefaultSkirtedGridSegments, DefaultSkirtedGridSegments) @@ -748,9 +734,6 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) _debugPropertyOwner.addProperty(_debugProperties.modelSpaceRenderingCutoffLevel); _debugPropertyOwner.addProperty(_debugProperties.dynamicLodIterationCount); - _debugProperties.modelSpaceRenderingCutoffLevel = - p.modelSpaceRenderingCutoffLevel.value_or(_debugProperties.modelSpaceRenderingCutoffLevel); - addProperty(_debugProperties.modelSpaceRenderingCutoffLevel); addPropertySubOwner(_debugPropertyOwner); auto notifyShaderRecompilation = [this]() { @@ -1341,7 +1324,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, bool renderGeomOnly) std::vector depthMapData; for (const auto& [node, groups] : _shadowSpec) { for (const std::string& grp : groups) { - auto [depthmap, vp] = global::renderEngine->shadowInformation(node, grp); + auto [depthmap, vp] = global::renderEngine->shadowInformation(grp); depthMapData.emplace_back(depthmap, vp); } } @@ -1364,8 +1347,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, bool renderGeomOnly) traversalMemory.erase(traversalMemory.begin()); if (isLeaf(*n) && n->isVisible) { - const bool useGlobalRendering = n->tileIndex.level < cutoff; - if (useGlobalRendering) { + if (n->tileIndex.level < cutoff) { global[iGlobal] = n; iGlobal++; } @@ -1692,7 +1674,6 @@ void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& d } } - std::vector lightViewProjections; std::vector> depthmapTextureUnits; for (const DepthMapData& depthData : depthMapData) { @@ -2000,12 +1981,12 @@ void RenderableGlobe::recompileShaders() { // Both shader programs use depthmap shadows shaderDictionary.setValue("useDepthmapShadows", 1); - int nmaps = 0; + int nDepthMaps = 0; for (const auto& [src, grps] : _shadowSpec) { - nmaps += static_cast(grps.size()); + nDepthMaps += static_cast(grps.size()); } - shaderDictionary.setValue("nDepthMaps", nmaps); + shaderDictionary.setValue("nDepthMaps", nDepthMaps); // // Create local shader // @@ -2094,8 +2075,9 @@ bool RenderableGlobe::testIfCullable(const Chunk& chunk, { ZoneScoped; - return (_debugProperties.performHorizonCulling && isCullableByHorizon(chunk, renderData, heights)) || - (_debugProperties.performFrustumCulling && isCullableByFrustum(chunk, renderData, mvp)); + return (PreformHorizonCulling && isCullableByHorizon(chunk, renderData, heights)) || + (_debugProperties.performFrustumCulling && + isCullableByFrustum(chunk, renderData, mvp)); } int RenderableGlobe::desiredLevel(const Chunk& chunk, const RenderData& renderData, diff --git a/modules/globebrowsing/src/renderableglobe.h b/modules/globebrowsing/src/renderableglobe.h index ecdf8da6a3..82f80c5f9f 100644 --- a/modules/globebrowsing/src/renderableglobe.h +++ b/modules/globebrowsing/src/renderableglobe.h @@ -243,7 +243,6 @@ private: properties::BoolProperty levelByProjectedAreaElseDistance; properties::TriggerProperty resetTileProviders; properties::BoolProperty performFrustumCulling; - properties::BoolProperty performHorizonCulling; properties::IntProperty modelSpaceRenderingCutoffLevel; properties::IntProperty dynamicLodIterationCount; } _debugProperties; diff --git a/src/rendering/framebufferrenderer.cpp b/src/rendering/framebufferrenderer.cpp index 137db1e4ad..c1a8fc8935 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -24,7 +24,6 @@ #include -#include #include #include #include @@ -34,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -46,9 +46,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -438,21 +440,25 @@ void FramebufferRenderer::deferredcastersChanged(Deferredcaster&, _dirtyDeferredcastData = true; } -void FramebufferRenderer::registerShadowCaster(const std::string& shadowgroup, - const SceneGraphNode* lightsource, const SceneGraphNode* target) +void FramebufferRenderer::registerShadowCaster(const std::string& shadowGroup, + const SceneGraphNode* lightsource, + const SceneGraphNode* target) { constexpr int DepthMapResolutionMultiplier = 4; - if (!_shadowMaps.contains(shadowgroup)) { + if (!_shadowMaps.contains(shadowGroup)) { _shadowMaps.insert({}); } - ShadowMap& shadowMap = _shadowMaps[shadowgroup]; + ShadowMap& shadowMap = _shadowMaps[shadowGroup]; - shadowMap.shadowGroups.push_back(target->identifier()); + shadowMap.targets.push_back(target); shadowMap.lightsource = lightsource; - shadowMap.depthMapResolution = global::renderEngine->renderingResolution() * DepthMapResolutionMultiplier; + shadowMap.depthMapResolution = + global::renderEngine->renderingResolution() * DepthMapResolutionMultiplier; + shadowMap.depthMapResolution = + glm::min(shadowMap.depthMapResolution, glm::ivec2(OpenGLCap.max2DTextureSize())); GLint prevFbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); @@ -490,8 +496,39 @@ void FramebufferRenderer::registerShadowCaster(const std::string& shadowgroup, glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); } +void FramebufferRenderer::removeShadowCaster(const std::string& shadowGroup, + const SceneGraphNode* target) +{ + if (!_shadowMaps.contains(shadowGroup)) { + throw ghoul::RuntimeError(std::format( + "Could not find shadow group '{}'", shadowGroup + )); + } + ShadowMap& shadowMap = _shadowMaps[shadowGroup]; + + auto it = std::find( + shadowMap.targets.begin(), + shadowMap.targets.end(), + target + ); + if (it == shadowMap.targets.end()) { + throw ghoul::RuntimeError(std::format( + "Could not find shadowing target '{}'", target->identifier() + )); + } + + shadowMap.targets.erase(it); + + // If this was the last target we can destroy the depth map and the FBO + if (shadowMap.targets.empty()) { + glDeleteTextures(1, &shadowMap.depthMap); + glDeleteFramebuffers(1, &shadowMap.fbo); + _shadowMaps.erase(shadowGroup); + } +} + std::pair FramebufferRenderer::shadowInformation( - const SceneGraphNode* node, const std::string& shadowgroup) const + const std::string& shadowgroup) const { ghoul_assert(_shadowMaps.contains(shadowgroup), "Shadow group not registered"); return { @@ -1178,26 +1215,30 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac RendererTasks tasks; if (!_renderedDepthMapsThisFrame) { + // We are using this flag to cover the cases where we have multiple draw calls per + // frame (for example for fisheye rendering). We only need to generate the shadow + // map once in these circumstances + renderDepthMaps(); _renderedDepthMapsThisFrame = true; } { - TracyGpuZone("Background"); + TracyGpuZone("Background") const ghoul::GLDebugGroup group("Background"); data.renderBinMask = static_cast(Renderable::RenderBin::Background); scene->render(data, tasks); } { - TracyGpuZone("Opaque"); + TracyGpuZone("Opaque") const ghoul::GLDebugGroup group("Opaque"); data.renderBinMask = static_cast(Renderable::RenderBin::Opaque); scene->render(data, tasks); } { - TracyGpuZone("PreDeferredTransparent"); + TracyGpuZone("PreDeferredTransparent") const ghoul::GLDebugGroup group("PreDeferredTransparent"); data.renderBinMask = static_cast( Renderable::RenderBin::PreDeferredTransparent @@ -1207,13 +1248,13 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac // Run Volume Tasks { - TracyGpuZone("Raycaster Tasks"); + TracyGpuZone("Raycaster Tasks") const ghoul::GLDebugGroup group("Raycaster Tasks"); performRaycasterTasks(tasks.raycasterTasks, viewport); } if (!tasks.deferredcasterTasks.empty()) { - TracyGpuZone("Deferred Caster Tasks"); + TracyGpuZone("Deferred Caster Tasks") const ghoul::GLDebugGroup group("Deferred Caster Tasks"); // We use ping pong rendering in order to be able to render multiple deferred @@ -1229,14 +1270,14 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac glEnablei(GL_BLEND, 0); { - TracyGpuZone("Overlay"); + TracyGpuZone("Overlay") const ghoul::GLDebugGroup group("Overlay"); data.renderBinMask = static_cast(Renderable::RenderBin::Overlay); scene->render(data, tasks); } { - TracyGpuZone("PostDeferredTransparent"); + TracyGpuZone("PostDeferredTransparent") const ghoul::GLDebugGroup group("PostDeferredTransparent"); data.renderBinMask = static_cast( Renderable::RenderBin::PostDeferredTransparent @@ -1245,7 +1286,7 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac } { - TracyGpuZone("Sticker"); + TracyGpuZone("Sticker") const ghoul::GLDebugGroup group("Sticker"); data.renderBinMask = static_cast( Renderable::RenderBin::Sticker @@ -1297,24 +1338,24 @@ void FramebufferRenderer::renderDepthMaps() { glGetIntegerv(GL_VIEWPORT, prevVp); for (std::pair& shadowMap : _shadowMaps) { - glm::dvec3 vmin = glm::dvec3(std::numeric_limits::max()), - vmax(-std::numeric_limits::max()); + glm::dvec3 vmin = glm::dvec3(std::numeric_limits::max()); + glm::dvec3 vmax = glm::dvec3(-std::numeric_limits::max()); - std::vector torender; - for (const std::string& identifier : shadowMap.second.shadowGroups) { - SceneGraphNode* node = - global::renderEngine->scene()->sceneGraphNode(identifier); - if (node) { - RenderableModel* model = - dynamic_cast(node->renderable()); - if (model && model->isEnabled() && model->isCastingShadow() && model->isReady()) { - const double fsz = model->shadowFrustumSize(); - glm::dvec3 center = model->center(); - vmin = glm::min(vmin, center - fsz / 2); - vmax = glm::max(vmax, center + fsz / 2); + std::vector torender; + for (const SceneGraphNode* node : shadowMap.second.targets) { + ghoul_assert(node, "No SceneGraphNode"); + ghoul_assert(node->renderable(), "No Renderable"); - torender.push_back(model); - } + const Shadower* model = dynamic_cast(node->renderable()); + if (model && node->renderable()->isEnabled() && + model->isCastingShadow() && node->renderable()->isReady()) + { + const double fsz = model->shadowFrustumSize(); + glm::dvec3 center = model->center(); + vmin = glm::min(vmin, center - fsz / 2); + vmax = glm::max(vmax, center + fsz / 2); + + torender.push_back(model); } } @@ -1342,10 +1383,9 @@ void FramebufferRenderer::renderDepthMaps() { shadowMap.second.depthMapResolution.y); glClear(GL_DEPTH_BUFFER_BIT); - for (const RenderableModel* model : torender) { + for (const Shadower* model : torender) { model->renderForDepthMap(shadowMap.second.viewProjectionMatrix); } - } // Restore previous FBO and viewport diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 27bdfb509e..3a3dd3e489 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -687,37 +687,58 @@ uint64_t RenderEngine::frameNumber() const { return _frameNumber; } -void RenderEngine::registerShadowCaster(const std::string& shadowgroup, - const SceneGraphNode* lightsource, SceneGraphNode* shadower, - SceneGraphNode* shadowee) +void RenderEngine::registerShadowCaster(const std::string& shadowGroup, + const SceneGraphNode* lightsource, + SceneGraphNode* shadower, + SceneGraphNode* shadowee) { - ghoul_assert(!shadowgroup.empty(), "No shadowgroup specified"); + ghoul_assert(!shadowGroup.empty(), "No shadowGroup specified"); ghoul_assert(lightsource, "No light source specified"); ghoul_assert(shadower, "No shadower specified"); ghoul_assert(shadowee, "No shadowee specified"); - _renderer.registerShadowCaster(shadowgroup, lightsource, shadower); + _renderer.registerShadowCaster(shadowGroup, lightsource, shadower); + Shadower* sr = dynamic_cast(shadower->renderable()); if (!sr) { throw ghoul::RuntimeError("Provided shadower scene graph node is not a shadower"); } sr->setLightSource(lightsource); - sr->setShadowGroup(shadowgroup); - + sr->setShadowGroup(shadowGroup); Shadowee* se = dynamic_cast(shadowee->renderable()); if (!se) { throw ghoul::RuntimeError("Provided shadowee scene graph node is not a shadowee"); } se->addShadower(sr); - - } -std::pair RenderEngine::shadowInformation(const SceneGraphNode* node, - const std::string& shadowgroup) const +void RenderEngine::removeShadowCaster(const std::string& shadowGroup, + SceneGraphNode* shadower, + SceneGraphNode* shadowee) { - return _renderer.shadowInformation(node, shadowgroup); + ghoul_assert(!shadowGroup.empty(), "No shadowGroup specified"); + ghoul_assert(shadower, "No shadower specified"); + ghoul_assert(shadowee, "No shadowee specified"); + + _renderer.removeShadowCaster(shadowGroup, shadower); + + Shadower* sr = dynamic_cast(shadower->renderable()); + if (!sr) { + throw ghoul::RuntimeError("Provided shadower scene graph node is not a shadower"); + } + + Shadowee* se = dynamic_cast(shadowee->renderable()); + if (!se) { + throw ghoul::RuntimeError("Provided shadowee scene graph node is not a shadowee"); + } + se->removeShadower(sr); +} + +std::pair RenderEngine::shadowInformation( + const std::string& shadowgroup) const +{ + return _renderer.shadowInformation(shadowgroup); } void RenderEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix, diff --git a/src/rendering/shadowmapping.cpp b/src/rendering/shadowmapping.cpp index 08d09c820b..73edebd2f5 100644 --- a/src/rendering/shadowmapping.cpp +++ b/src/rendering/shadowmapping.cpp @@ -105,4 +105,13 @@ void Shadowee::addShadower(const Shadower* shadower) { } } +void Shadowee::removeShadower(const Shadower* shadower) { + ghoul_precondition(shadower, "Shadower must not be nullptr"); + + auto it = std::find(_shadowers.begin(), _shadowers.end(), shadower); + if (it != _shadowers.end()) { + _shadowers.erase(it); + } +} + } // namespace openspace diff --git a/src/scene/scene_lua.inl b/src/scene/scene_lua.inl index 73d8155027..101d1d7116 100644 --- a/src/scene/scene_lua.inl +++ b/src/scene/scene_lua.inl @@ -1037,6 +1037,27 @@ namespace { return res; } +/** + * Registers the pair of light source, shadower, shadowee, and shadowGroup to act together + * in order to produce a depth image that is used for shadow calculations. The + * lightSource, the shadower, and the shadowee must be existing scene graph nodes that are + * used to calculate the positions of the light and to determine which object is rendered + * to cast a shadow and which object should receive the shadow. + * Shadowcasters registered using the same shadow group will have their shadows interact + * with each other, whereas objects with different shadowGroups will not cast shadows on + * objects other than the shadowee. + * + * \param lightSource The identifier of the scene graph node that should act as the source + * of the light for shadowing purposes + * \param shadower The identifier of the scene graph node that is the object that casts a + * shadow on the shadowee and other shadowers in the tsame shadow group + * \param shadowee The identifier of the scene graph node that is the object that receives + * the shadow of the shadower + * \param shadowGroup An arbitrary name that identifies a shadow group, meaning multiple + * shadowcaster registrations that should act in unison. The name must + * not start with a `_` character. If this parameter is omitted, a + * suitable unique name will be automatically generated + */ [[codegen::luawrap]] void registerShadowcaster(std::string lightSource, std::string shadower, std::string shadowee, std::optional shadowGroup) @@ -1079,6 +1100,68 @@ namespace { global::renderEngine->registerShadowCaster(*shadowGroup, ls, shdr, shdee); } +/** + * Removes an existing pairing of a shadowcaster group, consisting of a light source, a + * shadower, a shadowee, and a shadow group. If the pairing exists, it will be removed, + * causing the shadow calculations to cease. If the pairing does not exist, an error + * message will be raised. + * + * + * \param lightSource The identifier of the scene graph node that should act as the source + * of the light for shadowing purposes + * \param shadower The identifier of the scene graph node that is the object that casts a + * shadow on the shadowee and other shadowers in the tsame shadow group + * \param shadowee The identifier of the scene graph node that is the object that receives + * the shadow of the shadower + * \param shadowGroup An arbitrary name that identifies a shadow group, meaning multiple + * shadowcaster registrations that should act in unison. The name must + * not start with a `_` character. If this parameter is omitted, a + * suitable unique name will be automatically generated. If the same + * light source, shadower, and shadowee are provided as for a previous + * register call, the generated name will be identical + */ +[[codegen::luawrap]] void removeShadowcaster(std::string lightSource, + std::string shadower, std::string shadowee, + std::optional shadowGroup) +{ + using namespace openspace; + + if (shadowGroup.has_value() && !shadowGroup->empty() && shadowGroup->at(0) == '_') { + throw ghoul::lua::LuaError(std::format( + "The 'shadowGroup' parameter must not start with '_': {}", *shadowGroup + )); + } + + // Synthesize a unique name if none is provided + if (!shadowGroup.has_value()) { + static int Count = 0; + shadowGroup = std::format("_{}|{}|{}|{}", lightSource, shadower, shadowee, Count); + Count++; + } + ghoul_assert(shadowGroup.has_value(), "No shadowgroup specified"); + + const Scene* scene = global::renderEngine->scene(); + + const SceneGraphNode* ls = scene->sceneGraphNode(lightSource); + if (!ls) { + throw ghoul::lua::LuaError(std::format( + "Could not find light source '{}'", lightSource + )); + } + + SceneGraphNode* shdr = scene->sceneGraphNode(shadower); + if (!shdr) { + throw ghoul::lua::LuaError(std::format("Could not find shadower '{}'", shadower)); + } + + SceneGraphNode* shdee = scene->sceneGraphNode(shadowee); + if (!shdee) { + throw ghoul::lua::LuaError(std::format("Could not find shadowee '{}'", shadowee)); + } + + global::renderEngine->removeShadowCaster(*shadowGroup, shdr, shdee); +} + // Returns a list of all scene graph nodes in the scene that have a renderable of the // specific type [[codegen::luawrap]] std::vector nodeByRenderableType(std::string type) {