Extracting Shadower/Shadowee classes and making registering shadow caster explicit

This commit is contained in:
Alexander Bock
2025-12-18 16:06:12 +01:00
parent 5c433720ea
commit c327443886
12 changed files with 308 additions and 129 deletions

View File

@@ -45,11 +45,10 @@ local ModelMarsSmall = {
sun_transforms.LightSource
},
CastShadow = true,
LightSource = sun.LightSource.Identifier,
ShadowGroup = "mars"
LightSource = sun.LightSource.Identifier
},
GUI = {
Name = "Celestial Globe - Mars1",
Name = "Celestial Globe - Mars Small",
Path = "/Shadow Casting Models/Celestial Globe"
}
}
@@ -87,11 +86,10 @@ local ModelMarsLarge = {
sun_transforms.LightSource
},
CastShadow = true,
LightSource = sun.LightSource.Identifier,
ShadowGroup = "mars"
LightSource = sun.LightSource.Identifier
},
GUI = {
Name = "Celestial Globe - Mars2",
Name = "Celestial Globe - Mars Large",
Path = "/Shadow Casting Models/Celestial Globe"
}
}
@@ -130,11 +128,10 @@ local ModelMarsOtherGroup = {
sun_transforms.LightSource
},
CastShadow = true,
LightSource = sun.LightSource.Identifier,
ShadowGroup = "second-mars"
LightSource = sun.LightSource.Identifier
},
GUI = {
Name = "Celestial Globe - Mars3",
Name = "Celestial Globe - Mars OtherGroup",
Path = "/Shadow Casting Models/Celestial Globe"
}
}
@@ -169,8 +166,7 @@ local ModelEarth = {
sun_transforms.LightSource
},
CastShadow = true,
LightSource = sun.LightSource.Identifier,
ShadowGroup = "earth"
LightSource = sun.LightSource.Identifier
},
GUI = {
Name = "Celestial Globe - Earth",
@@ -207,8 +203,7 @@ local ModelMoon = {
sun_transforms.LightSource
},
CastShadow = true,
LightSource = sun.LightSource.Identifier,
ShadowGroup = "moon"
LightSource = sun.LightSource.Identifier
},
GUI = {
Name = "Celestial Globe - Moon",
@@ -219,10 +214,15 @@ local ModelMoon = {
asset.onInitialize(function()
openspace.addSceneGraphNode(ModelMarsSmall)
openspace.registerShadowcaster(sun.LightSource.Identifier, ModelMarsSmall.Identifier, mars.Mars.Identifier, "mars")
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)
asset.onDeinitialize(function()

View File

@@ -160,7 +160,7 @@ public:
uint64_t frameNumber() const;
void registerShadowCaster(const std::string& shadowgroup, const std::string& lightsource, const std::string& target);
void registerShadowCaster(const std::string& shadowgroup, const SceneGraphNode* lightsource, SceneGraphNode* shadower, SceneGraphNode* shadowee);
std::pair<GLuint, glm::dmat4> shadowInformation(const SceneGraphNode* node, const std::string& shadowgroup) const;
private:

View File

@@ -0,0 +1,79 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* 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 *
* 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_CORE___SHADOWMAPPING___H__
#define __OPENSPACE_CORE___SHADOWMAPPING___H__
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <vector>
namespace ghoul { class Dictionary; }
namespace openspace {
namespace documentation { struct Documentation; }
class SceneGraphNode;
// This drop-in class is representing that an object is capable of shadowing another
// object
class Shadower {
public:
Shadower(const ghoul::Dictionary& dictionary);
virtual ~Shadower() = default;
bool isCastingShadow() const;
void setLightSource(const SceneGraphNode* lightSource);
const SceneGraphNode* lightSource() const;
void setShadowGroup(std::string shadowGroup);
const std::string& shadowGroup() const;
double shadowFrustumSize() const;
static documentation::Documentation Documentation();
protected:
virtual void renderForDepthMap(const glm::dmat4& vp) const = 0;
properties::BoolProperty _castShadow;
const SceneGraphNode* _lightSource = nullptr;
std::string _shadowGroup;
properties::FloatProperty _frustumSize;
bool _hasFrustumSize = false;
};
// This drop-in class is representing that an object can be shadowed by other another
// object
class Shadowee {
public:
void addShadower(const Shadower* shadower);
protected:
std::vector<const Shadower*> _shadowers;
bool _isShadowersDirty = false;
};
} // namespace openspace
#endif // __OPENSPACE_CORE___SHADOWMAPPING___H__

View File

@@ -177,20 +177,6 @@ namespace {
openspace::properties::Property::Visibility::AdvancedUser
};
constexpr openspace::properties::Property::PropertyInfo CastShadowInfo = {
"CastShadow",
"Cast shadow",
"Enable model to cast shadow on its parent renderable.",
};
constexpr openspace::properties::Property::PropertyInfo FrustumSizeInfo = {
"FrustumSize",
"Size of the depth-pass view frustum",
"Sets the width & height (effectively left/right & top/bottom) of the depth-pass "
"view frustum, z-near & z-far are calculated.",
openspace::properties::Property::Visibility::AdvancedUser
};
constexpr openspace::properties::Property::PropertyInfo BlendingOptionInfo = {
"BlendingOption",
"Blending options",
@@ -305,9 +291,6 @@ namespace {
// [[codegen::verbatim(RenderWireframeInfo.description)]]
std::optional<bool> renderWireframe;
// [[codegen::verbatim(FrustumSizeInfo.description)]]
std::optional<float> frustumSize;
// [[codegen::verbatim(BlendingOptionInfo.description)]]
std::optional<std::string> blendingOption;
@@ -317,13 +300,6 @@ namespace {
// The path to a fragment shader program to use instead of the default shader.
std::optional<std::filesystem::path> fragmentShader;
// [[codegen::verbatim(CastShadowInfo.description)]]
std::optional<bool> castShadow;
std::optional<std::string> lightSource;
std::optional<std::string> shadowGroup;
// [[codegen::verbatim(UseOverrideColorInfo.description)]]
std::optional<bool> useOverrideColor;
@@ -336,11 +312,17 @@ namespace {
namespace openspace {
documentation::Documentation RenderableModel::Documentation() {
return codegen::doc<Parameters>("base_renderable_model");
documentation::Documentation docs = codegen::doc<Parameters>("base_renderable_model");
documentation::Documentation d = Shadower::Documentation();
docs.entries.insert(docs.entries.end(), d.entries.begin(), d.entries.end());
return docs;
}
RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary)
: Renderable(dictionary, { .automaticallyUpdateRenderBin = false })
, Shadower(dictionary)
, _enableAnimation(EnableAnimationInfo, false)
, _ambientIntensity(AmbientIntensityInfo, 0.2f, 0.f, 1.f)
, _diffuseIntensity(DiffuseIntensityInfo, 1.f, 0.f, 1.f)
@@ -375,8 +357,6 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary)
, _enableDepthTest(EnableDepthTestInfo, true)
, _blendingFuncOption(BlendingOptionInfo)
, _renderWireframe(RenderWireframeInfo, false)
, _frustumSize(FrustumSizeInfo, 1.f)
, _castShadow(CastShadowInfo, false)
, _lightSourcePropertyOwner({ "LightSources", "Light Sources" })
, _useOverrideColor(UseOverrideColorInfo, false)
, _overrideColor(OverrideColorInfo, glm::vec4(0, 0, 0, 1))
@@ -485,7 +465,6 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary)
_enableDepthTest = p.enableDepthTest.value_or(_enableDepthTest);
_enableFaceCulling = p.enableFaceCulling.value_or(_enableFaceCulling);
_renderWireframe = p.renderWireframe.value_or(_renderWireframe);
_frustumSize = p.frustumSize.value_or(_frustumSize);
_vertexShaderPath = p.vertexShader.value_or(_vertexShaderPath);
_fragmentShaderPath = p.fragmentShader.value_or(_fragmentShaderPath);
@@ -501,9 +480,6 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary)
}
}
_castShadow = p.castShadow.value_or(_castShadow);
_lightSource = p.lightSource.value_or(_lightSource);
_shadowGroup = p.shadowGroup.value_or(_shadowGroup);
_useOverrideColor = p.useOverrideColor.value_or(_useOverrideColor);
_overrideColor = p.overrideColor.value_or(_overrideColor);
@@ -528,8 +504,6 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary)
addProperty(_modelScale);
_modelScale.setExponent(20.f);
_autoSizeFrustum = !p.frustumSize.has_value();
_modelScale.onChange([this]() {
if (!_geometry) {
LWARNING(std::format(
@@ -543,7 +517,7 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary)
// Set Interaction sphere size to be 10% of the bounding sphere
setInteractionSphere(boundingSphere() * 0.1);
if (_autoSizeFrustum) {
if (_hasFrustumSize) {
const float radius = _geometry->boundingRadius() * _modelScale;
_frustumSize = radius;
_frustumSize.setMinValue(radius * 0.1f);
@@ -798,7 +772,7 @@ void RenderableModel::initializeGL() {
_geometry->calculateBoundingRadius();
setBoundingSphere(_geometry->boundingRadius() * _modelScale);
if (_autoSizeFrustum) {
if (_hasFrustumSize) {
const float radius = _geometry->boundingRadius() * _modelScale;
_frustumSize = radius;
_frustumSize.setMinValue(radius * 0.1f);
@@ -809,7 +783,6 @@ void RenderableModel::initializeGL() {
setInteractionSphere(boundingSphere() * 0.1);
if (_castShadow) {
global::renderEngine->registerShadowCaster(_shadowGroup, _lightSource, parent()->identifier());
createDepthMapResources();
}
}
@@ -1004,9 +977,11 @@ void RenderableModel::render(const RenderData& data, RendererTasks&) {
_program->setUniform("has_shadow_depth_map", _castShadow);
ghoul::opengl::TextureUnit shadowUnit;
if (_castShadow && !_lightSource.empty()) {
const SceneGraphNode* ls = global::renderEngine->scene()->sceneGraphNode(_lightSource);
auto [depthMap, vp] = global::renderEngine->shadowInformation(ls, _shadowGroup);
if (_castShadow && _lightSource) {
auto [depthMap, vp] = global::renderEngine->shadowInformation(
_lightSource,
_shadowGroup
);
_program->setUniform("model", modelTransform);
_program->setUniform("light_vp", vp);
@@ -1273,10 +1248,6 @@ void RenderableModel::update(const UpdateData& data) {
}
}
bool RenderableModel::isCastingShadow() const {
return _castShadow;
}
void RenderableModel::renderForDepthMap(const glm::dmat4& vp) const {
_depthMapProgram->activate();
@@ -1306,16 +1277,4 @@ glm::dvec3 RenderableModel::center() const {
return model * glm::dvec4(0.0, 0.0, 0.0, 1.0);
}
const std::string& RenderableModel::lightSource() const {
return _lightSource;
}
const std::string& RenderableModel::shadowGroup() const {
return _shadowGroup;
}
double RenderableModel::shadowFrustumSize() const {
return _frustumSize;
}
} // namespace openspace

View File

@@ -26,6 +26,8 @@
#define __OPENSPACE_MODULE_BASE___RENDERABLEMODEL___H__
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/shadowmapping.h>
#include <openspace/properties/matrix/dmat4property.h>
#include <openspace/properties/matrix/mat3property.h>
#include <openspace/properties/misc/optionproperty.h>
@@ -55,7 +57,7 @@ class LightSource;
namespace documentation { struct Documentation; }
class RenderableModel : public Renderable {
class RenderableModel : public Renderable, public Shadower {
public:
explicit RenderableModel(const ghoul::Dictionary& dictionary);
~RenderableModel() override = default;
@@ -71,16 +73,10 @@ public:
void render(const RenderData& data, RendererTasks& rendererTask) override;
void update(const UpdateData& data) override;
bool isCastingShadow() const;
void renderForDepthMap(const glm::dmat4& vp) const;
void renderForDepthMap(const glm::dmat4& vp) const override;
glm::dvec3 center() const;
const std::string& lightSource() const;
const std::string& shadowGroup() const;
double shadowFrustumSize() const;
static documentation::Documentation Documentation();
private:
@@ -118,16 +114,10 @@ private:
properties::BoolProperty _enableDepthTest;
properties::OptionProperty _blendingFuncOption;
properties::BoolProperty _renderWireframe;
properties::FloatProperty _frustumSize;
properties::BoolProperty _castShadow;
std::string _lightSource;
std::string _shadowGroup;
properties::BoolProperty _useOverrideColor;
properties::Vec4Property _overrideColor;
bool _autoSizeFrustum = false;
std::filesystem::path _vertexShaderPath;
std::filesystem::path _fragmentShaderPath;
ghoul::opengl::ProgramObject* _program = nullptr;

View File

@@ -1047,48 +1047,27 @@ void RenderableGlobe::update(const UpdateData& data) {
_geoJsonManager.update();
// Shadow mapping based on depth maps depend on the number of depthmaps
// in use, which is a compile-time define. Therefore we need to rebuild shaders
// when this changes.
const events::Event* e = global::eventEngine->firstEvent();
while (e) {
switch (e->type) {
case events::Event::Type::PropertyTreeUpdated:
case events::Event::Type::PropertyTreePruned:
case events::Event::Type::RenderableDisabled:
case events::Event::Type::RenderableEnabled:
case events::Event::Type::Custom:
size_t prevSize = _shadowers.size();
_shadowers = getShadowers(this->parent());
if (prevSize != _shadowers.size()) {
_shadowersUpdated = true;
_shadowersOk = false;
if (_isShadowersDirty) {
_shadowersUpdated = true;
_shadowersOk = false;
_shadowSpec.clear();
for (const RenderableModel* model : _shadowers) {
const std::string& modelLightSource = model->lightSource();
if (!_shadowSpec.contains(modelLightSource)) {
_shadowSpec.emplace(modelLightSource, std::vector<std::string>{});
}
_shadowSpec.at(modelLightSource).push_back(model->shadowGroup());
}
}
break;
_shadowSpec.clear();
for (const Shadower* model : _shadowers) {
const SceneGraphNode* modelLightSource = model->lightSource();
if (!_shadowSpec.contains(modelLightSource)) {
_shadowSpec.emplace(modelLightSource, std::vector<std::string>{});
}
_shadowSpec.at(modelLightSource).push_back(model->shadowGroup());
}
e = e->next;
_isShadowersDirty = false;
}
// Note that recompilation only occurs when all models are loaded and ready for rendering
if (_shadowersUpdated) {
bool allOK = true;
for (const RenderableModel* model : _shadowers) {
allOK &= model->isReady();
}
if (allOK) {
_shadowersUpdated = false;
_shadowersOk = true;
_shadersNeedRecompilation = true;
}
_shadowersUpdated = false;
_shadowersOk = true;
_shadersNeedRecompilation = true;
}
}
@@ -1360,9 +1339,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, bool renderGeomOnly)
}
std::vector<DepthMapData> depthMapData;
for (const auto& [key, groups] : _shadowSpec) {
const auto node = global::renderEngine->scene()->sceneGraphNode(key);
for (const auto& [node, groups] : _shadowSpec) {
for (const std::string& grp : groups) {
auto [depthmap, vp] = global::renderEngine->shadowInformation(node, grp);
depthMapData.emplace_back(depthmap, vp);

View File

@@ -26,6 +26,7 @@
#define __OPENSPACE_MODULE_GLOBEBROWSING___RENDERABLEGLOBE___H__
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/shadowmapping.h>
#include <modules/globebrowsing/src/geodeticpatch.h>
#include <modules/globebrowsing/src/geojson/geojsonmanager.h>
@@ -96,7 +97,7 @@ enum class ShadowCompType {
* A RenderableGlobe is a globe modeled as an ellipsoid using a chunked LOD algorithm for
* rendering.
*/
class RenderableGlobe : public Renderable {
class RenderableGlobe : public Renderable, public Shadowee {
public:
explicit RenderableGlobe(const ghoul::Dictionary& dictionary);
~RenderableGlobe() override = default;
@@ -312,11 +313,10 @@ private:
size_t _iterationsOfUnavailableData = 0;
Layer* _lastChangedLayer = nullptr;
std::vector<const RenderableModel*> _shadowers;
bool _shadowersUpdated = false;
bool _shadowersOk = false;
std::map<std::string, std::vector<std::string>> _shadowSpec;
std::map<const SceneGraphNode*, std::vector<std::string>> _shadowSpec;
// Components
std::unique_ptr<RingsComponent> _ringsComponent;

View File

@@ -145,6 +145,7 @@ set(OPENSPACE_SOURCE
rendering/screenspacerenderableframebuffer.cpp
rendering/screenspacerenderable.cpp
rendering/screenspacerenderabletext.cpp
rendering/shadowmapping.cpp
rendering/texturecomponent.cpp
rendering/transferfunction.cpp
rendering/volumeraycaster.cpp
@@ -344,6 +345,7 @@ set(OPENSPACE_HEADER
${PROJECT_SOURCE_DIR}/include/openspace/rendering/screenspacerenderableframebuffer.h
${PROJECT_SOURCE_DIR}/include/openspace/rendering/screenspacerenderable.h
${PROJECT_SOURCE_DIR}/include/openspace/rendering/screenspacerenderabletext.h
${PROJECT_SOURCE_DIR}/include/openspace/rendering/shadowmapping.h
${PROJECT_SOURCE_DIR}/include/openspace/rendering/texturecomponent.h
${PROJECT_SOURCE_DIR}/include/openspace/rendering/transferfunction.h
${PROJECT_SOURCE_DIR}/include/openspace/rendering/volumeraycaster.h

View File

@@ -41,7 +41,9 @@
#include <openspace/rendering/framebufferrenderer.h>
#include <openspace/rendering/luaconsole.h>
#include <openspace/rendering/raycastermanager.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/screenspacerenderable.h>
#include <openspace/rendering/shadowmapping.h>
#include <openspace/scene/scene.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/memorymanager.h>
@@ -680,11 +682,30 @@ uint64_t RenderEngine::frameNumber() const {
}
void RenderEngine::registerShadowCaster(const std::string& shadowgroup,
const std::string& lightsource, const std::string& target)
const SceneGraphNode* lightsource, SceneGraphNode* shadower,
SceneGraphNode* shadowee)
{
const SceneGraphNode* ls = _scene->sceneGraphNode(lightsource);
const SceneGraphNode* tgt = _scene->sceneGraphNode(target);
_renderer.registerShadowCaster(shadowgroup, ls, tgt);
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);
Shadower* sr = dynamic_cast<Shadower*>(shadower->renderable());
if (!sr) {
throw ghoul::RuntimeError("Provided shadower scene graph node is not a shadower");
}
sr->setLightSource(lightsource);
sr->setShadowGroup(shadowgroup);
Shadowee* se = dynamic_cast<Shadowee*>(shadowee->renderable());
if (!se) {
throw ghoul::RuntimeError("Provided shadowee scene graph node is not a shadowee");
}
se->addShadower(sr);
}
std::pair<GLuint, glm::dmat4> RenderEngine::shadowInformation(const SceneGraphNode* node,

View File

@@ -0,0 +1,108 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* 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 *
* 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 <openspace/rendering/shadowmapping.h>
#include <openspace/documentation/documentation.h>
#include <ghoul/misc/invariants.h>
#include <optional>
namespace {
constexpr openspace::properties::Property::PropertyInfo CastShadowInfo = {
"CastShadow",
"Cast shadow",
"Enable model to cast shadow on its parent renderable.",
};
constexpr openspace::properties::Property::PropertyInfo FrustumSizeInfo = {
"FrustumSize",
"Size of the depth-pass view frustum",
"Sets the width & height (effectively left/right & top/bottom) of the depth-pass "
"view frustum, z-near & z-far are calculated.",
openspace::properties::Property::Visibility::AdvancedUser
};
struct [[codegen::Dictionary(Shadower)]] Parameters {
// [[codegen::verbatim(FrustumSizeInfo.description)]]
std::optional<float> frustumSize;
// [[codegen::verbatim(CastShadowInfo.description)]]
std::optional<bool> castShadow;
};
#include "shadowmapping_codegen.cpp"
} // namespace
namespace openspace {
documentation::Documentation Shadower::Documentation() {
return codegen::doc<Parameters>("core_shadower");
}
Shadower::Shadower(const ghoul::Dictionary& dictionary)
: _castShadow(CastShadowInfo, false)
, _frustumSize(FrustumSizeInfo, 1.f)
{
const Parameters p = codegen::bake<Parameters>(dictionary);
_frustumSize = p.frustumSize.value_or(_frustumSize);
_hasFrustumSize = p.frustumSize.has_value();
_frustumSize.onChange([&]() { _hasFrustumSize = true; });
_castShadow = p.castShadow.value_or(_castShadow);
}
bool Shadower::isCastingShadow() const {
return _castShadow;
}
void Shadower::setLightSource(const SceneGraphNode* lightSource) {
ghoul_assert(lightSource, "No light source provided");
_lightSource = std::move(lightSource);
}
const SceneGraphNode* Shadower::lightSource() const {
return _lightSource;
}
void Shadower::setShadowGroup(std::string shadowGroup) {
_shadowGroup = std::move(shadowGroup);
}
const std::string& Shadower::shadowGroup() const {
return _shadowGroup;
}
double Shadower::shadowFrustumSize() const {
return _frustumSize;
}
void Shadowee::addShadower(const Shadower* shadower) {
ghoul_precondition(shadower, "Shadower must not be nullptr");
if (std::find(_shadowers.begin(), _shadowers.end(), shadower) == _shadowers.end()) {
_shadowers.push_back(shadower);
_isShadowersDirty = true;
}
}
} // namespace openspace

View File

@@ -985,6 +985,7 @@ at the end of the interpolation. If 0 was provided, the script runs immediately.
codegen::lua::HasSceneGraphNode,
codegen::lua::SceneGraphNodes,
codegen::lua::NodeByRenderableType,
codegen::lua::RegisterShadowcaster,
codegen::lua::ScreenSpaceRenderables,
codegen::lua::WorldPosition,
codegen::lua::WorldRotation,

View File

@@ -1025,6 +1025,48 @@ namespace {
return res;
}
[[codegen::luawrap]] void registerShadowcaster(std::string lightSource,
std::string shadower, std::string shadowee,
std::optional<std::string> 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->registerShadowCaster(*shadowGroup, ls, 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<std::string> nodeByRenderableType(std::string type) {