mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-17 19:10:24 +00:00
dd5901d351
Multiview shaders. Refactor Frustum management Rewrite shared shadow map cull mask should respect stereo Stereo savegame screencap LocalMap refactoring use the vertex buffer hint instead of the display list patch to enable/disable display lists Character preview fixes
193 lines
8.5 KiB
C++
193 lines
8.5 KiB
C++
#include "shadow.hpp"
|
|
|
|
#include <osgShadow/ShadowedScene>
|
|
#include <osgShadow/ShadowSettings>
|
|
|
|
#include <components/misc/stringops.hpp>
|
|
#include <components/settings/settings.hpp>
|
|
#include <components/stereo/stereomanager.hpp>
|
|
|
|
#include "mwshadowtechnique.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);
|
|
|
|
const int numberOfShadowMapsPerLight = std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 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::clamp(Settings::Manager::getFloat("shadow fade start", "Shadows"), 0.f, 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)
|
|
{
|
|
if (!Settings::Manager::getBool("enable shadows", "Shadows"))
|
|
return;
|
|
|
|
const int numberOfShadowMapsPerLight = std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 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, unsigned int worldMask, Shader::ShaderManager &shaderManager) : mShadowedScene(new osgShadow::ShadowedScene),
|
|
mShadowTechnique(new MWShadowTechnique),
|
|
mOutdoorShadowCastingMask(outdoorShadowCastingMask),
|
|
mIndoorShadowCastingMask(indoorShadowCastingMask)
|
|
{
|
|
mShadowedScene->setShadowTechnique(mShadowTechnique);
|
|
Stereo::Manager::instance().setShadowTechnique(mShadowTechnique);
|
|
|
|
mShadowedScene->addChild(sceneRoot);
|
|
rootNode->addChild(mShadowedScene);
|
|
mShadowedScene->setNodeMask(sceneRoot->getNodeMask());
|
|
|
|
mShadowSettings = mShadowedScene->getShadowSettings();
|
|
setupShadowSettings();
|
|
|
|
mShadowTechnique->setupCastingShader(shaderManager);
|
|
mShadowTechnique->setWorldMask(worldMask);
|
|
|
|
enableOutdoorMode();
|
|
}
|
|
|
|
ShadowManager::~ShadowManager()
|
|
{
|
|
Stereo::Manager::instance().setShadowTechnique(nullptr);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|