Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
9.3 kB · 228 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229#include "shadow.hpp"
#include <limits>
#include <osgShadow/ShadowSettings>#include <osgShadow/ShadowedScene>
#include <components/misc/strings/algorithm.hpp>#include <components/settings/categories/shadows.hpp>#include <components/stereo/stereomanager.hpp>
#include "mwshadowtechnique.hpp"
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) { mEnableShadows = settings.mEnableShadows;
if (mEnableShadows) mShadowTechnique->enableShadows(); else mShadowTechnique->disableShadows();
mShadowSettings->setReceivesShadowTraversalMask(~0u);
const int numberOfShadowMapsPerLight = settings.mNumberOfShadowMaps;
mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); mShadowSettings->setBaseShadowTextureUnit(shaderManager.reserveGlobalTextureUnits( Shader::ShaderManager::Slot::ShadowMaps, numberOfShadowMapsPerLight));
const float maximumShadowMapDistance = settings.mMaximumShadowMapDistance; if (maximumShadowMapDistance > 0) { const float shadowFadeStart = settings.mShadowFadeStart; mShadowTechnique->setMaximumShadowMapDistance(maximumShadowMapDistance); mShadowTechnique->setShadowFadeStart(maximumShadowMapDistance * shadowFadeStart); } else { mShadowTechnique->setMaximumShadowMapDistance(std::numeric_limits<float>::max()); mShadowTechnique->setShadowFadeStart(std::numeric_limits<float>::max()); }
mShadowSettings->setMinimumShadowMapNearFarRatio(settings.mMinimumLispsmNearFarRatio);
const std::string& computeSceneBounds = settings.mComputeSceneBounds; if (Misc::StringUtils::ciEqual(computeSceneBounds, "primitives")) 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);
const short mapres = static_cast<short>(settings.mShadowMapResolution); mShadowSettings->setTextureSize(osg::Vec2s(mapres, mapres));
mShadowTechnique->setSplitPointUniformLogarithmicRatio(settings.mSplitPointUniformLogarithmicRatio); mShadowTechnique->setSplitPointDeltaBias(settings.mSplitPointBias);
mShadowTechnique->setPolygonOffset(settings.mPolygonOffsetFactor, settings.mPolygonOffsetUnits);
if (settings.mUseFrontFaceCulling) mShadowTechnique->enableFrontFaceCulling(); else mShadowTechnique->disableFrontFaceCulling();
mShadowSettings->setMultipleShadowMapHint(osgShadow::ShadowSettings::CASCADED);
if (mEnableShadows && settings.mEnableDebugHud) mShadowTechnique->enableDebugHUD(); else mShadowTechnique->disableDebugHUD(); }
void ShadowManager::setOutdoorShadowCastingMask(unsigned int mask) { mOutdoorShadowCastingMask = mask; }
void ShadowManager::setIndoorShadowCastingMask(unsigned int mask) { mIndoorShadowCastingMask = mask; }
void ShadowManager::setupShaders(Shader::ShaderManager& shaderManager) const { mShadowTechnique->setupCastingShader(shaderManager); }
void ShadowManager::disableShadowsForStateSet(osg::StateSet& stateset) const { 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); 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, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); stateset.addUniform(new osg::Uniform( ("shadowTexture" + std::to_string(i - mShadowSettings->getBaseShadowTextureUnit())).c_str(), static_cast<int>(i))); } stateset.addUniform(new osg::Uniform("maximumShadowMapDistance", 0.00001f)); stateset.addUniform(new osg::Uniform("shadowFadeStart", 0.0f)); stateset.addUniform(new osg::Uniform("cascadeSplits", osg::Vec4(0.0f, 0.0f, 0.0f, 0.0f))); }
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");
mShadowedScene->setShadowTechnique(mShadowTechnique);
if (Stereo::getStereo()) Stereo::Manager::instance().setShadowTechnique(mShadowTechnique);
mShadowedScene->addChild(sceneRoot); rootNode->addChild(mShadowedScene); mShadowedScene->setNodeMask(sceneRoot->getNodeMask());
mShadowSettings = mShadowedScene->getShadowSettings(); setupShadowSettings(settings, 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 { if (!settings.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["useShadowDebugOverlay"] = settings.mEnableDebugOverlay ? "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.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() { Shader::ShaderManager::DefineMap definesWithoutShadows;
definesWithoutShadows["shadows_enabled"] = "0";
definesWithoutShadows["shadow_texture_unit_list"] = "";
definesWithoutShadows["useShadowDebugOverlay"] = "0";
definesWithoutShadows["perspectiveShadowMaps"] = "0";
definesWithoutShadows["disableNormalOffsetShadows"] = "0";
definesWithoutShadows["shadowNormalOffset"] = "0.0";
definesWithoutShadows["limitShadowMapDistance"] = "0";
return definesWithoutShadows; }
void ShadowManager::enableIndoorMode(const Settings::ShadowsCategory& settings) { if (settings.mEnableIndoorShadows) mShadowSettings->setCastsShadowTraversalMask(mIndoorShadowCastingMask); else mShadowTechnique->disableShadows(true); }
void ShadowManager::enableOutdoorMode() { if (mEnableShadows) mShadowTechnique->enableShadows(); mShadowSettings->setCastsShadowTraversalMask(mOutdoorShadowCastingMask); }}