1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-21 08:53:52 +00:00
openmw/components/sceneutil/shadow.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

219 lines
8.6 KiB
C++
Raw Normal View History

#include "shadow.hpp"
#include <osgShadow/ShadowSettings>
#include <osgShadow/ShadowedScene>
#include <components/misc/strings/algorithm.hpp>
#include <components/settings/categories/shadows.hpp>
#include <components/stereo/stereomanager.hpp>
2017-12-27 02:32:17 +00:00
#include "mwshadowtechnique.hpp"
2017-11-08 01:44:49 +00:00
namespace SceneUtil
{
using namespace osgShadow;
ShadowManager* ShadowManager::sInstance = nullptr;
const ShadowManager& ShadowManager::instance()
{
if (sInstance)
return *sInstance;
else
throw std::logic_error("No ShadowManager exists yet");
}
void ShadowManager::setupShadowSettings(
const Settings::ShadowsCategory& settings, Shader::ShaderManager& shaderManager)
2017-12-27 02:32:17 +00:00
{
mEnableShadows = settings.mEnableShadows;
2018-02-26 23:52:46 +00:00
if (!mEnableShadows)
2018-02-26 22:27:09 +00:00
{
mShadowTechnique->disableShadows();
2017-12-27 02:32:17 +00:00
return;
2018-02-26 22:27:09 +00:00
}
2022-09-22 18:26:05 +00:00
2018-02-26 23:52:46 +00:00
mShadowTechnique->enableShadows();
2017-12-27 02:32:17 +00:00
2018-02-26 23:52:46 +00:00
mShadowSettings->setLightNum(0);
mShadowSettings->setReceivesShadowTraversalMask(~0u);
2017-12-27 02:32:17 +00:00
const int numberOfShadowMapsPerLight = settings.mNumberOfShadowMaps;
2019-11-17 13:24:20 +00:00
2018-02-26 23:52:46 +00:00
mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight);
mShadowSettings->setBaseShadowTextureUnit(shaderManager.reserveGlobalTextureUnits(
Shader::ShaderManager::Slot::ShadowMaps, numberOfShadowMapsPerLight));
2017-12-27 02:32:17 +00:00
const float maximumShadowMapDistance = settings.mMaximumShadowMapDistance;
if (maximumShadowMapDistance > 0)
{
const float shadowFadeStart = settings.mShadowFadeStart;
mShadowSettings->setMaximumShadowMapDistance(maximumShadowMapDistance);
mShadowTechnique->setShadowFadeStart(maximumShadowMapDistance * shadowFadeStart);
}
mShadowSettings->setMinimumShadowMapNearFarRatio(settings.mMinimumLispsmNearFarRatio);
const std::string& computeSceneBounds = settings.mComputeSceneBounds;
if (Misc::StringUtils::ciEqual(computeSceneBounds, "primitives"))
2018-02-26 23:52:46 +00:00
mShadowSettings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
else if (Misc::StringUtils::ciEqual(computeSceneBounds, "bounds"))
mShadowSettings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES);
2017-12-27 02:32:17 +00:00
const int mapres = settings.mShadowMapResolution;
2018-02-26 23:52:46 +00:00
mShadowSettings->setTextureSize(osg::Vec2s(mapres, mapres));
2018-02-26 22:27:09 +00:00
mShadowTechnique->setSplitPointUniformLogarithmicRatio(settings.mSplitPointUniformLogarithmicRatio);
mShadowTechnique->setSplitPointDeltaBias(settings.mSplitPointBias);
mShadowTechnique->setPolygonOffset(settings.mPolygonOffsetFactor, settings.mPolygonOffsetUnits);
if (settings.mUseFrontFaceCulling)
mShadowTechnique->enableFrontFaceCulling();
else
mShadowTechnique->disableFrontFaceCulling();
if (settings.mAllowShadowMapOverlap)
mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::CASCADED);
else
mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT);
if (settings.mEnableDebugHud)
2018-02-26 22:27:09 +00:00
mShadowTechnique->enableDebugHUD();
else
mShadowTechnique->disableDebugHUD();
2017-12-27 02:32:17 +00:00
}
void ShadowManager::disableShadowsForStateSet(osg::StateSet& stateset) const
{
if (!mEnableShadows)
return;
2017-12-27 02:32:17 +00:00
osg::ref_ptr<osg::Image> fakeShadowMapImage = new osg::Image();
fakeShadowMapImage->allocateImage(1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT);
*(float*)fakeShadowMapImage->data() = std::numeric_limits<float>::infinity();
osg::ref_ptr<osg::Texture> fakeShadowMapTexture = new osg::Texture2D(fakeShadowMapImage);
fakeShadowMapTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
fakeShadowMapTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
2017-12-27 02:32:17 +00:00
fakeShadowMapTexture->setShadowComparison(true);
fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS);
for (unsigned int i = mShadowSettings->getBaseShadowTextureUnit();
i < mShadowSettings->getBaseShadowTextureUnit() + mShadowSettings->getNumShadowMapsPerLight(); ++i)
{
stateset.setTextureAttribute(i, fakeShadowMapTexture,
2017-12-27 02:32:17 +00:00
osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED);
stateset.addUniform(new osg::Uniform(
2024-02-20 23:51:42 +00:00
("shadowTexture" + std::to_string(i - mShadowSettings->getBaseShadowTextureUnit())).c_str(),
static_cast<int>(i)));
}
2017-12-27 02:32:17 +00:00
}
ShadowManager::ShadowManager(osg::ref_ptr<osg::Group> sceneRoot, osg::ref_ptr<osg::Group> rootNode,
unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, unsigned int worldMask,
const Settings::ShadowsCategory& settings, Shader::ShaderManager& shaderManager)
: mShadowedScene(new osgShadow::ShadowedScene)
, mShadowTechnique(new MWShadowTechnique)
, mOutdoorShadowCastingMask(outdoorShadowCastingMask)
, mIndoorShadowCastingMask(indoorShadowCastingMask)
{
if (sInstance)
throw std::logic_error("A ShadowManager already exists");
2018-02-26 22:27:09 +00:00
mShadowedScene->setShadowTechnique(mShadowTechnique);
if (Stereo::getStereo())
Stereo::Manager::instance().setShadowTechnique(mShadowTechnique);
2018-02-26 23:52:46 +00:00
2018-02-26 22:27:09 +00:00
mShadowedScene->addChild(sceneRoot);
rootNode->addChild(mShadowedScene);
mShadowedScene->setNodeMask(sceneRoot->getNodeMask());
2018-02-26 23:52:46 +00:00
mShadowSettings = mShadowedScene->getShadowSettings();
setupShadowSettings(settings, shaderManager);
mShadowTechnique->setupCastingShader(shaderManager);
mShadowTechnique->setWorldMask(worldMask);
enableOutdoorMode();
sInstance = this;
}
ShadowManager::~ShadowManager()
{
if (Stereo::getStereo())
Stereo::Manager::instance().setShadowTechnique(nullptr);
}
Shader::ShaderManager::DefineMap ShadowManager::getShadowDefines(const Settings::ShadowsCategory& settings) const
{
2018-02-26 23:52:46 +00:00
if (!mEnableShadows)
return getShadowsDisabledDefines();
Shader::ShaderManager::DefineMap definesWithShadows;
2019-01-31 20:12:17 +00:00
definesWithShadows["shadows_enabled"] = "1";
2018-02-27 14:15:06 +00:00
for (unsigned int i = 0; i < mShadowSettings->getNumShadowMapsPerLight(); ++i)
definesWithShadows["shadow_texture_unit_list"] += std::to_string(i) + ",";
// remove extra comma
definesWithShadows["shadow_texture_unit_list"] = definesWithShadows["shadow_texture_unit_list"].substr(
0, definesWithShadows["shadow_texture_unit_list"].length() - 1);
definesWithShadows["shadowMapsOverlap"] = settings.mAllowShadowMapOverlap ? "1" : "0";
definesWithShadows["useShadowDebugOverlay"] = settings.mEnableDebugOverlay ? "1" : "0";
2018-06-28 16:24:36 +00:00
// switch this to reading settings if it's ever exposed to the user
2019-01-31 20:12:17 +00:00
definesWithShadows["perspectiveShadowMaps"]
= mShadowSettings->getShadowMapProjectionHint() == ShadowSettings::PERSPECTIVE_SHADOW_MAP ? "1" : "0";
definesWithShadows["disableNormalOffsetShadows"] = settings.mNormalOffsetDistance == 0.0 ? "1" : "0";
definesWithShadows["shadowNormalOffset"] = std::to_string(settings.mNormalOffsetDistance);
definesWithShadows["limitShadowMapDistance"] = settings.mMaximumShadowMapDistance > 0 ? "1" : "0";
return definesWithShadows;
}
Shader::ShaderManager::DefineMap ShadowManager::getShadowsDisabledDefines()
{
2019-01-31 14:58:57 +00:00
Shader::ShaderManager::DefineMap definesWithoutShadows;
2019-01-31 20:12:17 +00:00
definesWithoutShadows["shadows_enabled"] = "0";
2019-01-31 14:58:57 +00:00
definesWithoutShadows["shadow_texture_unit_list"] = "";
2019-01-31 14:58:57 +00:00
definesWithoutShadows["shadowMapsOverlap"] = "0";
2019-01-31 14:58:57 +00:00
definesWithoutShadows["useShadowDebugOverlay"] = "0";
2018-06-28 16:24:36 +00:00
2019-01-31 14:58:57 +00:00
definesWithoutShadows["perspectiveShadowMaps"] = "0";
2019-01-31 14:58:57 +00:00
definesWithoutShadows["disableNormalOffsetShadows"] = "0";
2019-01-31 14:58:57 +00:00
definesWithoutShadows["shadowNormalOffset"] = "0.0";
definesWithoutShadows["limitShadowMapDistance"] = "0";
2019-01-31 14:58:57 +00:00
return definesWithoutShadows;
}
2019-01-31 20:12:17 +00:00
void ShadowManager::enableIndoorMode(const Settings::ShadowsCategory& settings)
{
if (settings.mEnableIndoorShadows)
2018-08-08 22:56:11 +00:00
mShadowSettings->setCastsShadowTraversalMask(mIndoorShadowCastingMask);
else
mShadowTechnique->disableShadows(true);
}
2019-01-31 20:12:17 +00:00
void ShadowManager::enableOutdoorMode()
{
2018-08-08 22:56:11 +00:00
if (mEnableShadows)
mShadowTechnique->enableShadows();
mShadowSettings->setCastsShadowTraversalMask(mOutdoorShadowCastingMask);
}
}