mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 03:15:32 +00:00
More formatting, OpenCS cells are unbroken
This commit is contained in:
parent
142c6d2993
commit
690995988b
9 changed files with 251 additions and 158 deletions
|
@ -83,7 +83,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
|
|||
defines["clamp"] = "1"; // Clamp lighting
|
||||
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
|
||||
defines["radialFog"] = "0";
|
||||
defines["ffpLighting"] = "0";
|
||||
defines["ffpLighting"] = "1";
|
||||
for (const auto& define : shadowDefines)
|
||||
defines[define.first] = define.second;
|
||||
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
|
||||
|
|
|
@ -199,8 +199,8 @@ namespace MWRender
|
|||
, mFieldOfViewOverridden(false)
|
||||
, mFieldOfViewOverride(0.f)
|
||||
{
|
||||
auto lightingModelString = Settings::Manager::getString("lighting method", "Shaders");
|
||||
bool usingFFPLighting = lightingModelString == "legacy" && SceneUtil::LightManager::isValidLightingModelString(lightingModelString);
|
||||
auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString(Settings::Manager::getString("lighting method", "Shaders"));
|
||||
bool usingFFPLighting = lightingMethod == SceneUtil::LightingMethod::FFP;
|
||||
|
||||
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
|
||||
resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders");
|
||||
|
@ -217,9 +217,9 @@ namespace MWRender
|
|||
resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::Manager::getString("specular map pattern", "Shaders"));
|
||||
resourceSystem->getSceneManager()->setApplyLightingToEnvMaps(Settings::Manager::getBool("apply lighting to environment maps", "Shaders"));
|
||||
resourceSystem->getSceneManager()->setConvertAlphaTestToAlphaToCoverage(Settings::Manager::getBool("antialias alpha test", "Shaders") && Settings::Manager::getInt("antialiasing", "Video") > 1);
|
||||
|
||||
|
||||
osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager(!forceShaders || usingFFPLighting);
|
||||
// Let LightManager choose which backend to use based, mostly depends on support for UBOs
|
||||
// Let LightManager choose which backend to use based on our hint, mostly depends on support for UBOs
|
||||
resourceSystem->getSceneManager()->getShaderManager().setLightingMethod(sceneRoot->getLightingMethod());
|
||||
resourceSystem->getSceneManager()->setLightingMethod(sceneRoot->getLightingMethod());
|
||||
|
||||
|
@ -262,7 +262,7 @@ namespace MWRender
|
|||
float groundcoverDistance = (Constants::CellSizeInUnits * std::max(1, Settings::Manager::getInt("distance", "Groundcover")) - 1024) * 0.93;
|
||||
globalDefines["groundcoverFadeStart"] = std::to_string(groundcoverDistance * 0.9f);
|
||||
globalDefines["groundcoverFadeEnd"] = std::to_string(groundcoverDistance);
|
||||
|
||||
|
||||
// It is unnecessary to stop/start the viewer as no frames are being rendered yet.
|
||||
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines);
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#include "apps/openmw/mwrender/vismask.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
/* similar to the boost::hash_combine */
|
||||
|
@ -28,7 +26,8 @@ namespace
|
|||
|
||||
bool sortLights(const SceneUtil::LightManager::LightSourceViewBound* left, const SceneUtil::LightManager::LightSourceViewBound* right)
|
||||
{
|
||||
return left->mViewBound.center().length2() - left->mViewBound.radius2()*81 < right->mViewBound.center().length2() - right->mViewBound.radius2()*81;
|
||||
static auto constexpr illuminationBias = 81.f;
|
||||
return left->mViewBound.center().length2() - left->mViewBound.radius2()*illuminationBias < right->mViewBound.center().length2() - right->mViewBound.radius2()*illuminationBias;
|
||||
}
|
||||
|
||||
float getLightRadius(const osg::Light* light)
|
||||
|
@ -99,8 +98,15 @@ namespace SceneUtil
|
|||
return (*mData)[3*index+1];
|
||||
}
|
||||
|
||||
auto& getData() { return mData; }
|
||||
void dirty() { mData->dirty(); }
|
||||
auto& getData()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
void dirty()
|
||||
{
|
||||
mData->dirty();
|
||||
}
|
||||
|
||||
static constexpr int queryBlockSize(int sz)
|
||||
{
|
||||
|
@ -135,6 +141,7 @@ namespace SceneUtil
|
|||
{
|
||||
switch (method)
|
||||
{
|
||||
case LightingMethod::Undefined:
|
||||
case LightingMethod::FFP:
|
||||
{
|
||||
break;
|
||||
|
@ -232,7 +239,7 @@ namespace SceneUtil
|
|||
|
||||
bool getModeUsage(ModeUsage & usage) const override
|
||||
{
|
||||
for (size_t i=0; i<mLights.size(); ++i)
|
||||
for (size_t i = 0; i < mLights.size(); ++i)
|
||||
usage.usesMode(GL_LIGHT0 + mIndex + i);
|
||||
return true;
|
||||
}
|
||||
|
@ -254,7 +261,7 @@ namespace SceneUtil
|
|||
|
||||
LightStateCache* cache = getLightStateCache(state.getContextID());
|
||||
|
||||
for (size_t i=0; i<mLights.size(); ++i)
|
||||
for (size_t i = 0; i < mLights.size(); ++i)
|
||||
{
|
||||
osg::Light* current = cache->lastAppliedLight[i+mIndex];
|
||||
if (current != mLights[i].get())
|
||||
|
@ -269,29 +276,28 @@ namespace SceneUtil
|
|||
|
||||
void applyLight(GLenum lightNum, const osg::Light* light) const
|
||||
{
|
||||
glLightfv( lightNum, GL_AMBIENT, light->getAmbient().ptr() );
|
||||
glLightfv( lightNum, GL_DIFFUSE, light->getDiffuse().ptr() );
|
||||
glLightfv( lightNum, GL_SPECULAR, light->getSpecular().ptr() );
|
||||
glLightfv( lightNum, GL_POSITION, light->getPosition().ptr() );
|
||||
glLightfv(lightNum, GL_AMBIENT, light->getAmbient().ptr());
|
||||
glLightfv(lightNum, GL_DIFFUSE, light->getDiffuse().ptr());
|
||||
glLightfv(lightNum, GL_SPECULAR, light->getSpecular().ptr());
|
||||
glLightfv(lightNum, GL_POSITION, light->getPosition().ptr());
|
||||
// TODO: enable this once spot lights are supported
|
||||
// need to transform SPOT_DIRECTION by the world matrix?
|
||||
//glLightfv( lightNum, GL_SPOT_DIRECTION, light->getDirection().ptr() );
|
||||
//glLightf ( lightNum, GL_SPOT_EXPONENT, light->getSpotExponent() );
|
||||
//glLightf ( lightNum, GL_SPOT_CUTOFF, light->getSpotCutoff() );
|
||||
glLightf ( lightNum, GL_CONSTANT_ATTENUATION, light->getConstantAttenuation() );
|
||||
glLightf ( lightNum, GL_LINEAR_ATTENUATION, light->getLinearAttenuation() );
|
||||
glLightf ( lightNum, GL_QUADRATIC_ATTENUATION, light->getQuadraticAttenuation() );
|
||||
//glLightfv(lightNum, GL_SPOT_DIRECTION, light->getDirection().ptr());
|
||||
//glLightf(lightNum, GL_SPOT_EXPONENT, light->getSpotExponent());
|
||||
//glLightf(lightNum, GL_SPOT_CUTOFF, light->getSpotCutoff());
|
||||
glLightf(lightNum, GL_CONSTANT_ATTENUATION, light->getConstantAttenuation());
|
||||
glLightf(lightNum, GL_LINEAR_ATTENUATION, light->getLinearAttenuation());
|
||||
glLightf(lightNum, GL_QUADRATIC_ATTENUATION, light->getQuadraticAttenuation());
|
||||
}
|
||||
|
||||
private:
|
||||
size_t mIndex;
|
||||
|
||||
std::vector<osg::ref_ptr<osg::Light>> mLights;
|
||||
};
|
||||
|
||||
LightManager* findLightManager(const osg::NodePath& path)
|
||||
{
|
||||
for (size_t i=0;i<path.size(); ++i)
|
||||
for (size_t i = 0; i < path.size(); ++i)
|
||||
{
|
||||
if (LightManager* lightManager = dynamic_cast<LightManager*>(path[i]))
|
||||
return lightManager;
|
||||
|
@ -406,8 +412,8 @@ namespace SceneUtil
|
|||
return stateset;
|
||||
}
|
||||
|
||||
// Cached statesets must be re-validated in case the light indicies change. There is no actual link between
|
||||
// a lights ID and the buffer index it will eventually be assigned (or reassigned) to.
|
||||
// Cached statesets must be revalidated in case the light indices change. There is no actual link between
|
||||
// a light's ID and the buffer index it will eventually be assigned (or reassigned) to.
|
||||
void update(osg::StateSet* stateset, const LightManager::LightList& lightList, size_t frameNum) override
|
||||
{
|
||||
int newCount = 0;
|
||||
|
@ -587,19 +593,56 @@ namespace SceneUtil
|
|||
LightManager* mLightManager;
|
||||
};
|
||||
|
||||
const std::unordered_map<std::string, LightingMethod> LightManager::mLightingMethodSettingMap = {
|
||||
{"legacy", LightingMethod::FFP}
|
||||
,{"shaders compatibility", LightingMethod::PerObjectUniform}
|
||||
,{"shaders", LightingMethod::SingleUBO}
|
||||
};
|
||||
|
||||
bool LightManager::isValidLightingModelString(const std::string& value)
|
||||
{
|
||||
static const std::unordered_set<std::string> validLightingModels = {"legacy", "default", "experimental"};
|
||||
return validLightingModels.count(value) != 0;
|
||||
return LightManager::mLightingMethodSettingMap.find(value) != LightManager::mLightingMethodSettingMap.end();
|
||||
}
|
||||
|
||||
LightingMethod LightManager::getLightingMethodFromString(const std::string& value)
|
||||
{
|
||||
auto it = LightManager::mLightingMethodSettingMap.find(value);
|
||||
if (it != LightManager::mLightingMethodSettingMap.end())
|
||||
return it->second;
|
||||
else
|
||||
return LightingMethod::Undefined;
|
||||
}
|
||||
|
||||
LightManager::LightManager(bool ffp)
|
||||
: mStartLight(0)
|
||||
, mLightingMask(~0u)
|
||||
, mSun(nullptr)
|
||||
, mPointLightRadiusMultiplier(std::clamp(Settings::Manager::getFloat("light bounds multiplier", "Shaders"), 0.f, 10.f))
|
||||
, mPointLightRadiusMultiplier(1.f)
|
||||
, mPointLightFadeEnd(0.f)
|
||||
, mPointLightFadeStart(0.f)
|
||||
{
|
||||
if (ffp)
|
||||
{
|
||||
setLightingMethod(LightingMethod::FFP);
|
||||
initFFP(LightManager::mFFPMaxLights);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string lightingMethodString = Settings::Manager::getString("lighting method", "Shaders");
|
||||
auto lightingMethod = LightManager::getLightingMethodFromString(lightingMethodString);
|
||||
if (lightingMethod == LightingMethod::Undefined)
|
||||
{
|
||||
Log(Debug::Error) << "Invalid option for 'lighting method': got '" << lightingMethodString
|
||||
<< "', expected legacy, shaders compatible, or shaders. Falling back to 'shaders compatible'.";
|
||||
setLightingMethod(LightingMethod::PerObjectUniform);
|
||||
}
|
||||
else
|
||||
{
|
||||
setLightingMethod(lightingMethod);
|
||||
}
|
||||
|
||||
mPointLightRadiusMultiplier = std::clamp(Settings::Manager::getFloat("light bounds multiplier", "Shaders"), 0.f, 10.f);
|
||||
|
||||
mPointLightFadeEnd = std::max(0.f, Settings::Manager::getFloat("maximum light distance", "Shaders"));
|
||||
if (mPointLightFadeEnd > 0)
|
||||
{
|
||||
|
@ -607,84 +650,31 @@ namespace SceneUtil
|
|||
mPointLightFadeStart = mPointLightFadeEnd * mPointLightFadeStart;
|
||||
}
|
||||
|
||||
auto lightingModelString = Settings::Manager::getString("lighting method", "Shaders");
|
||||
bool validLightingModel = isValidLightingModelString(lightingModelString);
|
||||
if (!validLightingModel)
|
||||
Log(Debug::Error) << "Invalid option for 'lighting model': got '" << lightingModelString
|
||||
<< "', expected legacy, default, or experimental.";
|
||||
|
||||
if (ffp || !validLightingModel)
|
||||
{
|
||||
setMaxLights(LightManager::mFFPMaxLights);
|
||||
setLightingMethod(LightingMethod::FFP);
|
||||
|
||||
for (int i=0; i<getMaxLights(); ++i)
|
||||
mDummies.push_back(new FFPLightStateAttribute(i, std::vector<osg::ref_ptr<osg::Light> >()));
|
||||
|
||||
setUpdateCallback(new LightManagerUpdateCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
osg::GLExtensions* exts = osg::GLExtensions::Get(0, false);
|
||||
bool supportsUBO = exts && exts->isUniformBufferObjectSupported;
|
||||
bool supportsGPU4 = exts && exts->isGpuShader4Supported;
|
||||
|
||||
if (!supportsUBO)
|
||||
Log(Debug::Info) << "GL_ARB_uniform_buffer_object not supported: using fallback uniforms";
|
||||
else if (!supportsGPU4)
|
||||
Log(Debug::Info) << "GL_EXT_gpu_shader4 not supported: using fallback uniforms";
|
||||
if (getLightingMethod() == LightingMethod::SingleUBO)
|
||||
{
|
||||
if (!supportsUBO)
|
||||
Log(Debug::Info) << "GL_ARB_uniform_buffer_object not supported: using fallback uniforms";
|
||||
else if (!supportsGPU4)
|
||||
Log(Debug::Info) << "GL_EXT_gpu_shader4 not supported: using fallback uniforms";
|
||||
}
|
||||
|
||||
int targetLights = Settings::Manager::getInt("max lights", "Shaders");
|
||||
auto* stateset = getOrCreateStateSet();
|
||||
|
||||
if (!supportsUBO || !supportsGPU4 || lightingModelString == "default")
|
||||
if (!supportsUBO || !supportsGPU4 || getLightingMethod() == LightingMethod::PerObjectUniform)
|
||||
{
|
||||
setLightingMethod(LightingMethod::PerObjectUniform);
|
||||
setMaxLights(std::max(2, targetLights));
|
||||
|
||||
mLightUniforms.resize(getMaxLights()+1);
|
||||
for (size_t i = 0; i < mLightUniforms.size(); ++i)
|
||||
{
|
||||
osg::ref_ptr<osg::Uniform> udiffuse = new osg::Uniform(osg::Uniform::FLOAT_VEC4, ("LightBuffer[" + std::to_string(i) + "].diffuse").c_str());
|
||||
osg::ref_ptr<osg::Uniform> uspecular = new osg::Uniform(osg::Uniform::FLOAT_VEC4, ("LightBuffer[" + std::to_string(i) + "].specular").c_str());
|
||||
osg::ref_ptr<osg::Uniform> uambient = new osg::Uniform(osg::Uniform::FLOAT_VEC4, ("LightBuffer[" + std::to_string(i) + "].ambient").c_str());
|
||||
osg::ref_ptr<osg::Uniform> uposition = new osg::Uniform(osg::Uniform::FLOAT_VEC4, ("LightBuffer[" + std::to_string(i) + "].position").c_str());
|
||||
osg::ref_ptr<osg::Uniform> uattenuation = new osg::Uniform(osg::Uniform::FLOAT_VEC4, ("LightBuffer[" + std::to_string(i) + "].attenuation").c_str());
|
||||
|
||||
mLightUniforms[i].emplace(UniformKey::Diffuse, udiffuse);
|
||||
mLightUniforms[i].emplace(UniformKey::Ambient, uambient);
|
||||
mLightUniforms[i].emplace(UniformKey::Specular, uspecular);
|
||||
mLightUniforms[i].emplace(UniformKey::Position, uposition);
|
||||
mLightUniforms[i].emplace(UniformKey::Attenuation, uattenuation);
|
||||
|
||||
stateset->addUniform(udiffuse);
|
||||
stateset->addUniform(uambient);
|
||||
stateset->addUniform(uposition);
|
||||
stateset->addUniform(uattenuation);
|
||||
|
||||
// specular isn't used besides sun, complete waste to upload it
|
||||
if (i == 0)
|
||||
stateset->addUniform(uspecular);
|
||||
}
|
||||
initPerObjectUniform(targetLights);
|
||||
}
|
||||
else
|
||||
{
|
||||
setLightingMethod(LightingMethod::SingleUBO);
|
||||
setMaxLights(std::clamp(targetLights, 2, getMaxLightsInScene() / 2));
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
mLightBuffers[i] = new LightBuffer(getMaxLightsInScene());
|
||||
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
|
||||
ubo->setUsage(GL_STREAM_DRAW);
|
||||
|
||||
mLightBuffers[i]->getData()->setBufferObject(ubo);
|
||||
}
|
||||
|
||||
stateset->setAttribute(new LightManagerStateAttribute(this), osg::StateAttribute::ON);
|
||||
initSingleUBO(targetLights);
|
||||
}
|
||||
|
||||
stateset->addUniform(new osg::Uniform("PointLightCount", 0));
|
||||
getOrCreateStateSet()->addUniform(new osg::Uniform("PointLightCount", 0));
|
||||
|
||||
setUpdateCallback(new LightManagerUpdateCallback);
|
||||
addCullCallback(new LightManagerCullCallback(this));
|
||||
|
@ -726,7 +716,7 @@ namespace SceneUtil
|
|||
int LightManager::getMaxLightsInScene() const
|
||||
{
|
||||
static constexpr int max = 16384 / LightBuffer::queryBlockSize(1);
|
||||
return max;
|
||||
return max;
|
||||
}
|
||||
|
||||
Shader::ShaderManager::DefineMap LightManager::getLightDefines() const
|
||||
|
@ -746,6 +736,66 @@ namespace SceneUtil
|
|||
return defines;
|
||||
}
|
||||
|
||||
void LightManager::initFFP(int targetLights)
|
||||
{
|
||||
setMaxLights(targetLights);
|
||||
|
||||
for (int i = 0; i < getMaxLights(); ++i)
|
||||
mDummies.push_back(new FFPLightStateAttribute(i, std::vector<osg::ref_ptr<osg::Light>>()));
|
||||
|
||||
setUpdateCallback(new LightManagerUpdateCallback);
|
||||
}
|
||||
|
||||
void LightManager::initPerObjectUniform(int targetLights)
|
||||
{
|
||||
auto* stateset = getOrCreateStateSet();
|
||||
|
||||
setMaxLights(std::max(2, targetLights));
|
||||
|
||||
mLightUniforms.resize(getMaxLights()+1);
|
||||
for (size_t i = 0; i < mLightUniforms.size(); ++i)
|
||||
{
|
||||
osg::ref_ptr<osg::Uniform> udiffuse = new osg::Uniform(osg::Uniform::FLOAT_VEC4, ("LightBuffer[" + std::to_string(i) + "].diffuse").c_str());
|
||||
osg::ref_ptr<osg::Uniform> uspecular = new osg::Uniform(osg::Uniform::FLOAT_VEC4, ("LightBuffer[" + std::to_string(i) + "].specular").c_str());
|
||||
osg::ref_ptr<osg::Uniform> uambient = new osg::Uniform(osg::Uniform::FLOAT_VEC4, ("LightBuffer[" + std::to_string(i) + "].ambient").c_str());
|
||||
osg::ref_ptr<osg::Uniform> uposition = new osg::Uniform(osg::Uniform::FLOAT_VEC4, ("LightBuffer[" + std::to_string(i) + "].position").c_str());
|
||||
osg::ref_ptr<osg::Uniform> uattenuation = new osg::Uniform(osg::Uniform::FLOAT_VEC4, ("LightBuffer[" + std::to_string(i) + "].attenuation").c_str());
|
||||
|
||||
mLightUniforms[i].emplace(UniformKey::Diffuse, udiffuse);
|
||||
mLightUniforms[i].emplace(UniformKey::Ambient, uambient);
|
||||
mLightUniforms[i].emplace(UniformKey::Specular, uspecular);
|
||||
mLightUniforms[i].emplace(UniformKey::Position, uposition);
|
||||
mLightUniforms[i].emplace(UniformKey::Attenuation, uattenuation);
|
||||
|
||||
stateset->addUniform(udiffuse);
|
||||
stateset->addUniform(uambient);
|
||||
stateset->addUniform(uposition);
|
||||
stateset->addUniform(uattenuation);
|
||||
|
||||
// specular isn't used besides sun, complete waste to upload it
|
||||
if (i == 0)
|
||||
stateset->addUniform(uspecular);
|
||||
}
|
||||
}
|
||||
|
||||
void LightManager::initSingleUBO(int targetLights)
|
||||
{
|
||||
setMaxLights(std::clamp(targetLights, 2, getMaxLightsInScene() / 2));
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
mLightBuffers[i] = new LightBuffer(getMaxLightsInScene());
|
||||
|
||||
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
|
||||
ubo->setUsage(GL_STREAM_DRAW);
|
||||
|
||||
mLightBuffers[i]->getData()->setBufferObject(ubo);
|
||||
}
|
||||
|
||||
getOrCreateStateSet()->setAttribute(new LightManagerStateAttribute(this), osg::StateAttribute::ON);
|
||||
}
|
||||
|
||||
|
||||
void LightManager::setLightingMethod(LightingMethod method)
|
||||
{
|
||||
mLightingMethod = method;
|
||||
|
@ -760,6 +810,9 @@ namespace SceneUtil
|
|||
case LightingMethod::PerObjectUniform:
|
||||
mStateSetGenerator = std::make_unique<StateSetGeneratorPerObjectUniform>();
|
||||
break;
|
||||
case LightingMethod::Undefined:
|
||||
mStateSetGenerator = nullptr;
|
||||
break;
|
||||
}
|
||||
mStateSetGenerator->mLightManager = this;
|
||||
}
|
||||
|
@ -783,7 +836,7 @@ namespace SceneUtil
|
|||
// Set default light state to zero
|
||||
// This is necessary because shaders don't respect glDisable(GL_LIGHTX) so in addition to disabling
|
||||
// we'll have to set a light state that has no visible effect
|
||||
for (int i=start; i<getMaxLights(); ++i)
|
||||
for (int i = start; i < getMaxLights(); ++i)
|
||||
{
|
||||
osg::ref_ptr<DisableLight> defaultLight (new DisableLight(i));
|
||||
getOrCreateStateSet()->setAttributeAndModes(defaultLight, osg::StateAttribute::OFF);
|
||||
|
@ -802,7 +855,7 @@ namespace SceneUtil
|
|||
mLightsInViewSpace.clear();
|
||||
|
||||
// Do an occasional cleanup for orphaned lights.
|
||||
for (int i=0; i<2; ++i)
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
if (mStateSetCache[i].size() > 5000)
|
||||
mStateSetCache[i].clear();
|
||||
|
@ -836,7 +889,7 @@ namespace SceneUtil
|
|||
{
|
||||
// possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists)
|
||||
size_t hash = 0;
|
||||
for (size_t i=0; i<lightList.size();++i)
|
||||
for (size_t i = 0; i < lightList.size(); ++i)
|
||||
{
|
||||
auto id = lightList[i]->mLightSource->getId();
|
||||
hash_combine(hash, id);
|
||||
|
@ -860,13 +913,10 @@ namespace SceneUtil
|
|||
mStateSetGenerator->update(found->second, lightList, frameNum);
|
||||
return found->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto stateset = mStateSetGenerator->generate(lightList, frameNum);
|
||||
stateSetCache.emplace(hash, stateset);
|
||||
return stateset;
|
||||
}
|
||||
return new osg::StateSet;
|
||||
|
||||
auto stateset = mStateSetGenerator->generate(lightList, frameNum);
|
||||
stateSetCache.emplace(hash, stateset);
|
||||
return stateset;
|
||||
}
|
||||
|
||||
const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix, size_t frameNum)
|
||||
|
@ -946,7 +996,7 @@ namespace SceneUtil
|
|||
{
|
||||
mId = sLightId++;
|
||||
|
||||
for (int i=0; i<2; ++i)
|
||||
for (int i = 0; i < 2; ++i)
|
||||
mLight[i] = new osg::Light(*copy.mLight[i].get(), copyop);
|
||||
}
|
||||
|
||||
|
@ -981,7 +1031,6 @@ namespace SceneUtil
|
|||
// makes sure we don't update it more than once per frame when rendering with multiple cameras
|
||||
if (mLastFrameNumber != cv->getTraversalNumber())
|
||||
{
|
||||
|
||||
mLastFrameNumber = cv->getTraversalNumber();
|
||||
|
||||
// Don't use Camera::getViewMatrix, that one might be relative to another camera!
|
||||
|
@ -994,7 +1043,7 @@ namespace SceneUtil
|
|||
osg::Transform* transform = node->asTransform();
|
||||
if (transform)
|
||||
{
|
||||
for (size_t i=0; i<transform->getNumChildren(); ++i)
|
||||
for (size_t i = 0; i < transform->getNumChildren(); ++i)
|
||||
nodeBound.expandBy(transform->getChild(i)->getBound());
|
||||
}
|
||||
else
|
||||
|
@ -1003,7 +1052,7 @@ namespace SceneUtil
|
|||
transformBoundingSphere(mat, nodeBound);
|
||||
|
||||
mLightList.clear();
|
||||
for (size_t i=0; i<lights.size(); ++i)
|
||||
for (size_t i = 0; i < lights.size(); ++i)
|
||||
{
|
||||
const LightManager::LightSourceViewBound& l = lights[i];
|
||||
|
||||
|
@ -1014,7 +1063,6 @@ namespace SceneUtil
|
|||
mLightList.push_back(&l);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mLightList.empty())
|
||||
{
|
||||
size_t maxLights = mLightManager->getMaxLights() - mLightManager->getStartLight();
|
||||
|
@ -1025,7 +1073,7 @@ namespace SceneUtil
|
|||
{
|
||||
// remove lights culled by this camera
|
||||
LightManager::LightList lightList = mLightList;
|
||||
for (auto it = lightList.begin(); it != lightList.end() && lightList.size() > maxLights; )
|
||||
for (auto it = lightList.begin(); it != lightList.end() && lightList.size() > maxLights;)
|
||||
{
|
||||
osg::CullStack::CullingStack& stack = cv->getModelViewCullingStack();
|
||||
|
||||
|
@ -1053,6 +1101,7 @@ namespace SceneUtil
|
|||
else
|
||||
stateset = mLightManager->getLightListStateSet(mLightList, cv->getTraversalNumber(), cv->getCurrentRenderStage()->getInitialViewMatrix());
|
||||
|
||||
|
||||
cv->pushStateSet(stateset);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
|
||||
|
||||
#include <set>
|
||||
#include <cassert>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
#include <osg/Light>
|
||||
|
||||
#include <osg/Group>
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/observer_ptr>
|
||||
|
@ -18,6 +18,7 @@ namespace osgUtil
|
|||
{
|
||||
class CullVisitor;
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
class LightBuffer;
|
||||
|
@ -27,7 +28,8 @@ namespace SceneUtil
|
|||
{
|
||||
FFP,
|
||||
SingleUBO,
|
||||
PerObjectUniform
|
||||
PerObjectUniform,
|
||||
Undefined
|
||||
};
|
||||
|
||||
void configureStateSetSunOverride(LightingMethod method, const osg::Light* light, osg::StateSet* stateset, int mode = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||
|
@ -98,8 +100,8 @@ namespace SceneUtil
|
|||
class LightManager : public osg::Group
|
||||
{
|
||||
public:
|
||||
|
||||
static bool isValidLightingModelString(const std::string& value);
|
||||
static LightingMethod getLightingMethodFromString(const std::string& value);
|
||||
|
||||
enum class UniformKey
|
||||
{
|
||||
|
@ -136,7 +138,7 @@ namespace SceneUtil
|
|||
/// By default, it's ~0u i.e. always on.
|
||||
/// If you have some views that do not require lighting, then set the Camera's cull mask to not include
|
||||
/// the lightingMask for a much faster cull and rendering.
|
||||
void setLightingMask (size_t mask);
|
||||
void setLightingMask(size_t mask);
|
||||
size_t getLightingMask() const;
|
||||
|
||||
/// Set the first light index that should be used by this manager, typically the number of directional lights in the scene.
|
||||
|
@ -167,7 +169,7 @@ namespace SceneUtil
|
|||
auto& getDummies() { return mDummies; }
|
||||
|
||||
auto& getLightIndexMap(size_t frameNum) { return mLightIndexMaps[frameNum%2]; }
|
||||
|
||||
|
||||
auto& getLightBuffer(size_t frameNum) { return mLightBuffers[frameNum%2]; }
|
||||
|
||||
auto& getLightUniform(int index, UniformKey key) { return mLightUniforms[index][key]; }
|
||||
|
@ -175,10 +177,13 @@ namespace SceneUtil
|
|||
std::map<std::string, std::string> getLightDefines() const;
|
||||
|
||||
private:
|
||||
|
||||
friend class LightManagerStateAttribute;
|
||||
friend class LightManagerCullCallback;
|
||||
|
||||
void initFFP(int targetLights);
|
||||
void initPerObjectUniform(int targetLights);
|
||||
void initSingleUBO(int targetLights);
|
||||
|
||||
void setLightingMethod(LightingMethod method);
|
||||
void setMaxLights(int value);
|
||||
|
||||
|
@ -188,7 +193,7 @@ namespace SceneUtil
|
|||
|
||||
using LightSourceViewBoundCollection = std::vector<LightSourceViewBound>;
|
||||
std::map<osg::observer_ptr<osg::Camera>, LightSourceViewBoundCollection> mLightsInViewSpace;
|
||||
|
||||
|
||||
// < Light list hash , StateSet >
|
||||
using LightStateSetMap = std::map<size_t, osg::ref_ptr<osg::StateSet>>;
|
||||
LightStateSetMap mStateSetCache[2];
|
||||
|
@ -221,6 +226,8 @@ namespace SceneUtil
|
|||
int mMaxLights;
|
||||
|
||||
static constexpr auto mFFPMaxLights = 8;
|
||||
|
||||
static const std::unordered_map<std::string, LightingMethod> mLightingMethodSettingMap;
|
||||
};
|
||||
|
||||
/// To receive lighting, objects must be decorated by a LightListCallback. Light list callbacks must be added via
|
||||
|
@ -259,7 +266,8 @@ namespace SceneUtil
|
|||
size_t mLastFrameNumber;
|
||||
LightManager::LightList mLightList;
|
||||
std::set<SceneUtil::LightSource*> mIgnoredLightSources;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <components/sceneutil/lightmanager.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ Only affects objects that render with shaders (see 'force shaders' option).
|
|||
Always affects terrain.
|
||||
|
||||
Leaving this option at its default makes the lighting compatible with Morrowind's fixed-function method,
|
||||
but the lighting may appear dull and there might be colour shifts.
|
||||
but the lighting may appear dull and there might be colour shifts.
|
||||
Setting this option to 'false' results in more dynamic lighting.
|
||||
|
||||
auto use object normal maps
|
||||
|
@ -152,32 +152,51 @@ lighting method
|
|||
---------------
|
||||
|
||||
:Type: string
|
||||
:Range: legacy|default|experimental
|
||||
:Range: legacy|shaders compatibility|shaders
|
||||
:Default: default
|
||||
|
||||
Sets the internal handling of light sources.
|
||||
Sets the internal handling of light sources.
|
||||
|
||||
'legacy' is restricted to a maximum of 8 lights per object and guarantees fixed function pipeline compatible lighting.
|
||||
'legacy' is restricted to 8 lights per object and emulates fixed function
|
||||
pipeline compatible lighting.
|
||||
|
||||
'default' removes the light limit via :ref:`max lights` and follows a new attenuation formula which can drastically reduce light popping and seams.
|
||||
This mode also enables vertex lighting on groundcover, which is otherwise completely disabled with 'legacy'.
|
||||
It is recommended to use this mode with older hardware, as the technique ensures a range of compatibility equal to that of 'legacy'.
|
||||
'shaders compatibility' removes the light limit via :ref:`max lights` and
|
||||
follows a modifed attenuation formula which can drastically reduce light popping
|
||||
and seams. This mode also enables lighting on groundcover and a configurable
|
||||
light fade. It is recommended to use this with older hardware and a light limit
|
||||
closer to 8. Because of its wide range of compatibility it is set as the
|
||||
default.
|
||||
|
||||
'experimental' carries all of the benefits that 'legacy' has, but uses a modern approach that allows for a higher 'max lights' count with little to no performance penalties on modern hardware.
|
||||
'shaders' carries all of the benefits that 'shaders compatibility' does, but
|
||||
uses a modern approach that allows for a higher :ref:`max lights` count with
|
||||
little to no performance penalties on modern hardware. It is recommended to use
|
||||
this mode when supported and where the GPU is not a bottleneck. On some weaker
|
||||
devices, using this mode along with :ref:`force per pixel lighting` can carry
|
||||
performance penalties.
|
||||
|
||||
Note that when enabled, groundcover lighting is forced to be vertex lighting,
|
||||
unless normal maps are provided. This is due to some groundcover mods using the
|
||||
Z-Up Normals technique to avoid some common issues with shading. As a
|
||||
consequence, per pixel lighting would give undesirable results.
|
||||
|
||||
This setting has no effect if :ref:`force shaders` is 'false'.
|
||||
|
||||
light bounds multiplier
|
||||
-----------------------
|
||||
|
||||
:Type: float
|
||||
:Range: 0.0-10.0
|
||||
:Default: 2.0
|
||||
:Default: 1.75
|
||||
|
||||
Controls the bounding sphere radius of point lights, which is used to determine if an object should receive lighting from a particular light source.
|
||||
Note, this has no direct effect on the overall illumination of lights.
|
||||
Larger multipliers will allow for smoother transitions of light sources, but may require an increase in :ref:`max lights` and thus carries a performance penalty.
|
||||
This especially helps with abrupt light popping with handheld light sources such as torches and lanterns.
|
||||
Controls the bounding sphere radius of point lights, which is used to determine
|
||||
if an object should receive lighting from a particular light source. Note, this
|
||||
has no direct effect on the overall illumination of lights. Larger multipliers
|
||||
will allow for smoother transitions of light sources, but may require an
|
||||
increase in :ref:`max lights` and thus carries a performance penalty. This
|
||||
especially helps with abrupt light popping with handheld light sources such as
|
||||
torches and lanterns.
|
||||
|
||||
It is recommended to keep this at 1.0 if :ref:`lighting method` is set to 'legacy', as the number of lights is fixed in that mode.
|
||||
This setting has no effect if :ref:`lighting method` is 'legacy'.
|
||||
|
||||
maximum light distance
|
||||
----------------------
|
||||
|
@ -186,9 +205,11 @@ maximum light distance
|
|||
:Range: The whole range of 32-bit floating point
|
||||
:Default: 8192
|
||||
|
||||
The maximum distance from the camera that lights will be illuminated, applies to both interiors and exteriors.
|
||||
A lower distance will improve performance.
|
||||
Set this to a non-positive value to disable fading.
|
||||
The maximum distance from the camera that lights will be illuminated, applies to
|
||||
both interiors and exteriors. A lower distance will improve performance. Set
|
||||
this to a non-positive value to disable fading.
|
||||
|
||||
This setting has no effect if :ref:`lighting method` is 'legacy'.
|
||||
|
||||
light fade start
|
||||
----------------
|
||||
|
@ -199,18 +220,23 @@ light fade start
|
|||
|
||||
The fraction of the maximum distance at which lights will begin to fade away.
|
||||
Tweaking it will make the transition proportionally more or less smooth.
|
||||
This setting has no effect if the maximum light distance is non-positive.
|
||||
|
||||
This setting has no effect if the :ref:`maximum light distance` is non-positive
|
||||
or :ref:`lighting method` is 'legacy'.
|
||||
|
||||
max lights
|
||||
----------
|
||||
|
||||
:Type: integer
|
||||
:Range: >=2
|
||||
:Default: 16
|
||||
:Default: 8
|
||||
|
||||
Sets the maximum number of lights that each object can receive lighting from.
|
||||
Has no effect if :ref:`force shaders` option is off or :ref:`lighting method` is 'legacy'. In this case the maximum number of lights is fixed at 8.
|
||||
Increasing this too much can cause significant performance loss, especially if :ref:`lighting method` is not set to 'experimental' or :ref:`force per pixel lighting` is on.
|
||||
Increasing this too much can cause significant performance loss, especially if
|
||||
:ref:`lighting method` is not set to 'shaders' or :ref:`force per pixel
|
||||
lighting` is on.
|
||||
|
||||
This setting has no effect if :ref:`lighting method` is 'legacy'.
|
||||
|
||||
antialias alpha test
|
||||
---------------------------------------
|
||||
|
|
|
@ -442,23 +442,32 @@ apply lighting to environment maps = false
|
|||
# This makes fogging independent from the viewing angle. Shaders will be used to render all objects.
|
||||
radial fog = false
|
||||
|
||||
# Internal handling of lights, values are 'legacy', 'default', 'experimental'
|
||||
lighting method = experimental
|
||||
# Internal handling of lights, ignored if 'force shaders' is off. "legacy"
|
||||
# provides fixed function pipeline emulation."shaders compatibility" (default)
|
||||
# uncaps the light limit, enables groundcover lighting, and uses a modified
|
||||
# attenuation formula to reduce popping and light seams. "shaders" comes with
|
||||
# all these benefits and is meant for larger light limits, but may not be
|
||||
# supported on older hardware and may be less performant on weaker hardware when
|
||||
# 'force per pixel lighting' is enabled.
|
||||
lighting method = shaders compatibility
|
||||
|
||||
# Sets the bounding sphere multiplier of light sources, which are used to determine if an object should
|
||||
# receive lighting. Higher values will allow for smoother transitions of light sources, but may have a performance cost and
|
||||
# requires a higher number of 'max lights' set. It is recommended to keep this at 1.0 with 'legacy' lighting enabled.
|
||||
light bounds multiplier = 1.0
|
||||
# Sets the bounding sphere multiplier of light sources, which are used to
|
||||
# determine if an object should receive lighting. Higher values will allow for
|
||||
# smoother transitions of light sources, but may have a performance cost and
|
||||
# requires a higher number of 'max lights' set. It is recommended to keep this
|
||||
# at 1.0 with 'legacy' lighting enabled.
|
||||
light bounds multiplier = 1.75
|
||||
|
||||
# The distance from the camera at which lights fade away completely. Set to 0 to disable fading.
|
||||
# The distance from the camera at which lights fade away completely.
|
||||
# Set to 0 to disable fading.
|
||||
maximum light distance = 8192
|
||||
|
||||
# Fraction of the maximum distance at which lights begin to gradually fade away.
|
||||
light fade start = 0.85
|
||||
|
||||
# Set maximum number of lights per object.
|
||||
# Only used when 'lighting method' is not set to 'legacy'
|
||||
max lights = 16
|
||||
# When 'lighting method' is set to 'legacy', this setting will have no effect.
|
||||
max lights = 8
|
||||
|
||||
# Convert the alpha test (cutout/punchthrough alpha) to alpha-to-coverage.
|
||||
# This allows MSAA to work with alpha-tested meshes, producing better-looking edges without pixelation.
|
||||
|
|
|
@ -69,7 +69,7 @@ uniform int PointLightCount;
|
|||
#endif
|
||||
|
||||
void perLightSun(out vec3 ambientOut, out vec3 diffuseOut, vec3 viewPos, vec3 viewNormal)
|
||||
{
|
||||
{
|
||||
vec3 lightDir = normalize(getLight[0].position.xyz);
|
||||
|
||||
#if @lightingModel == LIGHTING_MODEL_SINGLE_UBO
|
||||
|
@ -98,9 +98,9 @@ void perLightSun(out vec3 ambientOut, out vec3 diffuseOut, vec3 viewPos, vec3 vi
|
|||
|
||||
void perLightPoint(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal)
|
||||
{
|
||||
vec3 lightDir = getLight[lightIndex].position.xyz - viewPos;
|
||||
vec3 lightPos = getLight[lightIndex].position.xyz - viewPos;
|
||||
|
||||
float lightDistance = length(lightDir);
|
||||
float lightDistance = length(lightPos);
|
||||
|
||||
#if !@ffpLighting
|
||||
// This has a *considerable* performance uplift where GPU is a bottleneck
|
||||
|
@ -112,7 +112,7 @@ void perLightPoint(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec
|
|||
}
|
||||
#endif
|
||||
|
||||
lightDir = normalize(lightDir);
|
||||
lightPos = normalize(lightPos);
|
||||
|
||||
#if @ffpLighting
|
||||
float illumination = clamp(1.0 / (getLight[lightIndex].constantAttenuation + getLight[lightIndex].linearAttenuation * lightDistance + getLight[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0);
|
||||
|
@ -128,8 +128,8 @@ void perLightPoint(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec
|
|||
ambientOut = getLight[lightIndex].ambient.xyz * illumination;
|
||||
#endif
|
||||
|
||||
float lambert = dot(viewNormal.xyz, lightDir) * illumination;
|
||||
|
||||
float lambert = dot(viewNormal.xyz, lightPos) * illumination;
|
||||
|
||||
#ifndef GROUNDCOVER
|
||||
lambert = max(lambert, 0.0);
|
||||
#else
|
||||
|
@ -179,7 +179,7 @@ void doLighting(vec3 viewPos, vec3 viewNormal, out vec3 diffuseLight, out vec3 a
|
|||
for (int i=1; i <= PointLightCount; ++i)
|
||||
{
|
||||
perLightPoint(ambientOut, diffuseOut, i, viewPos, viewNormal);
|
||||
#else
|
||||
#else
|
||||
for (int i=0; i < PointLightCount; ++i)
|
||||
{
|
||||
perLightPoint(ambientOut, diffuseOut, PointLightIndex[i], viewPos, viewNormal);
|
||||
|
|
|
@ -151,6 +151,8 @@ uniform vec3 nodePosition;
|
|||
|
||||
uniform float rainIntensity;
|
||||
|
||||
#define PER_PIXEL_LIGHTING 0
|
||||
|
||||
#include "shadows_fragment.glsl"
|
||||
#include "lighting.glsl"
|
||||
|
||||
|
|
Loading…
Reference in a new issue