Some more cleanup of the PR

This commit is contained in:
Alexander Bock
2025-12-18 21:12:01 +01:00
parent f307dfb64a
commit 36fc575ffd
16 changed files with 252 additions and 118 deletions

View File

@@ -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)

View File

@@ -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;

View File

@@ -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<GLuint, glm::dmat4> 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<GLuint, glm::dmat4> shadowInformation(const std::string& shadowgroup) const;
private:
using RaycasterProgObjMap = std::map<
@@ -251,7 +253,7 @@ private:
struct ShadowMap {
const SceneGraphNode* lightsource = nullptr;
std::vector<std::string> shadowGroups;
std::vector<const SceneGraphNode*> targets;
GLuint depthMap = 0;
glm::ivec2 depthMapResolution = glm::ivec2(0);
GLuint fbo = 0;

View File

@@ -34,6 +34,7 @@
#include <openspace/properties/vector/vec3property.h>
#include <openspace/properties/vector/vec4property.h>
#include <openspace/rendering/framebufferrenderer.h>
#include <ghoul/opengl/ghoul_gl.h>
#include <cstdint>
#include <chrono>
#include <filesystem>
@@ -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<GLuint, glm::dmat4> 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<GLuint, glm::dmat4> shadowInformation(const std::string& shadowgroup) const;
private:
void renderScreenLog();

View File

@@ -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<const Shadower*> _shadowers;

View File

@@ -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);

View File

@@ -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;

View File

@@ -25,12 +25,9 @@
#include <modules/base/rendering/renderablemodel.h>
#include <modules/base/basemodule.h>
#include <modules/base/lightsource/scenegraphlightsource.h>
#include <openspace/documentation/documentation.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/events/event.h>
#include <openspace/events/eventengine.h>
#include <openspace/rendering/framebufferrenderer.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/util/distanceconversion.h>
@@ -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<Parameters>(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<float>(_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<events::CustomEvent>("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<float>(_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);

View File

@@ -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<ghoul::modelgeometry::ModelGeometry> _geometry;
bool _invertModelScale = false;

View File

@@ -24,7 +24,6 @@
#include <modules/globebrowsing/src/renderableglobe.h>
#include <modules/base/rendering/renderablemodel.h>
#include <modules/debugging/rendering/debugrenderer.h>
#include <modules/globebrowsing/src/basictypes.h>
#include <modules/globebrowsing/src/gpulayergroup.h>
@@ -35,8 +34,6 @@
#include <modules/globebrowsing/src/tileprovider/tileprovider.h>
#include <openspace/documentation/documentation.h>
#include <openspace/engine/globals.h>
#include <openspace/events/event.h>
#include <openspace/events/eventengine.h>
#include <openspace/interaction/sessionrecordinghandler.h>
#include <openspace/query/query.h>
#include <openspace/rendering/renderengine.h>
@@ -59,7 +56,6 @@
#include <ghoul/opengl/openglstatecache.h>
#include <ghoul/opengl/programobject.h>
#include <ghoul/systemcapabilities/openglcapabilitiescomponent.h>
#include <ghoul/io/model/modelgeometry.h>
#include <algorithm>
#include <cmath>
#include <limits>
@@ -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<float> targetLodScaleFactor;
// [[codegen::verbatim(ModelSpaceRenderingInfo.description)]]
std::optional<int> modelSpaceRenderingCutoffLevel;
// [[codegen::verbatim(OrenNayarRoughnessInfo.description)]]
std::optional<float> 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> 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<glm::dmat4> lightViewProjections;
std::vector<std::pair<ghoul::opengl::TextureUnit, GLuint>> 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<int>(grps.size());
nDepthMaps += static_cast<int>(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,

View File

@@ -243,7 +243,6 @@ private:
properties::BoolProperty levelByProjectedAreaElseDistance;
properties::TriggerProperty resetTileProviders;
properties::BoolProperty performFrustumCulling;
properties::BoolProperty performHorizonCulling;
properties::IntProperty modelSpaceRenderingCutoffLevel;
properties::IntProperty dynamicLodIterationCount;
} _debugProperties;

View File

@@ -24,7 +24,6 @@
#include <openspace/rendering/framebufferrenderer.h>
#include <modules/base/rendering/renderablemodel.h>
#include <openspace/camera/camera.h>
#include <openspace/engine/globals.h>
#include <openspace/rendering/deferredcaster.h>
@@ -34,6 +33,7 @@
#include <openspace/rendering/raycastermanager.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/rendering/shadowmapping.h>
#include <openspace/rendering/volumeraycaster.h>
#include <openspace/scene/scene.h>
#include <openspace/util/timemanager.h>
@@ -46,9 +46,11 @@
#include <ghoul/opengl/programobject.h>
#include <ghoul/opengl/openglstatecache.h>
#include <ghoul/opengl/textureunit.h>
#include <ghoul/systemcapabilities/openglcapabilitiescomponent.h>
#include <glm/gtc/type_ptr.hpp>
#include <algorithm>
#include <filesystem>
#include <limits>
#include <memory>
#include <string>
#include <string_view>
@@ -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<GLuint, glm::dmat4> 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<int>(Renderable::RenderBin::Background);
scene->render(data, tasks);
}
{
TracyGpuZone("Opaque");
TracyGpuZone("Opaque")
const ghoul::GLDebugGroup group("Opaque");
data.renderBinMask = static_cast<int>(Renderable::RenderBin::Opaque);
scene->render(data, tasks);
}
{
TracyGpuZone("PreDeferredTransparent");
TracyGpuZone("PreDeferredTransparent")
const ghoul::GLDebugGroup group("PreDeferredTransparent");
data.renderBinMask = static_cast<int>(
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<int>(Renderable::RenderBin::Overlay);
scene->render(data, tasks);
}
{
TracyGpuZone("PostDeferredTransparent");
TracyGpuZone("PostDeferredTransparent")
const ghoul::GLDebugGroup group("PostDeferredTransparent");
data.renderBinMask = static_cast<int>(
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<int>(
Renderable::RenderBin::Sticker
@@ -1297,24 +1338,24 @@ void FramebufferRenderer::renderDepthMaps() {
glGetIntegerv(GL_VIEWPORT, prevVp);
for (std::pair<const std::string, ShadowMap>& shadowMap : _shadowMaps) {
glm::dvec3 vmin = glm::dvec3(std::numeric_limits<double>::max()),
vmax(-std::numeric_limits<double>::max());
glm::dvec3 vmin = glm::dvec3(std::numeric_limits<double>::max());
glm::dvec3 vmax = glm::dvec3(-std::numeric_limits<double>::max());
std::vector<RenderableModel*> torender;
for (const std::string& identifier : shadowMap.second.shadowGroups) {
SceneGraphNode* node =
global::renderEngine->scene()->sceneGraphNode(identifier);
if (node) {
RenderableModel* model =
dynamic_cast<RenderableModel*>(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<const Shadower*> 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<const Shadower*>(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

View File

@@ -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*>(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*>(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,
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*>(shadower->renderable());
if (!sr) {
throw ghoul::RuntimeError("Provided shadower scene graph node is not a shadower");
}
Shadowee* se = dynamic_cast<Shadowee*>(shadowee->renderable());
if (!se) {
throw ghoul::RuntimeError("Provided shadowee scene graph node is not a shadowee");
}
se->removeShadower(sr);
}
std::pair<GLuint, glm::dmat4> RenderEngine::shadowInformation(
const std::string& shadowgroup) const
{
return _renderer.shadowInformation(shadowgroup);
}
void RenderEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix,

View File

@@ -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

View File

@@ -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<std::string> 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<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->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<std::string> nodeByRenderableType(std::string type) {