mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 18:59:57 +00:00
Merge branch 'light_settings_tweak' into 'master'
Lighting patch Closes #5957 and #5959 See merge request OpenMW/openmw!752
This commit is contained in:
commit
d0883f9a0d
11 changed files with 280 additions and 219 deletions
|
@ -111,20 +111,17 @@ namespace
|
|||
max = MyGUI::utility::parseFloat(widget->getUserString(settingMax));
|
||||
}
|
||||
|
||||
const char* getLightingMethodCaptionText(SceneUtil::LightingMethod lightingMethod)
|
||||
void updateMaxLightsComboBox(MyGUI::ComboBox* box)
|
||||
{
|
||||
switch (lightingMethod)
|
||||
{
|
||||
case SceneUtil::LightingMethod::FFP:
|
||||
return "Emulates fixed function pipeline lighting, advanced light settings are disabled when this mode is active";
|
||||
case SceneUtil::LightingMethod::PerObjectUniform:
|
||||
return "Removes limit of 8 lights per object, fixes lighting attenuation, and enables groundcover lighting and light fade."
|
||||
"\n\nDesigned for compatibility across hardware, and is not meant for large max light counts.";
|
||||
case SceneUtil::LightingMethod::SingleUBO:
|
||||
return "Removes limit of 8 lights per object, fixes lighting attenuation, and enables groundcover lighting and light fade."
|
||||
"\n\nDesigned for more modern hardware and large max light counts.";
|
||||
}
|
||||
return "";
|
||||
constexpr int min = 8;
|
||||
constexpr int max = 32;
|
||||
constexpr int increment = 8;
|
||||
int maxLights = Settings::Manager::getInt("max lights", "Shaders");
|
||||
// show increments of 8 in dropdown
|
||||
if (maxLights >= min && maxLights <= max && !(maxLights % increment))
|
||||
box->setIndexSelected((maxLights / increment)-1);
|
||||
else
|
||||
box->setIndexSelected(MyGUI::ITEM_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,9 +232,9 @@ namespace MWGui
|
|||
getWidget(mControllerSwitch, "ControllerButton");
|
||||
getWidget(mWaterTextureSize, "WaterTextureSize");
|
||||
getWidget(mWaterReflectionDetail, "WaterReflectionDetail");
|
||||
getWidget(mLightingMethodText, "LightingMethodText");
|
||||
getWidget(mLightingMethodButton, "LightingMethodButton");
|
||||
getWidget(mLightsResetButton, "LightsResetButton");
|
||||
getWidget(mLightSettingOverlay, "LightSettingOverlay");
|
||||
getWidget(mMaxLights, "MaxLights");
|
||||
|
||||
#ifndef WIN32
|
||||
// hide gamma controls since it currently does not work under Linux
|
||||
|
@ -263,7 +260,9 @@ namespace MWGui
|
|||
mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged);
|
||||
mWaterReflectionDetail->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterReflectionDetailChanged);
|
||||
|
||||
mLightingMethodButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onLightingMethodButtonChanged);
|
||||
mLightsResetButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onLightsResetButtonClicked);
|
||||
mMaxLights->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onMaxLightsChanged);
|
||||
|
||||
mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked);
|
||||
mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked);
|
||||
|
@ -310,6 +309,8 @@ namespace MWGui
|
|||
waterReflectionDetail = std::min(5, std::max(0, waterReflectionDetail));
|
||||
mWaterReflectionDetail->setIndexSelected(waterReflectionDetail);
|
||||
|
||||
updateMaxLightsComboBox(mMaxLights);
|
||||
|
||||
mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video"));
|
||||
|
||||
mKeyboardSwitch->setStateSelected(true);
|
||||
|
@ -396,19 +397,50 @@ namespace MWGui
|
|||
apply();
|
||||
}
|
||||
|
||||
void SettingsWindow::onLightingMethodButtonChanged(MyGUI::ComboBox* _sender, size_t pos)
|
||||
{
|
||||
if (pos == MyGUI::ITEM_NONE)
|
||||
return;
|
||||
|
||||
std::string message = "This change requires a restart to take effect.";
|
||||
MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, {"#{sOK}"}, true);
|
||||
|
||||
Settings::Manager::setString("lighting method", "Shaders", _sender->getItemNameAt(pos));
|
||||
apply();
|
||||
}
|
||||
|
||||
void SettingsWindow::onMaxLightsChanged(MyGUI::ComboBox* _sender, size_t pos)
|
||||
{
|
||||
int count = 8 * (pos + 1);
|
||||
|
||||
Settings::Manager::setInt("max lights", "Shaders", count);
|
||||
apply();
|
||||
configureWidgets(mMainWidget, false);
|
||||
}
|
||||
|
||||
void SettingsWindow::onLightsResetButtonClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
std::vector<std::string> buttons = {"#{sYes}", "#{sNo}"};
|
||||
std::string message = "Resets to default values, would you like to continue?";
|
||||
std::string message = "Resets to default values, would you like to continue? Changes to lighting method will require a restart.";
|
||||
MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons, true);
|
||||
int selectedButton = MWBase::Environment::get().getWindowManager()->readPressedButton();
|
||||
if (selectedButton == 1 || selectedButton == -1)
|
||||
return;
|
||||
|
||||
constexpr std::array<const char*, 5> settings = {"light bounds multiplier", "maximum light distance", "light fade start", "minimum interior brightness", "max lights"};
|
||||
constexpr std::array<const char*, 6> settings = {
|
||||
"light bounds multiplier",
|
||||
"maximum light distance",
|
||||
"light fade start",
|
||||
"minimum interior brightness",
|
||||
"max lights",
|
||||
"lighting method",
|
||||
};
|
||||
for (const auto& setting : settings)
|
||||
Settings::Manager::setString(setting, "Shaders", Settings::Manager::mDefaultSettings[{"Shaders", setting}]);
|
||||
|
||||
mLightingMethodButton->setIndexSelected(mLightingMethodButton->findItemIndexWith(Settings::Manager::mDefaultSettings[{"Shaders", "lighting method"}]));
|
||||
updateMaxLightsComboBox(mMaxLights);
|
||||
|
||||
apply();
|
||||
configureWidgets(mMainWidget, false);
|
||||
}
|
||||
|
@ -614,20 +646,25 @@ namespace MWGui
|
|||
void SettingsWindow::updateLightSettings()
|
||||
{
|
||||
auto lightingMethod = MWBase::Environment::get().getResourceSystem()->getSceneManager()->getLightingMethod();
|
||||
mLightingMethodText->setCaption(SceneUtil::LightManager::getLightingMethodString(lightingMethod));
|
||||
std::string lightingMethodStr = SceneUtil::LightManager::getLightingMethodString(lightingMethod);
|
||||
|
||||
if (lightingMethod == SceneUtil::LightingMethod::FFP || !Settings::Manager::getBool("force shaders", "Shaders"))
|
||||
mLightingMethodButton->removeAllItems();
|
||||
|
||||
std::array<SceneUtil::LightingMethod, 3> methods = {
|
||||
SceneUtil::LightingMethod::FFP,
|
||||
SceneUtil::LightingMethod::PerObjectUniform,
|
||||
SceneUtil::LightingMethod::SingleUBO,
|
||||
};
|
||||
|
||||
for (const auto& method : methods)
|
||||
{
|
||||
MyGUI::Widget* parent = mLightSettingOverlay->getParent();
|
||||
mLightSettingOverlay->setEnabled(false);
|
||||
mLightSettingOverlay->setAlpha(0.8);
|
||||
parent->setUserString("ToolTipType", "Layout");
|
||||
parent->setUserString("ToolTipLayout", "TextToolTip");
|
||||
parent->setUserString("Caption_Text", "Unavailable with current settings.");
|
||||
parent->setEnabled(true);
|
||||
if (!MWBase::Environment::get().getResourceSystem()->getSceneManager()->isSupportedLightingMethod(method))
|
||||
continue;
|
||||
|
||||
mLightingMethodButton->addItem(SceneUtil::LightManager::getLightingMethodString(method));
|
||||
}
|
||||
|
||||
mLightingMethodText->setUserString("Caption_Text", getLightingMethodCaptionText(lightingMethod));
|
||||
mLightingMethodButton->setIndexSelected(mLightingMethodButton->findItemIndexWith(lightingMethodStr));
|
||||
}
|
||||
|
||||
void SettingsWindow::layoutControlsBox()
|
||||
|
|
|
@ -32,8 +32,8 @@ namespace MWGui
|
|||
MyGUI::ComboBox* mWaterTextureSize;
|
||||
MyGUI::ComboBox* mWaterReflectionDetail;
|
||||
|
||||
MyGUI::Widget* mLightSettingOverlay;
|
||||
MyGUI::TextBox* mLightingMethodText;
|
||||
MyGUI::ComboBox* mMaxLights;
|
||||
MyGUI::ComboBox* mLightingMethodButton;
|
||||
MyGUI::Button* mLightsResetButton;
|
||||
|
||||
// controls
|
||||
|
@ -56,7 +56,9 @@ namespace MWGui
|
|||
void onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos);
|
||||
void onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos);
|
||||
|
||||
void onLightingMethodButtonChanged(MyGUI::ComboBox* _sender, size_t pos);
|
||||
void onLightsResetButtonClicked(MyGUI::Widget* _sender);
|
||||
void onMaxLightsChanged(MyGUI::ComboBox* _sender, size_t pos);
|
||||
|
||||
void onRebindAction(MyGUI::Widget* _sender);
|
||||
void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel);
|
||||
|
|
|
@ -233,7 +233,16 @@ namespace MWRender
|
|||
float positionZ = std::cos(altitude);
|
||||
light->setPosition(osg::Vec4(positionX,positionY,positionZ, 0.0));
|
||||
light->setDiffuse(osg::Vec4(diffuseR,diffuseG,diffuseB,1));
|
||||
light->setAmbient(osg::Vec4(ambientR,ambientG,ambientB,1));
|
||||
osg::Vec4 ambientRGBA = osg::Vec4(ambientR,ambientG,ambientB,1);
|
||||
if (mResourceSystem->getSceneManager()->getForceShaders())
|
||||
{
|
||||
// When using shaders, we now skip the ambient sun calculation as this is the only place it's used.
|
||||
// Using the scene ambient will give identical results.
|
||||
lightmodel->setAmbientIntensity(ambientRGBA);
|
||||
light->setAmbient(osg::Vec4(0,0,0,1));
|
||||
}
|
||||
else
|
||||
light->setAmbient(ambientRGBA);
|
||||
light->setSpecular(osg::Vec4(0,0,0,0));
|
||||
light->setLightNum(0);
|
||||
light->setConstantAttenuation(1.f);
|
||||
|
|
|
@ -224,8 +224,7 @@ osg::ref_ptr<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, f
|
|||
SceneUtil::ShadowManager::disableShadowsForStateSet(stateset);
|
||||
|
||||
// override sun for local map
|
||||
auto lightingMethod = MWBase::Environment::get().getResourceSystem()->getSceneManager()->getLightingMethod();
|
||||
SceneUtil::configureStateSetSunOverride(lightingMethod, light, stateset);
|
||||
SceneUtil::configureStateSetSunOverride(static_cast<SceneUtil::LightManager*>(mSceneRoot.get()), light, stateset);
|
||||
|
||||
camera->addChild(lightSource);
|
||||
camera->setStateSet(stateset);
|
||||
|
|
|
@ -201,11 +201,15 @@ namespace MWRender
|
|||
, mFieldOfViewOverridden(false)
|
||||
, mFieldOfViewOverride(0.f)
|
||||
{
|
||||
auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString(Settings::Manager::getString("lighting method", "Shaders"));
|
||||
|
||||
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
|
||||
resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders");
|
||||
bool explicitlyForceShaders = Settings::Manager::getBool("force shaders", "Shaders");
|
||||
// Shadows and radial fog have problems with fixed-function mode
|
||||
bool forceShaders = Settings::Manager::getBool("radial fog", "Shaders") || explicitlyForceShaders || Settings::Manager::getBool("enable shadows", "Shadows");
|
||||
bool forceShaders = Settings::Manager::getBool("radial fog", "Shaders")
|
||||
|| Settings::Manager::getBool("force shaders", "Shaders")
|
||||
|| Settings::Manager::getBool("enable shadows", "Shadows")
|
||||
|| lightingMethod != SceneUtil::LightingMethod::FFP;
|
||||
resourceSystem->getSceneManager()->setForceShaders(forceShaders);
|
||||
// FIXME: calling dummy method because terrain needs to know whether lighting is clamped
|
||||
resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders"));
|
||||
|
@ -217,12 +221,11 @@ namespace MWRender
|
|||
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);
|
||||
|
||||
auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString(Settings::Manager::getString("lighting method", "Shaders"));
|
||||
// Let LightManager choose which backend to use based on our hint. For methods besides legacy lighting, this depends on support for various OpenGL extensions.
|
||||
osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager(!explicitlyForceShaders || lightingMethod == SceneUtil::LightingMethod::FFP);
|
||||
osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager(lightingMethod == SceneUtil::LightingMethod::FFP);
|
||||
resourceSystem->getSceneManager()->getShaderManager().setLightingMethod(sceneRoot->getLightingMethod());
|
||||
resourceSystem->getSceneManager()->setLightingMethod(sceneRoot->getLightingMethod());
|
||||
|
||||
resourceSystem->getSceneManager()->setSupportedLightingMethods(sceneRoot->getSupportedLightingMethods());
|
||||
mMinimumAmbientLuminance = std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f);
|
||||
|
||||
sceneRoot->setLightingMask(Mask_Lighting);
|
||||
|
@ -554,7 +557,7 @@ namespace MWRender
|
|||
// brighten ambient so it reaches the minimum threshold but no more, we want to mess with content data as least we can
|
||||
float targetBrightnessIncreaseFactor = mMinimumAmbientLuminance / relativeLuminance;
|
||||
if (ambient.r() == 0.f && ambient.g() == 0.f && ambient.b() == 0.f)
|
||||
ambient = osg::Vec4(targetBrightnessIncreaseFactor, targetBrightnessIncreaseFactor, targetBrightnessIncreaseFactor, ambient.a());
|
||||
ambient = osg::Vec4(mMinimumAmbientLuminance, mMinimumAmbientLuminance, mMinimumAmbientLuminance, ambient.a());
|
||||
else
|
||||
ambient *= targetBrightnessIncreaseFactor;
|
||||
}
|
||||
|
|
|
@ -305,6 +305,16 @@ namespace Resource
|
|||
mApplyLightingToEnvMaps = apply;
|
||||
}
|
||||
|
||||
void SceneManager::setSupportedLightingMethods(const SceneUtil::LightManager::SupportedMethods& supported)
|
||||
{
|
||||
mSupportedLightingMethods = supported;
|
||||
}
|
||||
|
||||
bool SceneManager::isSupportedLightingMethod(SceneUtil::LightingMethod method) const
|
||||
{
|
||||
return mSupportedLightingMethods[static_cast<int>(method)];
|
||||
}
|
||||
|
||||
void SceneManager::setLightingMethod(SceneUtil::LightingMethod method)
|
||||
{
|
||||
mLightingMethod = method;
|
||||
|
|
|
@ -107,6 +107,9 @@ namespace Resource
|
|||
|
||||
void setApplyLightingToEnvMaps(bool apply);
|
||||
|
||||
void setSupportedLightingMethods(const SceneUtil::LightManager::SupportedMethods& supported);
|
||||
bool isSupportedLightingMethod(SceneUtil::LightingMethod method) const;
|
||||
|
||||
void setLightingMethod(SceneUtil::LightingMethod method);
|
||||
SceneUtil::LightingMethod getLightingMethod() const;
|
||||
|
||||
|
@ -197,6 +200,7 @@ namespace Resource
|
|||
std::string mSpecularMapPattern;
|
||||
bool mApplyLightingToEnvMaps;
|
||||
SceneUtil::LightingMethod mLightingMethod;
|
||||
SceneUtil::LightManager::SupportedMethods mSupportedLightingMethods;
|
||||
bool mConvertAlphaTestToAlphaToCoverage;
|
||||
|
||||
osg::ref_ptr<MultiObjectCache> mInstanceCache;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include <osg/BufferObject>
|
||||
#include <osg/BufferIndexBinding>
|
||||
#include <osg/Endian>
|
||||
#include <osg/Version>
|
||||
#include <osg/ValueObject>
|
||||
|
||||
#include <osgUtil/CullVisitor>
|
||||
|
||||
|
@ -102,6 +104,7 @@ namespace SceneUtil
|
|||
, mEndian(osg::getCpuByteOrder())
|
||||
, mCount(count)
|
||||
, mStride(12)
|
||||
, mCachedSunPos(osg::Vec4())
|
||||
{
|
||||
mOffsets[Diffuse] = 0;
|
||||
mOffsets[Ambient] = 1;
|
||||
|
@ -118,6 +121,7 @@ namespace SceneUtil
|
|||
, mCount(copy.mCount)
|
||||
, mStride(copy.mStride)
|
||||
, mOffsets(copy.mOffsets)
|
||||
, mCachedSunPos(copy.mCachedSunPos)
|
||||
{}
|
||||
|
||||
void setDiffuse(int index, const osg::Vec4& value)
|
||||
|
@ -172,6 +176,17 @@ namespace SceneUtil
|
|||
return 3 * osg::Vec4::num_components * sizeof(GL_FLOAT) * sz;
|
||||
}
|
||||
|
||||
void setCachedSunPos(const osg::Vec4& pos)
|
||||
{
|
||||
mCachedSunPos = pos;
|
||||
}
|
||||
|
||||
void uploadCachedSunPos(const osg::Matrix& viewMat)
|
||||
{
|
||||
osg::Vec4 viewPos = mCachedSunPos * viewMat;
|
||||
std::memcpy(&(*mData)[getOffset(0, Position)], viewPos.ptr(), sizeof(osg::Vec4f));
|
||||
}
|
||||
|
||||
unsigned int asRGBA(const osg::Vec4& value) const
|
||||
{
|
||||
return mEndian == osg::BigEndian ? value.asABGR() : value.asRGBA();
|
||||
|
@ -187,6 +202,8 @@ namespace SceneUtil
|
|||
constexpr auto sizeofFloat = sizeof(GL_FLOAT);
|
||||
constexpr auto sizeofVec4 = sizeofFloat * osg::Vec4::num_components;
|
||||
|
||||
LightBuffer oldBuffer = LightBuffer(*this);
|
||||
|
||||
mOffsets[Diffuse] = offsetColors / sizeofFloat;
|
||||
mOffsets[Ambient] = mOffsets[Diffuse] + 1;
|
||||
mOffsets[Specular] = mOffsets[Diffuse] + 2;
|
||||
|
@ -196,7 +213,6 @@ namespace SceneUtil
|
|||
mStride = (offsetAttenuationRadius + sizeofVec4 + stride) / 4;
|
||||
|
||||
// Copy over previous buffers light data. Buffers populate before we know the layout.
|
||||
LightBuffer oldBuffer = LightBuffer(*this);
|
||||
mData->resize(size / sizeofFloat);
|
||||
for (int i = 0; i < oldBuffer.mCount; ++i)
|
||||
{
|
||||
|
@ -212,6 +228,7 @@ namespace SceneUtil
|
|||
int mCount;
|
||||
int mStride;
|
||||
std::array<std::size_t, 6> mOffsets;
|
||||
osg::Vec4 mCachedSunPos;
|
||||
};
|
||||
|
||||
class LightStateCache
|
||||
|
@ -229,8 +246,9 @@ namespace SceneUtil
|
|||
return &cacheVector[contextid];
|
||||
}
|
||||
|
||||
void configureStateSetSunOverride(LightingMethod method, const osg::Light* light, osg::StateSet* stateset, int mode)
|
||||
void configureStateSetSunOverride(LightManager* lightManager, const osg::Light* light, osg::StateSet* stateset, int mode)
|
||||
{
|
||||
auto method = lightManager->getLightingMethod();
|
||||
switch (method)
|
||||
{
|
||||
case LightingMethod::FFP:
|
||||
|
@ -244,12 +262,15 @@ namespace SceneUtil
|
|||
configureAmbient(lightMat, light->getAmbient());
|
||||
configureDiffuse(lightMat, light->getDiffuse());
|
||||
configureSpecular(lightMat, light->getSpecular());
|
||||
stateset->addUniform(new osg::Uniform("LightBuffer", lightMat), mode);
|
||||
|
||||
osg::ref_ptr<osg::Uniform> uni = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "LightBuffer", lightManager->getMaxLights());
|
||||
uni->setElement(0, lightMat);
|
||||
stateset->addUniform(uni, mode);
|
||||
break;
|
||||
}
|
||||
case LightingMethod::SingleUBO:
|
||||
{
|
||||
osg::ref_ptr<LightBuffer> buffer = new LightBuffer(1);
|
||||
osg::ref_ptr<LightBuffer> buffer = new LightBuffer(lightManager->getMaxLightsInScene());
|
||||
|
||||
buffer->setDiffuse(0, light->getDiffuse());
|
||||
buffer->setAmbient(0, light->getAmbient());
|
||||
|
@ -258,8 +279,11 @@ namespace SceneUtil
|
|||
|
||||
osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject;
|
||||
buffer->getData()->setBufferObject(ubo);
|
||||
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(static_cast<int>(Shader::UBOBinding::LightBuffer), buffer->getData().get(), 0, buffer->getData()->getTotalDataSize());
|
||||
|
||||
#if OSG_VERSION_GREATER_OR_EQUAL(3,5,7)
|
||||
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(static_cast<int>(Shader::UBOBinding::LightBuffer), buffer->getData(), 0, buffer->getData()->getTotalDataSize());
|
||||
#else
|
||||
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(static_cast<int>(Shader::UBOBinding::LightBuffer), ubo, 0, buffer->getData()->getTotalDataSize());
|
||||
#endif
|
||||
stateset->setAttributeAndModes(ubb, mode);
|
||||
|
||||
break;
|
||||
|
@ -433,6 +457,11 @@ namespace SceneUtil
|
|||
|
||||
lightUniform->setElement(i+1, lightMat);
|
||||
}
|
||||
|
||||
auto sun = mLightManager->getSunlightBuffer(state.getFrameStamp()->getFrameNumber());
|
||||
configurePosition(sun, osg::Vec4(sun(0,0), sun(0,1), sun(0,2), 0.0) * state.getInitialViewMatrix());
|
||||
lightUniform->setElement(0, sun);
|
||||
|
||||
lightUniform->dirty();
|
||||
}
|
||||
|
||||
|
@ -618,7 +647,6 @@ namespace SceneUtil
|
|||
void operator()(osg::Node* node, osg::NodeVisitor* nv) override
|
||||
{
|
||||
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
|
||||
bool pop = false;
|
||||
|
||||
if (mLastFrameNumber != cv->getTraversalNumber())
|
||||
{
|
||||
|
@ -628,18 +656,24 @@ namespace SceneUtil
|
|||
{
|
||||
auto stateset = mLightManager->getStateSet();
|
||||
auto bo = mLightManager->getLightBuffer(mLastFrameNumber);
|
||||
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(static_cast<int>(Shader::UBOBinding::LightBuffer), bo->getData().get(), 0, bo->getData()->getTotalDataSize());
|
||||
stateset->setAttributeAndModes(ubb.get(), osg::StateAttribute::ON);
|
||||
|
||||
#if OSG_VERSION_GREATER_OR_EQUAL(3,5,7)
|
||||
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(static_cast<int>(Shader::UBOBinding::LightBuffer), bo->getData(), 0, bo->getData()->getTotalDataSize());
|
||||
#else
|
||||
osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(static_cast<int>(Shader::UBOBinding::LightBuffer), bo->getData()->getBufferObject(), 0, bo->getData()->getTotalDataSize());
|
||||
#endif
|
||||
stateset->setAttributeAndModes(ubb, osg::StateAttribute::ON);
|
||||
}
|
||||
|
||||
auto sun = mLightManager->getSunlight();
|
||||
|
||||
if (sun)
|
||||
{
|
||||
// we must defer uploading the transformation to view-space position to deal with different cameras (e.g. reflection RTT).
|
||||
if (mLightManager->getLightingMethod() == LightingMethod::PerObjectUniform)
|
||||
{
|
||||
osg::Matrixf lightMat;
|
||||
configurePosition(lightMat, sun->getPosition() * (*cv->getCurrentRenderStage()->getInitialViewMatrix()));
|
||||
configurePosition(lightMat, sun->getPosition());
|
||||
configureAmbient(lightMat, sun->getAmbient());
|
||||
configureDiffuse(lightMat, sun->getDiffuse());
|
||||
configureSpecular(lightMat, sun->getSpecular());
|
||||
|
@ -649,33 +683,15 @@ namespace SceneUtil
|
|||
{
|
||||
auto buf = mLightManager->getLightBuffer(mLastFrameNumber);
|
||||
|
||||
buf->setPosition(0, sun->getPosition() * (*cv->getCurrentRenderStage()->getInitialViewMatrix()));
|
||||
buf->setCachedSunPos(sun->getPosition());
|
||||
buf->setAmbient(0, sun->getAmbient());
|
||||
buf->setDiffuse(0, sun->getDiffuse());
|
||||
buf->setSpecular(0, sun->getSpecular());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isReflectionCamera(cv->getCurrentCamera()))
|
||||
{
|
||||
auto sun = mLightManager->getSunlight();
|
||||
if (sun)
|
||||
{
|
||||
osg::Vec4 originalPos = sun->getPosition();
|
||||
sun->setPosition(originalPos * (*cv->getCurrentRenderStage()->getInitialViewMatrix()));
|
||||
|
||||
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
|
||||
configureStateSetSunOverride(mLightManager->getLightingMethod(), sun, stateset);
|
||||
|
||||
sun->setPosition(originalPos);
|
||||
cv->pushStateSet(stateset);
|
||||
pop = true;
|
||||
}
|
||||
}
|
||||
|
||||
traverse(node, nv);
|
||||
if (pop)
|
||||
cv->popStateSet();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -692,6 +708,7 @@ namespace SceneUtil
|
|||
LightManagerStateAttribute(LightManager* lightManager)
|
||||
: mLightManager(lightManager)
|
||||
, mDummyProgram(new osg::Program)
|
||||
, mInitLayout(false)
|
||||
{
|
||||
static const std::string dummyVertSource = generateDummyShader(mLightManager->getMaxLightsInScene());
|
||||
|
||||
|
@ -741,8 +758,7 @@ namespace SceneUtil
|
|||
|
||||
void apply(osg::State& state) const override
|
||||
{
|
||||
static bool init = false;
|
||||
if (!init)
|
||||
if (!mInitLayout)
|
||||
{
|
||||
auto handle = mDummyProgram->getPCP(state)->getHandle();
|
||||
auto* ext = state.get<osg::GLExtensions>();
|
||||
|
@ -754,14 +770,12 @@ namespace SceneUtil
|
|||
if (activeUniformBlocks > 0)
|
||||
{
|
||||
initSharedLayout(ext, handle);
|
||||
init = true;
|
||||
mInitLayout = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLightManager->getLightBuffer(state.getFrameStamp()->getFrameNumber())->uploadCachedSunPos(state.getInitialViewMatrix());
|
||||
mLightManager->getLightBuffer(state.getFrameStamp()->getFrameNumber())->dirty();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
@ -792,36 +806,7 @@ namespace SceneUtil
|
|||
|
||||
LightManager* mLightManager;
|
||||
osg::ref_ptr<osg::Program> mDummyProgram;
|
||||
};
|
||||
|
||||
class LightManagerStateAttributePerObjectUniform : public osg::StateAttribute
|
||||
{
|
||||
public:
|
||||
LightManagerStateAttributePerObjectUniform()
|
||||
: mLightManager(nullptr) {}
|
||||
|
||||
LightManagerStateAttributePerObjectUniform(LightManager* lightManager)
|
||||
: mLightManager(lightManager)
|
||||
{
|
||||
}
|
||||
|
||||
LightManagerStateAttributePerObjectUniform(const LightManagerStateAttributePerObjectUniform& copy, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY)
|
||||
: osg::StateAttribute(copy,copyop), mLightManager(copy.mLightManager) {}
|
||||
|
||||
int compare(const StateAttribute &sa) const override
|
||||
{
|
||||
throw std::runtime_error("LightManagerStateAttributePerObjectUniform::compare: unimplemented");
|
||||
}
|
||||
|
||||
META_StateAttribute(NifOsg, LightManagerStateAttributePerObjectUniform, osg::StateAttribute::LIGHT)
|
||||
|
||||
void apply(osg::State& state) const override
|
||||
{
|
||||
mLightManager->getStateSet()->getUniform("LightBuffer")->setElement(0, mLightManager->getSunlightBuffer(state.getFrameStamp()->getFrameNumber()));
|
||||
}
|
||||
|
||||
private:
|
||||
LightManager* mLightManager;
|
||||
mutable bool mInitLayout;
|
||||
};
|
||||
|
||||
const std::unordered_map<std::string, LightingMethod> LightManager::mLightingMethodSettingMap = {
|
||||
|
@ -857,6 +842,14 @@ namespace SceneUtil
|
|||
, mPointLightFadeEnd(0.f)
|
||||
, mPointLightFadeStart(0.f)
|
||||
{
|
||||
osg::GLExtensions* exts = osg::GLExtensions::Get(0, false);
|
||||
bool supportsUBO = exts && exts->isUniformBufferObjectSupported;
|
||||
bool supportsGPU4 = exts && exts->isGpuShader4Supported;
|
||||
|
||||
mSupported[static_cast<int>(LightingMethod::FFP)] = true;
|
||||
mSupported[static_cast<int>(LightingMethod::PerObjectUniform)] = true;
|
||||
mSupported[static_cast<int>(LightingMethod::SingleUBO)] = supportsUBO && supportsGPU4;
|
||||
|
||||
setUpdateCallback(new LightManagerUpdateCallback);
|
||||
|
||||
if (ffp)
|
||||
|
@ -870,10 +863,6 @@ namespace SceneUtil
|
|||
|
||||
updateSettings();
|
||||
|
||||
osg::GLExtensions* exts = osg::GLExtensions::Get(0, false);
|
||||
bool supportsUBO = exts && exts->isUniformBufferObjectSupported;
|
||||
bool supportsGPU4 = exts && exts->isGpuShader4Supported;
|
||||
|
||||
static bool hasLoggedWarnings = false;
|
||||
|
||||
if (lightingMethod == LightingMethod::SingleUBO && !hasLoggedWarnings)
|
||||
|
@ -1046,7 +1035,8 @@ namespace SceneUtil
|
|||
setLightingMethod(LightingMethod::PerObjectUniform);
|
||||
setMaxLights(std::clamp(targetLights, mMaxLightsLowerLimit, mMaxLightsUpperLimit));
|
||||
|
||||
stateset->setAttributeAndModes(new LightManagerStateAttributePerObjectUniform(this), osg::StateAttribute::ON);
|
||||
// ensures sunlight element in our uniform array is updated when there are no point lights in scene
|
||||
stateset->setAttributeAndModes(new LightStateAttributePerObjectUniform({}, this), osg::StateAttribute::ON);
|
||||
stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "LightBuffer", getMaxLights()));
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <array>
|
||||
|
||||
#include <osg/Light>
|
||||
|
||||
|
@ -24,7 +25,7 @@ namespace osgUtil
|
|||
namespace SceneUtil
|
||||
{
|
||||
class LightBuffer;
|
||||
class StateSetGenerator;
|
||||
struct StateSetGenerator;
|
||||
|
||||
enum class LightingMethod
|
||||
{
|
||||
|
@ -33,8 +34,6 @@ namespace SceneUtil
|
|||
SingleUBO,
|
||||
};
|
||||
|
||||
void configureStateSetSunOverride(LightingMethod method, const osg::Light* light, osg::StateSet* stateset, int mode = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||
|
||||
/// LightSource managed by a LightManager.
|
||||
/// @par Typically used for point lights. Spot lights are not supported yet. Directional lights affect the whole scene
|
||||
/// so do not need to be managed by a LightManager - so for directional lights use a plain osg::LightSource instead.
|
||||
|
@ -130,6 +129,7 @@ namespace SceneUtil
|
|||
};
|
||||
|
||||
using LightList = std::vector<const LightSourceViewBound*>;
|
||||
using SupportedMethods = std::array<bool, 3>;
|
||||
|
||||
META_Node(SceneUtil, LightManager)
|
||||
|
||||
|
@ -178,6 +178,8 @@ namespace SceneUtil
|
|||
osg::Matrixf getSunlightBuffer(size_t frameNum) const { return mSunlightBuffers[frameNum%2]; }
|
||||
void setSunlightBuffer(const osg::Matrixf& buffer, size_t frameNum) { mSunlightBuffers[frameNum%2] = buffer; }
|
||||
|
||||
SupportedMethods getSupportedLightingMethods() { return mSupported; }
|
||||
|
||||
std::map<std::string, std::string> getLightDefines() const;
|
||||
|
||||
void processChangedSettings(const Settings::CategorySettingVector& changed);
|
||||
|
@ -232,6 +234,8 @@ namespace SceneUtil
|
|||
|
||||
int mMaxLights;
|
||||
|
||||
SupportedMethods mSupported;
|
||||
|
||||
static constexpr auto mMaxLightsLowerLimit = 2;
|
||||
static constexpr auto mMaxLightsUpperLimit = 64;
|
||||
static constexpr auto mFFPMaxLights = 8;
|
||||
|
@ -277,6 +281,8 @@ namespace SceneUtil
|
|||
std::set<SceneUtil::LightSource*> mIgnoredLightSources;
|
||||
};
|
||||
|
||||
void configureStateSetSunOverride(LightManager* lightManager, const osg::Light* light, osg::StateSet* stateset, int mode = osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -174,12 +174,14 @@ 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.
|
||||
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'.
|
||||
Note that the rendering will act as if you have 'force shaders' option enabled
|
||||
when not set to 'legacy'. This means that shaders will be used to render all objects and
|
||||
the terrain.
|
||||
|
||||
light bounds multiplier
|
||||
-----------------------
|
||||
|
|
|
@ -460,15 +460,14 @@
|
|||
|
||||
<Widget type="TabItem" skin="" position="4 32 360 308">
|
||||
<Property key="Caption" value=" Lights "/>
|
||||
<Widget type="Widget" skin="" position="0 0 360 315" align="Stretch">
|
||||
<Widget type="Widget" skin="" position="0 0 360 315" align="Stretch" name="LightSettingOverlay">
|
||||
<!-- Lighting Method -->
|
||||
<Widget type="TextBox" skin="NormalText" position="0 4 170 18" align="Left Top">
|
||||
<Property key="Caption" value="Lighting Method:"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="0 28 170 18" align="Left Top" name="LightingMethodText">
|
||||
<UserString key="ToolTipType" value="Layout"/>
|
||||
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||
<Widget type="ComboBox" skin="MW_ComboBox" position="0 28 170 24" align="Left Top" name="LightingMethodButton">
|
||||
<Property key="AddItem" value="legacy"/>
|
||||
<Property key="AddItem" value="shaders compatibility"/>
|
||||
<Property key="AddItem" value="shaders"/>
|
||||
</Widget>
|
||||
<!-- Max Lights -->
|
||||
<Widget type="TextBox" skin="NormalText" position="178 4 160 18" align="Left Top" name="MaxLightsText">
|
||||
|
@ -476,17 +475,19 @@
|
|||
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||
<UserString key="Caption_Text" value="Default: 8\nMaximum number of lights per object.\n\nA low number near default will cause light popping similar to what you would see with legacy lighting."/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="178 30 160 18" align="Right Top HStretch" name="MaxLightsSlider">
|
||||
<Property key="Range" value="24"/>
|
||||
<Property key="Page" value="1"/>
|
||||
<Widget type="ScrollBar" skin="" position="0 0 0 0">
|
||||
<UserString key="SettingType" value="Slider"/>
|
||||
<UserString key="SettingMin" value="4"/>
|
||||
<UserString key="SettingMax" value="32"/>
|
||||
<UserString key="SettingCategory" value="Shaders"/>
|
||||
<UserString key="SettingName" value="max lights"/>
|
||||
<UserString key="SettingValueType" value="Integer"/>
|
||||
<UserString key="SettingLabelWidget" value="MaxLightsText"/>
|
||||
<UserString key="SettingLabelCaption" value="Max Lights (%s)"/>
|
||||
<UserString key="SettingLabelCaption" value="Max Lights: (%s)"/>
|
||||
</Widget>
|
||||
<Widget type="ComboBox" skin="MW_ComboBox" position="178 28 170 24" align="Left Top" name="MaxLights">
|
||||
<Property key="AddItem" value="8"/>
|
||||
<Property key="AddItem" value="16"/>
|
||||
<Property key="AddItem" value="24"/>
|
||||
<Property key="AddItem" value="32"/>
|
||||
</Widget>
|
||||
<Widget type="ImageBox" skin="MW_HLine" position="0 54 360 18" align="Top HStretch"/>
|
||||
<!-- Light Fade Start -->
|
||||
|
@ -511,7 +512,7 @@
|
|||
<Widget type="TextBox" skin="NormalText" position="0 128 352 18" align="Left Top" name="LightFadeMultiplierText">
|
||||
<UserString key="ToolTipType" value="Layout"/>
|
||||
<UserString key="ToolTipLayout" value="TextToolTip"/>
|
||||
<UserString key="Caption_Text" value="Default: 0.85\nFraction of maximum distance at which lights will start to fade.\n\nSet this to a low value for slower transitions or a high value of quicker transitions."/>
|
||||
<UserString key="Caption_Text" value="Default: 0.85\nFraction of maximum distance at which lights will start to fade.\n\nSet this to a low value for slower transitions or a high value for quicker transitions."/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="0 152 352 18" align="HStretch Top">
|
||||
<Property key="Range" value="10000"/>
|
||||
|
@ -563,8 +564,6 @@
|
|||
<Property key="Caption" value="Reset To Defaults"/>
|
||||
</Widget>
|
||||
</Widget>
|
||||
</Widget>
|
||||
</Widget>
|
||||
<!--
|
||||
<Widget type="TabItem" skin="" position="0 28 352 268">
|
||||
<Widget type="Widget" skin="" position="0 28 352 268">
|
||||
|
|
Loading…
Reference in a new issue