mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-27 20:11:34 +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["clamp"] = "1"; // Clamp lighting
|
||||||
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
|
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
|
||||||
defines["radialFog"] = "0";
|
defines["radialFog"] = "0";
|
||||||
defines["ffpLighting"] = "0";
|
defines["ffpLighting"] = "1";
|
||||||
for (const auto& define : shadowDefines)
|
for (const auto& define : shadowDefines)
|
||||||
defines[define.first] = define.second;
|
defines[define.first] = define.second;
|
||||||
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
|
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
|
||||||
|
|
|
@ -199,8 +199,8 @@ namespace MWRender
|
||||||
, mFieldOfViewOverridden(false)
|
, mFieldOfViewOverridden(false)
|
||||||
, mFieldOfViewOverride(0.f)
|
, mFieldOfViewOverride(0.f)
|
||||||
{
|
{
|
||||||
auto lightingModelString = Settings::Manager::getString("lighting method", "Shaders");
|
auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString(Settings::Manager::getString("lighting method", "Shaders"));
|
||||||
bool usingFFPLighting = lightingModelString == "legacy" && SceneUtil::LightManager::isValidLightingModelString(lightingModelString);
|
bool usingFFPLighting = lightingMethod == SceneUtil::LightingMethod::FFP;
|
||||||
|
|
||||||
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
|
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
|
||||||
resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders");
|
resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders");
|
||||||
|
@ -219,7 +219,7 @@ namespace MWRender
|
||||||
resourceSystem->getSceneManager()->setConvertAlphaTestToAlphaToCoverage(Settings::Manager::getBool("antialias alpha test", "Shaders") && Settings::Manager::getInt("antialiasing", "Video") > 1);
|
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);
|
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()->getShaderManager().setLightingMethod(sceneRoot->getLightingMethod());
|
||||||
resourceSystem->getSceneManager()->setLightingMethod(sceneRoot->getLightingMethod());
|
resourceSystem->getSceneManager()->setLightingMethod(sceneRoot->getLightingMethod());
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include "apps/openmw/mwrender/vismask.hpp"
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
/* similar to the boost::hash_combine */
|
/* similar to the boost::hash_combine */
|
||||||
|
@ -28,7 +26,8 @@ namespace
|
||||||
|
|
||||||
bool sortLights(const SceneUtil::LightManager::LightSourceViewBound* left, const SceneUtil::LightManager::LightSourceViewBound* right)
|
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)
|
float getLightRadius(const osg::Light* light)
|
||||||
|
@ -99,8 +98,15 @@ namespace SceneUtil
|
||||||
return (*mData)[3*index+1];
|
return (*mData)[3*index+1];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& getData() { return mData; }
|
auto& getData()
|
||||||
void dirty() { mData->dirty(); }
|
{
|
||||||
|
return mData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dirty()
|
||||||
|
{
|
||||||
|
mData->dirty();
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr int queryBlockSize(int sz)
|
static constexpr int queryBlockSize(int sz)
|
||||||
{
|
{
|
||||||
|
@ -135,6 +141,7 @@ namespace SceneUtil
|
||||||
{
|
{
|
||||||
switch (method)
|
switch (method)
|
||||||
{
|
{
|
||||||
|
case LightingMethod::Undefined:
|
||||||
case LightingMethod::FFP:
|
case LightingMethod::FFP:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
@ -285,7 +292,6 @@ namespace SceneUtil
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t mIndex;
|
size_t mIndex;
|
||||||
|
|
||||||
std::vector<osg::ref_ptr<osg::Light>> mLights;
|
std::vector<osg::ref_ptr<osg::Light>> mLights;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -406,8 +412,8 @@ namespace SceneUtil
|
||||||
return stateset;
|
return stateset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cached statesets must be re-validated in case the light indicies change. There is no actual link between
|
// Cached statesets must be revalidated in case the light indices change. There is no actual link between
|
||||||
// a lights ID and the buffer index it will eventually be assigned (or reassigned) to.
|
// 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
|
void update(osg::StateSet* stateset, const LightManager::LightList& lightList, size_t frameNum) override
|
||||||
{
|
{
|
||||||
int newCount = 0;
|
int newCount = 0;
|
||||||
|
@ -587,19 +593,56 @@ namespace SceneUtil
|
||||||
LightManager* mLightManager;
|
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)
|
bool LightManager::isValidLightingModelString(const std::string& value)
|
||||||
{
|
{
|
||||||
static const std::unordered_set<std::string> validLightingModels = {"legacy", "default", "experimental"};
|
return LightManager::mLightingMethodSettingMap.find(value) != LightManager::mLightingMethodSettingMap.end();
|
||||||
return validLightingModels.count(value) != 0;
|
}
|
||||||
|
|
||||||
|
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)
|
LightManager::LightManager(bool ffp)
|
||||||
: mStartLight(0)
|
: mStartLight(0)
|
||||||
, mLightingMask(~0u)
|
, mLightingMask(~0u)
|
||||||
, mSun(nullptr)
|
, 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)
|
, 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"));
|
mPointLightFadeEnd = std::max(0.f, Settings::Manager::getFloat("maximum light distance", "Shaders"));
|
||||||
if (mPointLightFadeEnd > 0)
|
if (mPointLightFadeEnd > 0)
|
||||||
{
|
{
|
||||||
|
@ -607,84 +650,31 @@ namespace SceneUtil
|
||||||
mPointLightFadeStart = mPointLightFadeEnd * mPointLightFadeStart;
|
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);
|
osg::GLExtensions* exts = osg::GLExtensions::Get(0, false);
|
||||||
bool supportsUBO = exts && exts->isUniformBufferObjectSupported;
|
bool supportsUBO = exts && exts->isUniformBufferObjectSupported;
|
||||||
bool supportsGPU4 = exts && exts->isGpuShader4Supported;
|
bool supportsGPU4 = exts && exts->isGpuShader4Supported;
|
||||||
|
|
||||||
|
if (getLightingMethod() == LightingMethod::SingleUBO)
|
||||||
|
{
|
||||||
if (!supportsUBO)
|
if (!supportsUBO)
|
||||||
Log(Debug::Info) << "GL_ARB_uniform_buffer_object not supported: using fallback uniforms";
|
Log(Debug::Info) << "GL_ARB_uniform_buffer_object not supported: using fallback uniforms";
|
||||||
else if (!supportsGPU4)
|
else if (!supportsGPU4)
|
||||||
Log(Debug::Info) << "GL_EXT_gpu_shader4 not supported: using fallback uniforms";
|
Log(Debug::Info) << "GL_EXT_gpu_shader4 not supported: using fallback uniforms";
|
||||||
|
}
|
||||||
|
|
||||||
int targetLights = Settings::Manager::getInt("max lights", "Shaders");
|
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);
|
setLightingMethod(LightingMethod::PerObjectUniform);
|
||||||
setMaxLights(std::max(2, targetLights));
|
initPerObjectUniform(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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setLightingMethod(LightingMethod::SingleUBO);
|
initSingleUBO(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stateset->setAttribute(new LightManagerStateAttribute(this), osg::StateAttribute::ON);
|
getOrCreateStateSet()->addUniform(new osg::Uniform("PointLightCount", 0));
|
||||||
}
|
|
||||||
|
|
||||||
stateset->addUniform(new osg::Uniform("PointLightCount", 0));
|
|
||||||
|
|
||||||
setUpdateCallback(new LightManagerUpdateCallback);
|
setUpdateCallback(new LightManagerUpdateCallback);
|
||||||
addCullCallback(new LightManagerCullCallback(this));
|
addCullCallback(new LightManagerCullCallback(this));
|
||||||
|
@ -746,6 +736,66 @@ namespace SceneUtil
|
||||||
return defines;
|
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)
|
void LightManager::setLightingMethod(LightingMethod method)
|
||||||
{
|
{
|
||||||
mLightingMethod = method;
|
mLightingMethod = method;
|
||||||
|
@ -760,6 +810,9 @@ namespace SceneUtil
|
||||||
case LightingMethod::PerObjectUniform:
|
case LightingMethod::PerObjectUniform:
|
||||||
mStateSetGenerator = std::make_unique<StateSetGeneratorPerObjectUniform>();
|
mStateSetGenerator = std::make_unique<StateSetGeneratorPerObjectUniform>();
|
||||||
break;
|
break;
|
||||||
|
case LightingMethod::Undefined:
|
||||||
|
mStateSetGenerator = nullptr;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
mStateSetGenerator->mLightManager = this;
|
mStateSetGenerator->mLightManager = this;
|
||||||
}
|
}
|
||||||
|
@ -860,14 +913,11 @@ namespace SceneUtil
|
||||||
mStateSetGenerator->update(found->second, lightList, frameNum);
|
mStateSetGenerator->update(found->second, lightList, frameNum);
|
||||||
return found->second;
|
return found->second;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
auto stateset = mStateSetGenerator->generate(lightList, frameNum);
|
auto stateset = mStateSetGenerator->generate(lightList, frameNum);
|
||||||
stateSetCache.emplace(hash, stateset);
|
stateSetCache.emplace(hash, stateset);
|
||||||
return stateset;
|
return stateset;
|
||||||
}
|
}
|
||||||
return new osg::StateSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix, size_t frameNum)
|
const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix, size_t frameNum)
|
||||||
{
|
{
|
||||||
|
@ -981,7 +1031,6 @@ namespace SceneUtil
|
||||||
// makes sure we don't update it more than once per frame when rendering with multiple cameras
|
// makes sure we don't update it more than once per frame when rendering with multiple cameras
|
||||||
if (mLastFrameNumber != cv->getTraversalNumber())
|
if (mLastFrameNumber != cv->getTraversalNumber())
|
||||||
{
|
{
|
||||||
|
|
||||||
mLastFrameNumber = cv->getTraversalNumber();
|
mLastFrameNumber = cv->getTraversalNumber();
|
||||||
|
|
||||||
// Don't use Camera::getViewMatrix, that one might be relative to another camera!
|
// Don't use Camera::getViewMatrix, that one might be relative to another camera!
|
||||||
|
@ -1014,7 +1063,6 @@ namespace SceneUtil
|
||||||
mLightList.push_back(&l);
|
mLightList.push_back(&l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mLightList.empty())
|
if (!mLightList.empty())
|
||||||
{
|
{
|
||||||
size_t maxLights = mLightManager->getMaxLights() - mLightManager->getStartLight();
|
size_t maxLights = mLightManager->getMaxLights() - mLightManager->getStartLight();
|
||||||
|
@ -1053,6 +1101,7 @@ namespace SceneUtil
|
||||||
else
|
else
|
||||||
stateset = mLightManager->getLightListStateSet(mLightList, cv->getTraversalNumber(), cv->getCurrentRenderStage()->getInitialViewMatrix());
|
stateset = mLightManager->getLightListStateSet(mLightList, cv->getTraversalNumber(), cv->getCurrentRenderStage()->getInitialViewMatrix());
|
||||||
|
|
||||||
|
|
||||||
cv->pushStateSet(stateset);
|
cv->pushStateSet(stateset);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
|
#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <cassert>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <unordered_map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <osg/Light>
|
#include <osg/Light>
|
||||||
|
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
#include <osg/NodeVisitor>
|
#include <osg/NodeVisitor>
|
||||||
#include <osg/observer_ptr>
|
#include <osg/observer_ptr>
|
||||||
|
@ -18,6 +18,7 @@ namespace osgUtil
|
||||||
{
|
{
|
||||||
class CullVisitor;
|
class CullVisitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
class LightBuffer;
|
class LightBuffer;
|
||||||
|
@ -27,7 +28,8 @@ namespace SceneUtil
|
||||||
{
|
{
|
||||||
FFP,
|
FFP,
|
||||||
SingleUBO,
|
SingleUBO,
|
||||||
PerObjectUniform
|
PerObjectUniform,
|
||||||
|
Undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
void configureStateSetSunOverride(LightingMethod method, const osg::Light* light, osg::StateSet* stateset, int mode = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
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
|
class LightManager : public osg::Group
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static bool isValidLightingModelString(const std::string& value);
|
static bool isValidLightingModelString(const std::string& value);
|
||||||
|
static LightingMethod getLightingMethodFromString(const std::string& value);
|
||||||
|
|
||||||
enum class UniformKey
|
enum class UniformKey
|
||||||
{
|
{
|
||||||
|
@ -175,10 +177,13 @@ namespace SceneUtil
|
||||||
std::map<std::string, std::string> getLightDefines() const;
|
std::map<std::string, std::string> getLightDefines() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class LightManagerStateAttribute;
|
friend class LightManagerStateAttribute;
|
||||||
friend class LightManagerCullCallback;
|
friend class LightManagerCullCallback;
|
||||||
|
|
||||||
|
void initFFP(int targetLights);
|
||||||
|
void initPerObjectUniform(int targetLights);
|
||||||
|
void initSingleUBO(int targetLights);
|
||||||
|
|
||||||
void setLightingMethod(LightingMethod method);
|
void setLightingMethod(LightingMethod method);
|
||||||
void setMaxLights(int value);
|
void setMaxLights(int value);
|
||||||
|
|
||||||
|
@ -221,6 +226,8 @@ namespace SceneUtil
|
||||||
int mMaxLights;
|
int mMaxLights;
|
||||||
|
|
||||||
static constexpr auto mFFPMaxLights = 8;
|
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
|
/// To receive lighting, objects must be decorated by a LightListCallback. Light list callbacks must be added via
|
||||||
|
@ -260,6 +267,7 @@ namespace SceneUtil
|
||||||
LightManager::LightList mLightList;
|
LightManager::LightList mLightList;
|
||||||
std::set<SceneUtil::LightSource*> mIgnoredLightSources;
|
std::set<SceneUtil::LightSource*> mIgnoredLightSources;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
#include <components/sceneutil/lightmanager.hpp>
|
#include <components/sceneutil/lightmanager.hpp>
|
||||||
#include <components/resource/scenemanager.hpp>
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
|
|
@ -152,32 +152,51 @@ lighting method
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
:Type: string
|
:Type: string
|
||||||
:Range: legacy|default|experimental
|
:Range: legacy|shaders compatibility|shaders
|
||||||
:Default: default
|
: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.
|
'shaders compatibility' removes the light limit via :ref:`max lights` and
|
||||||
This mode also enables vertex lighting on groundcover, which is otherwise completely disabled with 'legacy'.
|
follows a modifed attenuation formula which can drastically reduce light popping
|
||||||
It is recommended to use this mode with older hardware, as the technique ensures a range of compatibility equal to that of 'legacy'.
|
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
|
light bounds multiplier
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
:Type: float
|
:Type: float
|
||||||
:Range: 0.0-10.0
|
: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.
|
Controls the bounding sphere radius of point lights, which is used to determine
|
||||||
Note, this has no direct effect on the overall illumination of lights.
|
if an object should receive lighting from a particular light source. Note, this
|
||||||
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.
|
has no direct effect on the overall illumination of lights. Larger multipliers
|
||||||
This especially helps with abrupt light popping with handheld light sources such as torches and lanterns.
|
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
|
maximum light distance
|
||||||
----------------------
|
----------------------
|
||||||
|
@ -186,9 +205,11 @@ maximum light distance
|
||||||
:Range: The whole range of 32-bit floating point
|
:Range: The whole range of 32-bit floating point
|
||||||
:Default: 8192
|
:Default: 8192
|
||||||
|
|
||||||
The maximum distance from the camera that lights will be illuminated, applies to both interiors and exteriors.
|
The maximum distance from the camera that lights will be illuminated, applies to
|
||||||
A lower distance will improve performance.
|
both interiors and exteriors. A lower distance will improve performance. Set
|
||||||
Set this to a non-positive value to disable fading.
|
this to a non-positive value to disable fading.
|
||||||
|
|
||||||
|
This setting has no effect if :ref:`lighting method` is 'legacy'.
|
||||||
|
|
||||||
light fade start
|
light fade start
|
||||||
----------------
|
----------------
|
||||||
|
@ -199,18 +220,23 @@ light fade start
|
||||||
|
|
||||||
The fraction of the maximum distance at which lights will begin to fade away.
|
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.
|
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
|
max lights
|
||||||
----------
|
----------
|
||||||
|
|
||||||
:Type: integer
|
:Type: integer
|
||||||
:Range: >=2
|
:Range: >=2
|
||||||
:Default: 16
|
:Default: 8
|
||||||
|
|
||||||
Sets the maximum number of lights that each object can receive lighting from.
|
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
|
||||||
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.
|
: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
|
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.
|
# This makes fogging independent from the viewing angle. Shaders will be used to render all objects.
|
||||||
radial fog = false
|
radial fog = false
|
||||||
|
|
||||||
# Internal handling of lights, values are 'legacy', 'default', 'experimental'
|
# Internal handling of lights, ignored if 'force shaders' is off. "legacy"
|
||||||
lighting method = experimental
|
# 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
|
# Sets the bounding sphere multiplier of light sources, which are used to
|
||||||
# receive lighting. Higher values will allow for smoother transitions of light sources, but may have a performance cost and
|
# determine if an object should receive lighting. Higher values will allow for
|
||||||
# requires a higher number of 'max lights' set. It is recommended to keep this at 1.0 with 'legacy' lighting enabled.
|
# smoother transitions of light sources, but may have a performance cost and
|
||||||
light bounds multiplier = 1.0
|
# 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
|
maximum light distance = 8192
|
||||||
|
|
||||||
# Fraction of the maximum distance at which lights begin to gradually fade away.
|
# Fraction of the maximum distance at which lights begin to gradually fade away.
|
||||||
light fade start = 0.85
|
light fade start = 0.85
|
||||||
|
|
||||||
# Set maximum number of lights per object.
|
# Set maximum number of lights per object.
|
||||||
# Only used when 'lighting method' is not set to 'legacy'
|
# When 'lighting method' is set to 'legacy', this setting will have no effect.
|
||||||
max lights = 16
|
max lights = 8
|
||||||
|
|
||||||
# Convert the alpha test (cutout/punchthrough alpha) to alpha-to-coverage.
|
# 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.
|
# This allows MSAA to work with alpha-tested meshes, producing better-looking edges without pixelation.
|
||||||
|
|
|
@ -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)
|
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
|
#if !@ffpLighting
|
||||||
// This has a *considerable* performance uplift where GPU is a bottleneck
|
// 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
|
#endif
|
||||||
|
|
||||||
lightDir = normalize(lightDir);
|
lightPos = normalize(lightPos);
|
||||||
|
|
||||||
#if @ffpLighting
|
#if @ffpLighting
|
||||||
float illumination = clamp(1.0 / (getLight[lightIndex].constantAttenuation + getLight[lightIndex].linearAttenuation * lightDistance + getLight[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0);
|
float illumination = clamp(1.0 / (getLight[lightIndex].constantAttenuation + getLight[lightIndex].linearAttenuation * lightDistance + getLight[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0);
|
||||||
|
@ -128,7 +128,7 @@ void perLightPoint(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec
|
||||||
ambientOut = getLight[lightIndex].ambient.xyz * illumination;
|
ambientOut = getLight[lightIndex].ambient.xyz * illumination;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float lambert = dot(viewNormal.xyz, lightDir) * illumination;
|
float lambert = dot(viewNormal.xyz, lightPos) * illumination;
|
||||||
|
|
||||||
#ifndef GROUNDCOVER
|
#ifndef GROUNDCOVER
|
||||||
lambert = max(lambert, 0.0);
|
lambert = max(lambert, 0.0);
|
||||||
|
|
|
@ -151,6 +151,8 @@ uniform vec3 nodePosition;
|
||||||
|
|
||||||
uniform float rainIntensity;
|
uniform float rainIntensity;
|
||||||
|
|
||||||
|
#define PER_PIXEL_LIGHTING 0
|
||||||
|
|
||||||
#include "shadows_fragment.glsl"
|
#include "shadows_fragment.glsl"
|
||||||
#include "lighting.glsl"
|
#include "lighting.glsl"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue