mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-15 15:19:55 +00:00
7768556ce6
As we don't reconfigure all shaders without shadows when we disable them indoors (as it'd probably add a hitch to transitioning in and out) we need to set up dummy state so the shaders don't do anything illegal. This hadn't had symptoms for most objects as when indoors, nearly everything would be drawn first in one of the water RTTs, which had dummy state to disable shadows already. This wasn't true of the water plane itself, though, yet somehow it took until just now for anyone to report that. This resolves vtastek's issue where the water would be invisible indoors
180 lines
8.2 KiB
C++
180 lines
8.2 KiB
C++
#include "shadow.hpp"
|
|
|
|
#include <osgShadow/ShadowedScene>
|
|
|
|
#include <components/misc/stringops.hpp>
|
|
#include <components/settings/settings.hpp>
|
|
|
|
namespace SceneUtil
|
|
{
|
|
using namespace osgShadow;
|
|
|
|
void ShadowManager::setupShadowSettings()
|
|
{
|
|
mEnableShadows = Settings::Manager::getBool("enable shadows", "Shadows");
|
|
|
|
if (!mEnableShadows)
|
|
{
|
|
mShadowTechnique->disableShadows();
|
|
return;
|
|
}
|
|
|
|
mShadowTechnique->enableShadows();
|
|
|
|
mShadowSettings->setLightNum(0);
|
|
mShadowSettings->setReceivesShadowTraversalMask(~0u);
|
|
|
|
int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows");
|
|
numberOfShadowMapsPerLight = std::max(1, std::min(numberOfShadowMapsPerLight, 8));
|
|
|
|
mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight);
|
|
mShadowSettings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight);
|
|
|
|
const float maximumShadowMapDistance = Settings::Manager::getFloat("maximum shadow map distance", "Shadows");
|
|
if (maximumShadowMapDistance > 0)
|
|
{
|
|
const float shadowFadeStart = std::min(std::max(0.f, Settings::Manager::getFloat("shadow fade start", "Shadows")), 1.f);
|
|
mShadowSettings->setMaximumShadowMapDistance(maximumShadowMapDistance);
|
|
mShadowTechnique->setShadowFadeStart(maximumShadowMapDistance * shadowFadeStart);
|
|
}
|
|
|
|
mShadowSettings->setMinimumShadowMapNearFarRatio(Settings::Manager::getFloat("minimum lispsm near far ratio", "Shadows"));
|
|
|
|
std::string computeSceneBounds = Settings::Manager::getString("compute scene bounds", "Shadows");
|
|
if (Misc::StringUtils::lowerCase(computeSceneBounds) == "primitives")
|
|
mShadowSettings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
|
|
else if (Misc::StringUtils::lowerCase(computeSceneBounds) == "bounds")
|
|
mShadowSettings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES);
|
|
|
|
int mapres = Settings::Manager::getInt("shadow map resolution", "Shadows");
|
|
mShadowSettings->setTextureSize(osg::Vec2s(mapres, mapres));
|
|
|
|
mShadowTechnique->setSplitPointUniformLogarithmicRatio(Settings::Manager::getFloat("split point uniform logarithmic ratio", "Shadows"));
|
|
mShadowTechnique->setSplitPointDeltaBias(Settings::Manager::getFloat("split point bias", "Shadows"));
|
|
|
|
mShadowTechnique->setPolygonOffset(Settings::Manager::getFloat("polygon offset factor", "Shadows"), Settings::Manager::getFloat("polygon offset units", "Shadows"));
|
|
|
|
if (Settings::Manager::getBool("use front face culling", "Shadows"))
|
|
mShadowTechnique->enableFrontFaceCulling();
|
|
else
|
|
mShadowTechnique->disableFrontFaceCulling();
|
|
|
|
if (Settings::Manager::getBool("allow shadow map overlap", "Shadows"))
|
|
mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::CASCADED);
|
|
else
|
|
mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::PARALLEL_SPLIT);
|
|
|
|
if (Settings::Manager::getBool("enable debug hud", "Shadows"))
|
|
mShadowTechnique->enableDebugHUD();
|
|
else
|
|
mShadowTechnique->disableDebugHUD();
|
|
}
|
|
|
|
void ShadowManager::disableShadowsForStateSet(osg::ref_ptr<osg::StateSet> stateset)
|
|
{
|
|
int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows");
|
|
numberOfShadowMapsPerLight = std::max(1, std::min(numberOfShadowMapsPerLight, 8));
|
|
|
|
int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight;
|
|
|
|
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->setShadowComparison(true);
|
|
fakeShadowMapTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS);
|
|
for (int i = baseShadowTextureUnit; i < baseShadowTextureUnit + numberOfShadowMapsPerLight; ++i)
|
|
{
|
|
stateset->setTextureAttributeAndModes(i, fakeShadowMapTexture, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED);
|
|
stateset->addUniform(new osg::Uniform(("shadowTexture" + std::to_string(i - baseShadowTextureUnit)).c_str(), i));
|
|
stateset->addUniform(new osg::Uniform(("shadowTextureUnit" + std::to_string(i - baseShadowTextureUnit)).c_str(), i));
|
|
}
|
|
}
|
|
|
|
ShadowManager::ShadowManager(osg::ref_ptr<osg::Group> sceneRoot, osg::ref_ptr<osg::Group> rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager) : mShadowedScene(new osgShadow::ShadowedScene),
|
|
mShadowTechnique(new MWShadowTechnique),
|
|
mOutdoorShadowCastingMask(outdoorShadowCastingMask),
|
|
mIndoorShadowCastingMask(indoorShadowCastingMask)
|
|
{
|
|
mShadowedScene->setShadowTechnique(mShadowTechnique);
|
|
|
|
mShadowedScene->addChild(sceneRoot);
|
|
rootNode->addChild(mShadowedScene);
|
|
mShadowedScene->setNodeMask(sceneRoot->getNodeMask());
|
|
|
|
mShadowSettings = mShadowedScene->getShadowSettings();
|
|
setupShadowSettings();
|
|
|
|
mShadowTechnique->setupCastingShader(shaderManager);
|
|
|
|
enableOutdoorMode();
|
|
}
|
|
|
|
Shader::ShaderManager::DefineMap ShadowManager::getShadowDefines()
|
|
{
|
|
if (!mEnableShadows)
|
|
return getShadowsDisabledDefines();
|
|
|
|
Shader::ShaderManager::DefineMap definesWithShadows;
|
|
|
|
definesWithShadows["shadows_enabled"] = "1";
|
|
|
|
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::Manager::getBool("allow shadow map overlap", "Shadows") ? "1" : "0";
|
|
|
|
definesWithShadows["useShadowDebugOverlay"] = Settings::Manager::getBool("enable debug overlay", "Shadows") ? "1" : "0";
|
|
|
|
// switch this to reading settings if it's ever exposed to the user
|
|
definesWithShadows["perspectiveShadowMaps"] = mShadowSettings->getShadowMapProjectionHint() == ShadowSettings::PERSPECTIVE_SHADOW_MAP ? "1" : "0";
|
|
|
|
definesWithShadows["disableNormalOffsetShadows"] = Settings::Manager::getFloat("normal offset distance", "Shadows") == 0.0 ? "1" : "0";
|
|
|
|
definesWithShadows["shadowNormalOffset"] = std::to_string(Settings::Manager::getFloat("normal offset distance", "Shadows"));
|
|
|
|
definesWithShadows["limitShadowMapDistance"] = Settings::Manager::getFloat("maximum shadow map distance", "Shadows") > 0 ? "1" : "0";
|
|
|
|
return definesWithShadows;
|
|
}
|
|
|
|
Shader::ShaderManager::DefineMap ShadowManager::getShadowsDisabledDefines()
|
|
{
|
|
Shader::ShaderManager::DefineMap definesWithoutShadows;
|
|
|
|
definesWithoutShadows["shadows_enabled"] = "0";
|
|
|
|
definesWithoutShadows["shadow_texture_unit_list"] = "";
|
|
|
|
definesWithoutShadows["shadowMapsOverlap"] = "0";
|
|
|
|
definesWithoutShadows["useShadowDebugOverlay"] = "0";
|
|
|
|
definesWithoutShadows["perspectiveShadowMaps"] = "0";
|
|
|
|
definesWithoutShadows["disableNormalOffsetShadows"] = "0";
|
|
|
|
definesWithoutShadows["shadowNormalOffset"] = "0.0";
|
|
|
|
definesWithoutShadows["limitShadowMapDistance"] = "0";
|
|
|
|
return definesWithoutShadows;
|
|
}
|
|
|
|
void ShadowManager::enableIndoorMode()
|
|
{
|
|
if (Settings::Manager::getBool("enable indoor shadows", "Shadows"))
|
|
mShadowSettings->setCastsShadowTraversalMask(mIndoorShadowCastingMask);
|
|
else
|
|
mShadowTechnique->disableShadows(true);
|
|
}
|
|
|
|
void ShadowManager::enableOutdoorMode()
|
|
{
|
|
if (mEnableShadows)
|
|
mShadowTechnique->enableShadows();
|
|
mShadowSettings->setCastsShadowTraversalMask(mOutdoorShadowCastingMask);
|
|
}
|
|
}
|