mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-04 02:29:49 -06:00
Extracting Shadower/Shadowee classes and making registering shadow caster explicit
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
79
include/openspace/rendering/shadowmapping.h
Normal file
79
include/openspace/rendering/shadowmapping.h
Normal 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__
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
108
src/rendering/shadowmapping.cpp
Normal file
108
src/rendering/shadowmapping.cpp
Normal 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
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user