mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-30 23:56:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			217 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			217 lines
		
	
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "shadow.hpp"
 | |
| 
 | |
| #include <osgShadow/ShadowSettings>
 | |
| #include <osgShadow/ShadowedScene>
 | |
| 
 | |
| #include <components/misc/strings/algorithm.hpp>
 | |
| #include <components/settings/settings.hpp>
 | |
| #include <components/stereo/stereomanager.hpp>
 | |
| 
 | |
| #include "mwshadowtechnique.hpp"
 | |
| 
 | |
| namespace SceneUtil
 | |
| {
 | |
|     using namespace osgShadow;
 | |
| 
 | |
|     void ShadowManager::setupShadowSettings(Shader::ShaderManager& shaderManager)
 | |
|     {
 | |
|         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(shaderManager.reserveGlobalTextureUnits(
 | |
|             Shader::ShaderManager::Slot::ShadowMaps, 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"));
 | |
| 
 | |
|         const std::string& computeSceneBounds = Settings::Manager::getString("compute scene bounds", "Shadows");
 | |
|         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);
 | |
| 
 | |
|         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->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 (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);
 | |
| 
 | |
|         if (Stereo::getStereo())
 | |
|             Stereo::Manager::instance().setShadowTechnique(mShadowTechnique);
 | |
| 
 | |
|         mShadowedScene->addChild(sceneRoot);
 | |
|         rootNode->addChild(mShadowedScene);
 | |
|         mShadowedScene->setNodeMask(sceneRoot->getNodeMask());
 | |
| 
 | |
|         mShadowSettings = mShadowedScene->getShadowSettings();
 | |
|         setupShadowSettings(shaderManager);
 | |
| 
 | |
|         mShadowTechnique->setupCastingShader(shaderManager);
 | |
|         mShadowTechnique->setWorldMask(worldMask);
 | |
| 
 | |
|         enableOutdoorMode();
 | |
|     }
 | |
| 
 | |
|     ShadowManager::~ShadowManager()
 | |
|     {
 | |
|         if (Stereo::getStereo())
 | |
|             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);
 | |
|     }
 | |
| }
 |