in-game settings, some require restart

pull/593/head
glassmancody.info 4 years ago
parent 3d713e8602
commit 71c30a31df

@ -6,6 +6,7 @@
#include <MyGUI_ScrollView.h> #include <MyGUI_ScrollView.h>
#include <MyGUI_Gui.h> #include <MyGUI_Gui.h>
#include <MyGUI_TabControl.h> #include <MyGUI_TabControl.h>
#include <MyGUI_TabItem.h>
#include <SDL_video.h> #include <SDL_video.h>
@ -17,6 +18,7 @@
#include <components/misc/constants.hpp> #include <components/misc/constants.hpp>
#include <components/widgets/sharedstatebutton.hpp> #include <components/widgets/sharedstatebutton.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/sceneutil/lightmanager.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -107,7 +109,7 @@ namespace
namespace MWGui namespace MWGui
{ {
void SettingsWindow::configureWidgets(MyGUI::Widget* widget) void SettingsWindow::configureWidgets(MyGUI::Widget* widget, bool init)
{ {
MyGUI::EnumeratorWidgetPtr widgets = widget->getEnumerator(); MyGUI::EnumeratorWidgetPtr widgets = widget->getEnumerator();
while (widgets.next()) while (widgets.next())
@ -121,7 +123,8 @@ namespace MWGui
getSettingCategory(current)) getSettingCategory(current))
? "#{sOn}" : "#{sOff}"; ? "#{sOn}" : "#{sOff}";
current->castType<MyGUI::Button>()->setCaptionWithReplacing(initialValue); current->castType<MyGUI::Button>()->setCaptionWithReplacing(initialValue);
current->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); if (init)
current->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
} }
if (type == sliderType) if (type == sliderType)
{ {
@ -141,6 +144,12 @@ namespace MWGui
ss << std::fixed << std::setprecision(2) << value/Constants::CellSizeInUnits; ss << std::fixed << std::setprecision(2) << value/Constants::CellSizeInUnits;
valueStr = ss.str(); valueStr = ss.str();
} }
else if (valueType == "Float")
{
std::stringstream ss;
ss << std::fixed << std::setprecision(2) << value;
valueStr = ss.str();
}
else else
valueStr = MyGUI::utility::toString(int(value)); valueStr = MyGUI::utility::toString(int(value));
@ -155,12 +164,13 @@ namespace MWGui
valueStr = MyGUI::utility::toString(value); valueStr = MyGUI::utility::toString(value);
scroll->setScrollPosition(value); scroll->setScrollPosition(value);
} }
scroll->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); if (init)
scroll->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition);
if (scroll->getVisible()) if (scroll->getVisible())
updateSliderLabel(scroll, valueStr); updateSliderLabel(scroll, valueStr);
} }
configureWidgets(current); configureWidgets(current, init);
} }
} }
@ -187,7 +197,7 @@ namespace MWGui
getWidget(unusedSlider, widgetName); getWidget(unusedSlider, widgetName);
unusedSlider->setVisible(false); unusedSlider->setVisible(false);
configureWidgets(mMainWidget); configureWidgets(mMainWidget, true);
setTitle("#{sOptions}"); setTitle("#{sOptions}");
@ -204,6 +214,9 @@ namespace MWGui
getWidget(mControllerSwitch, "ControllerButton"); getWidget(mControllerSwitch, "ControllerButton");
getWidget(mWaterTextureSize, "WaterTextureSize"); getWidget(mWaterTextureSize, "WaterTextureSize");
getWidget(mWaterReflectionDetail, "WaterReflectionDetail"); getWidget(mWaterReflectionDetail, "WaterReflectionDetail");
getWidget(mLightingMethodButton, "LightingMethodButton");
getWidget(mMaxLightsSlider, "MaxLightsSlider");
getWidget(mLightsResetButton, "LightsResetButton");
#ifndef WIN32 #ifndef WIN32
// hide gamma controls since it currently does not work under Linux // hide gamma controls since it currently does not work under Linux
@ -229,6 +242,9 @@ namespace MWGui
mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged);
mWaterReflectionDetail->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterReflectionDetailChanged); mWaterReflectionDetail->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterReflectionDetailChanged);
mLightingMethodButton->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onLightingMethodChanged);
mLightsResetButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onLightsResetButtonClicked);
mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked); mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked);
mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked); mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked);
@ -272,6 +288,21 @@ namespace MWGui
waterReflectionDetail = std::min(5, std::max(0, waterReflectionDetail)); waterReflectionDetail = std::min(5, std::max(0, waterReflectionDetail));
mWaterReflectionDetail->setIndexSelected(waterReflectionDetail); mWaterReflectionDetail->setIndexSelected(waterReflectionDetail);
auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString(Settings::Manager::getString("lighting method", "Shaders"));
switch (lightingMethod)
{
case SceneUtil::LightingMethod::Undefined:
case SceneUtil::LightingMethod::FFP:
mLightingMethodButton->setIndexSelected(0);
break;
case SceneUtil::LightingMethod::PerObjectUniform:
mLightingMethodButton->setIndexSelected(1);
break;
case SceneUtil::LightingMethod::SingleUBO:
mLightingMethodButton->setIndexSelected(2);
break;
}
mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video")); mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video"));
mKeyboardSwitch->setStateSelected(true); mKeyboardSwitch->setStateSelected(true);
@ -358,6 +389,49 @@ namespace MWGui
apply(); apply();
} }
void SettingsWindow::onLightsResetButtonClicked(MyGUI::Widget* _sender)
{
std::vector<std::string> buttons = {"#{sYes}", "#{sNo}"};
std::string message = "This will reset all lighting settings to default, some changes will require a restart. Would you like to continue?";
MWBase::Environment::get().getWindowManager()->interactiveMessageBox(message, buttons, true);
int selectedButton = MWBase::Environment::get().getWindowManager()->readPressedButton();
if (selectedButton == 1 || selectedButton == -1)
return;
Settings::Manager::setString("lighting method", "Shaders", "shaders compatibility");
Settings::Manager::setFloat("light bounds multiplier", "Shaders", 1.75);
Settings::Manager::setInt("maximum light distance", "Shaders", 8192);
Settings::Manager::setFloat("light fade start", "Shaders", 0.85);
Settings::Manager::setFloat("minimum interior brightness", "Shaders", 0.1);
Settings::Manager::setInt("max lights", "Shaders", 8);
mLightingMethodButton->setIndexSelected(1);
apply();
configureWidgets(mMainWidget, false);
}
void SettingsWindow::onLightingMethodChanged(MyGUI::ComboBox* _sender, size_t pos)
{
std::string setting;
auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString(_sender->getItemNameAt(pos));
switch (lightingMethod)
{
case SceneUtil::LightingMethod::FFP:
setting = "legacy";
break;
case SceneUtil::LightingMethod::Undefined:
case SceneUtil::LightingMethod::PerObjectUniform:
setting = "shaders compatibility";
break;
case SceneUtil::LightingMethod::SingleUBO:
setting = "shaders";
break;
}
Settings::Manager::setString("lighting method", "Shaders", setting);
apply();
}
void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender) void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender)
{ {
std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On"); std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On");
@ -460,6 +534,12 @@ namespace MWGui
ss << std::fixed << std::setprecision(2) << value/Constants::CellSizeInUnits; ss << std::fixed << std::setprecision(2) << value/Constants::CellSizeInUnits;
valueStr = ss.str(); valueStr = ss.str();
} }
else if (valueType == "Float")
{
std::stringstream ss;
ss << std::fixed << std::setprecision(2) << value;
valueStr = ss.str();
}
else else
valueStr = MyGUI::utility::toString(int(value)); valueStr = MyGUI::utility::toString(int(value));
} }

@ -35,6 +35,10 @@ namespace MWGui
MyGUI::ComboBox* mWaterTextureSize; MyGUI::ComboBox* mWaterTextureSize;
MyGUI::ComboBox* mWaterReflectionDetail; MyGUI::ComboBox* mWaterReflectionDetail;
MyGUI::ComboBox* mLightingMethodButton;
MyGUI::ScrollBar* mMaxLightsSlider;
MyGUI::Button* mLightsResetButton;
// controls // controls
MyGUI::ScrollView* mControlsBox; MyGUI::ScrollView* mControlsBox;
MyGUI::Button* mResetControlsButton; MyGUI::Button* mResetControlsButton;
@ -55,6 +59,9 @@ namespace MWGui
void onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); void onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos);
void onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos); void onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos);
void onLightsResetButtonClicked(MyGUI::Widget* _sender);
void onLightingMethodChanged(MyGUI::ComboBox* _sender, size_t pos);
void onRebindAction(MyGUI::Widget* _sender); void onRebindAction(MyGUI::Widget* _sender);
void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel); void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel);
void onResetDefaultBindings(MyGUI::Widget* _sender); void onResetDefaultBindings(MyGUI::Widget* _sender);
@ -66,7 +73,7 @@ namespace MWGui
void apply(); void apply();
void configureWidgets(MyGUI::Widget* widget); void configureWidgets(MyGUI::Widget* widget, bool init);
void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value); void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value);
void layoutControlsBox(); void layoutControlsBox();

@ -52,6 +52,7 @@
#include "../mwgui/loadingscreen.hpp" #include "../mwgui/loadingscreen.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwmechanics/actorutil.hpp"
#include "sky.hpp" #include "sky.hpp"
#include "effectmanager.hpp" #include "effectmanager.hpp"
@ -224,8 +225,7 @@ namespace MWRender
resourceSystem->getSceneManager()->getShaderManager().setLightingMethod(sceneRoot->getLightingMethod()); resourceSystem->getSceneManager()->getShaderManager().setLightingMethod(sceneRoot->getLightingMethod());
resourceSystem->getSceneManager()->setLightingMethod(sceneRoot->getLightingMethod()); resourceSystem->getSceneManager()->setLightingMethod(sceneRoot->getLightingMethod());
if (sceneRoot->getLightingMethod() != SceneUtil::LightingMethod::FFP) mMinimumAmbientLuminance = std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f);
mMinimumAmbientLuminance = std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f);
sceneRoot->setLightingMask(Mask_Lighting); sceneRoot->setLightingMask(Mask_Lighting);
mSceneRoot = sceneRoot; mSceneRoot = sceneRoot;
@ -1144,9 +1144,25 @@ namespace MWRender
else if (it->first == "General" && (it->second == "texture filter" || else if (it->first == "General" && (it->second == "texture filter" ||
it->second == "texture mipmap" || it->second == "texture mipmap" ||
it->second == "anisotropy")) it->second == "anisotropy"))
{
updateTextureFiltering(); updateTextureFiltering();
}
else if (it->first == "Water") else if (it->first == "Water")
{
mWater->processChangedSettings(changed); mWater->processChangedSettings(changed);
}
else if (it->first == "Shaders" && it->second == "minimum interior brightness")
{
mMinimumAmbientLuminance = std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f);
if (MWMechanics::getPlayer().getCell())
configureAmbient(MWMechanics::getPlayer().getCell()->getCell());
}
else if (it->first == "Shaders" && (it->second == "light bounds multiplier" ||
it->second == "maximum light distance" ||
it->second == "light fade start"))
{
static_cast<SceneUtil::LightManager*>(getLightRoot())->processChangedSettings(changed);
}
} }
} }

@ -10,8 +10,6 @@
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include <components/settings/settings.hpp>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
namespace namespace
@ -41,6 +39,43 @@ namespace
{ {
light->setUserValue("radius", value); light->setUserValue("radius", value);
} }
void configurePosition(osg::Matrixf& mat, const osg::Vec4& pos)
{
mat(0, 0) = pos.x();
mat(0, 1) = pos.y();
mat(0, 2) = pos.z();
}
void configureAmbient(osg::Matrixf& mat, const osg::Vec4& color)
{
mat(1, 0) = color.r();
mat(1, 1) = color.g();
mat(1, 2) = color.b();
}
void configureDiffuse(osg::Matrixf& mat, const osg::Vec4& color)
{
mat(2, 0) = color.r();
mat(2, 1) = color.g();
mat(2, 2) = color.b();
}
void configureSpecular(osg::Matrixf& mat, const osg::Vec4& color)
{
mat(3, 0) = color.r();
mat(3, 1) = color.g();
mat(3, 2) = color.b();
mat(3, 3) = color.a();
}
void configureAttenuation(osg::Matrixf& mat, float c, float l, float q, float r)
{
mat(0, 3) = c;
mat(1, 3) = l;
mat(2, 3) = q;
mat(3, 3) = r;
}
} }
namespace SceneUtil namespace SceneUtil
@ -206,11 +241,12 @@ namespace SceneUtil
} }
case LightingMethod::PerObjectUniform: case LightingMethod::PerObjectUniform:
{ {
stateset->addUniform(new osg::Uniform("LightBuffer[0].diffuse", light->getDiffuse()), mode); osg::Matrixf lightMat;
stateset->addUniform(new osg::Uniform("LightBuffer[0].ambient", light->getAmbient()), mode); configurePosition(lightMat, light->getPosition());
stateset->addUniform(new osg::Uniform("LightBuffer[0].specular", light->getSpecular()), mode); configureAmbient(lightMat, light->getAmbient());
stateset->addUniform(new osg::Uniform("LightBuffer[0].position", light->getPosition()), mode); configureDiffuse(lightMat, light->getDiffuse());
configureSpecular(lightMat, light->getSpecular());
stateset->addUniform(new osg::Uniform("LightBuffer", lightMat), mode);
break; break;
} }
case LightingMethod::SingleUBO: case LightingMethod::SingleUBO:
@ -381,14 +417,20 @@ namespace SceneUtil
void apply(osg::State &state) const override void apply(osg::State &state) const override
{ {
auto* lightUniform = mLightManager->getStateSet()->getUniform("LightBuffer");
for (size_t i = 0; i < mLights.size(); ++i) for (size_t i = 0; i < mLights.size(); ++i)
{ {
auto light = mLights[i]; auto light = mLights[i];
mLightManager->getLightUniform(i+1, LightManager::UniformKey::Diffuse)->set(light->getDiffuse()); osg::Matrixf lightMat;
mLightManager->getLightUniform(i+1, LightManager::UniformKey::Ambient)->set(light->getAmbient());
mLightManager->getLightUniform(i+1, LightManager::UniformKey::Attenuation)->set(osg::Vec4(light->getConstantAttenuation(), light->getLinearAttenuation(), light->getQuadraticAttenuation(), getLightRadius(light))); configurePosition(lightMat, light->getPosition() * state.getInitialViewMatrix());
mLightManager->getLightUniform(i+1, LightManager::UniformKey::Position)->set(light->getPosition() * state.getInitialViewMatrix()); configureAmbient(lightMat, light->getAmbient());
configureDiffuse(lightMat, light->getDiffuse());
configureAttenuation(lightMat, light->getConstantAttenuation(), light->getLinearAttenuation(), light->getQuadraticAttenuation(), getLightRadius(light));
lightUniform->setElement(i+1, lightMat);
} }
lightUniform->dirty();
} }
private: private:
@ -589,10 +631,12 @@ namespace SceneUtil
{ {
if (mLightManager->getLightingMethod() == LightingMethod::PerObjectUniform) if (mLightManager->getLightingMethod() == LightingMethod::PerObjectUniform)
{ {
mLightManager->getLightUniform(0, LightManager::UniformKey::Diffuse)->set(sun->getDiffuse()); osg::Matrixf lightMat;
mLightManager->getLightUniform(0, LightManager::UniformKey::Ambient)->set(sun->getAmbient()); configurePosition(lightMat, sun->getPosition() * (*cv->getCurrentRenderStage()->getInitialViewMatrix()));
mLightManager->getLightUniform(0, LightManager::UniformKey::Specular)->set(sun->getSpecular()); configureAmbient(lightMat, sun->getAmbient());
mLightManager->getLightUniform(0, LightManager::UniformKey::Position)->set(sun->getPosition() * (*cv->getCurrentRenderStage()->getInitialViewMatrix())); configureDiffuse(lightMat, sun->getDiffuse());
configureSpecular(lightMat, sun->getSpecular());
mLightManager->getStateSet()->getUniform("LightBuffer")->setElement(0, lightMat);
} }
else else
{ {
@ -760,14 +804,7 @@ namespace SceneUtil
lightingMethod = LightingMethod::PerObjectUniform; lightingMethod = LightingMethod::PerObjectUniform;
} }
mPointLightRadiusMultiplier = std::clamp(Settings::Manager::getFloat("light bounds multiplier", "Shaders"), 0.f, 10.f); updateSettings();
mPointLightFadeEnd = std::max(0.f, Settings::Manager::getFloat("maximum light distance", "Shaders"));
if (mPointLightFadeEnd > 0)
{
mPointLightFadeStart = std::clamp(Settings::Manager::getFloat("light fade start", "Shaders"), 0.f, 1.f);
mPointLightFadeStart = mPointLightFadeEnd * mPointLightFadeStart;
}
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;
@ -839,9 +876,6 @@ namespace SceneUtil
{ {
Shader::ShaderManager::DefineMap defines; Shader::ShaderManager::DefineMap defines;
bool ffp = usingFFP();
defines["ffpLighting"] = ffp ? "1" : "0";
defines["maxLights"] = std::to_string(getMaxLights()); defines["maxLights"] = std::to_string(getMaxLights());
defines["maxLightsInScene"] = std::to_string(getMaxLightsInScene()); defines["maxLightsInScene"] = std::to_string(getMaxLightsInScene());
defines["lightingModel"] = std::to_string(static_cast<int>(mLightingMethod)); defines["lightingModel"] = std::to_string(static_cast<int>(mLightingMethod));
@ -852,6 +886,26 @@ namespace SceneUtil
return defines; return defines;
} }
void LightManager::processChangedSettings(const Settings::CategorySettingVector& changed)
{
updateSettings();
}
void LightManager::updateSettings()
{
if (getLightingMethod() == LightingMethod::FFP)
return;
mPointLightRadiusMultiplier = std::clamp(Settings::Manager::getFloat("light bounds multiplier", "Shaders"), 0.f, 5.f);
mPointLightFadeEnd = std::max(0.f, Settings::Manager::getFloat("maximum light distance", "Shaders"));
if (mPointLightFadeEnd > 0)
{
mPointLightFadeStart = std::clamp(Settings::Manager::getFloat("light fade start", "Shaders"), 0.f, 1.f);
mPointLightFadeStart = mPointLightFadeEnd * mPointLightFadeStart;
}
}
void LightManager::initFFP(int targetLights) void LightManager::initFFP(int targetLights)
{ {
setLightingMethod(LightingMethod::FFP); setLightingMethod(LightingMethod::FFP);
@ -866,38 +920,15 @@ namespace SceneUtil
auto* stateset = getOrCreateStateSet(); auto* stateset = getOrCreateStateSet();
setLightingMethod(LightingMethod::PerObjectUniform); setLightingMethod(LightingMethod::PerObjectUniform);
setMaxLights(std::max(2, targetLights)); setMaxLights(std::clamp(targetLights, 2, 64));
mLightUniforms.resize(getMaxLights()+1); stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "LightBuffer", 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) void LightManager::initSingleUBO(int targetLights)
{ {
setLightingMethod(LightingMethod::SingleUBO); setLightingMethod(LightingMethod::SingleUBO);
setMaxLights(std::clamp(targetLights, 2, getMaxLightsInScene() / 2)); setMaxLights(std::clamp(targetLights, 2, 64));
for (int i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i)
{ {
@ -912,7 +943,6 @@ namespace SceneUtil
getOrCreateStateSet()->setAttribute(new LightManagerStateAttribute(this), osg::StateAttribute::ON); getOrCreateStateSet()->setAttribute(new LightManagerStateAttribute(this), osg::StateAttribute::ON);
} }
void LightManager::setLightingMethod(LightingMethod method) void LightManager::setLightingMethod(LightingMethod method)
{ {
mLightingMethod = method; mLightingMethod = method;

@ -14,6 +14,8 @@
#include <components/shader/shadermanager.hpp> #include <components/shader/shadermanager.hpp>
#include <components/settings/settings.hpp>
namespace osgUtil namespace osgUtil
{ {
class CullVisitor; class CullVisitor;
@ -172,10 +174,10 @@ namespace SceneUtil
auto& getLightBuffer(size_t frameNum) { return mLightBuffers[frameNum%2]; } auto& getLightBuffer(size_t frameNum) { return mLightBuffers[frameNum%2]; }
auto& getLightUniform(int index, UniformKey key) { return mLightUniforms[index][key]; }
std::map<std::string, std::string> getLightDefines() const; std::map<std::string, std::string> getLightDefines() const;
void processChangedSettings(const Settings::CategorySettingVector& changed);
private: private:
friend class LightManagerStateAttribute; friend class LightManagerStateAttribute;
friend class LightManagerCullCallback; friend class LightManagerCullCallback;
@ -184,6 +186,8 @@ namespace SceneUtil
void initPerObjectUniform(int targetLights); void initPerObjectUniform(int targetLights);
void initSingleUBO(int targetLights); void initSingleUBO(int targetLights);
void updateSettings();
void setLightingMethod(LightingMethod method); void setLightingMethod(LightingMethod method);
void setMaxLights(int value); void setMaxLights(int value);
@ -212,9 +216,6 @@ namespace SceneUtil
using LightIndexMap = std::unordered_map<int, int>; using LightIndexMap = std::unordered_map<int, int>;
LightIndexMap mLightIndexMaps[2]; LightIndexMap mLightIndexMaps[2];
using UniformMap = std::vector<std::unordered_map<UniformKey, osg::ref_ptr<osg::Uniform>>>;
UniformMap mLightUniforms;
std::unique_ptr<StateSetGenerator> mStateSetGenerator; std::unique_ptr<StateSetGenerator> mStateSetGenerator;
LightingMethod mLightingMethod; LightingMethod mLightingMethod;

@ -185,7 +185,7 @@ light bounds multiplier
----------------------- -----------------------
:Type: float :Type: float
:Range: 0.0-10.0 :Range: 0.0-5.0
:Default: 1.75 :Default: 1.75
Controls the bounding sphere radius of point lights, which is used to determine Controls the bounding sphere radius of point lights, which is used to determine
@ -228,7 +228,7 @@ max lights
---------- ----------
:Type: integer :Type: integer
:Range: >=2 :Range: 2-64
:Default: 8 :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.

@ -456,6 +456,95 @@
</Widget> </Widget>
</Widget> </Widget>
</Widget>
<Widget type="TabItem" skin="" position="4 32 360 308">
<Property key="Caption" value=" Lights "/>
<!-- Lighting Method -->
<Widget type="TextBox" skin="NormalText" position="0 4 160 18" align="Left Top">
<Property key="Caption" value="*Lighting Method"/>
</Widget>
<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"/>
<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"/>
<UserString key="SettingType" value="Slider"/>
<UserString key="SettingMin" value="8"/>
<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)"/>
</Widget>
<Widget type="ImageBox" skin="MW_HLine" position="0 54 360 18" align="Top HStretch"/>
<!-- Light Fade Start -->
<Widget type="TextBox" skin="NormalText" position="0 78 352 18" align="Left Top" name="MaxLightDistanceText"/>
<Widget type="ScrollBar" skin="MW_HScroll" position="0 104 352 18" align="HStretch Top">
<Property key="Range" value="8192"/>
<Property key="Page" value="1"/>
<UserString key="SettingType" value="Slider"/>
<UserString key="SettingMin" value="0"/>
<UserString key="SettingMax" value="8192"/>
<UserString key="SettingCategory" value="Shaders"/>
<UserString key="SettingName" value="maximum light distance"/>
<UserString key="SettingValueType" value="Integer"/>
<UserString key="SettingLabelWidget" value="MaxLightDistanceText"/>
<UserString key="SettingLabelCaption" value="Maximum Light Distance (%s)"/>
</Widget>
<!-- Light Fade Multiplier -->
<Widget type="TextBox" skin="NormalText" position="0 128 352 18" align="Left Top" name="LightFadeMultiplierText"/>
<Widget type="ScrollBar" skin="MW_HScroll" position="0 152 352 18" align="HStretch Top">
<Property key="Range" value="10000"/>
<Property key="Page" value="300"/>
<UserString key="SettingType" value="Slider"/>
<UserString key="SettingCategory" value="Shaders"/>
<UserString key="SettingName" value="light fade start"/>
<UserString key="SettingValueType" value="Float"/>
<UserString key="SettingLabelWidget" value="LightFadeMultiplierText"/>
<UserString key="SettingLabelCaption" value="Fade Start Multiplier (%s)"/>
</Widget>
<!-- Bounding Sphere Multiplier -->
<Widget type="TextBox" skin="NormalText" position="0 176 352 18" align="Left Top" name="BoundingSphereMultText"/>
<Widget type="ScrollBar" skin="MW_HScroll" position="0 200 352 18" align="HStretch Top">
<Property key="Range" value="10000"/>
<Property key="Page" value="300"/>
<UserString key="SettingType" value="Slider"/>
<UserString key="SettingMin" value="0.1"/>
<UserString key="SettingMax" value="5.0"/>
<UserString key="SettingCategory" value="Shaders"/>
<UserString key="SettingName" value="light bounds multiplier"/>
<UserString key="SettingValueType" value="Float"/>
<UserString key="SettingLabelWidget" value="BoundingSphereMultText"/>
<UserString key="SettingLabelCaption" value="Bounding Sphere Multiplier (%s)"/>
</Widget>
<!-- Minimum Ambient Brightness -->
<Widget type="TextBox" skin="NormalText" position="0 224 352 18" align="Left Top" name="MinimumBrightnessText"/>
<Widget type="ScrollBar" skin="MW_HScroll" position="0 248 352 18" align="HStretch Top">
<Property key="Range" value="10000"/>
<Property key="Page" value="300"/>
<UserString key="SettingType" value="Slider"/>
<UserString key="SettingCategory" value="Shaders"/>
<UserString key="SettingName" value="minimum interior brightness"/>
<UserString key="SettingValueType" value="Float"/>
<UserString key="SettingLabelWidget" value="MinimumBrightnessText"/>
<UserString key="SettingLabelCaption" value="Minimum Interior Brightness (%s)"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" position="0 308 0 0" align="Bottom Left" name="LightsResetButton">
<Property key="Caption" value="Reset To Defaults"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="NormalText" position="210 308 0 0" align="Bottom Right HStretch">
<Property key="Caption" value="(*) Requires Restart"/>
<Property key="TextAlign" value="Right"/>
</Widget>
</Widget> </Widget>
<!-- <!--
<Widget type="TabItem" skin="" position="0 28 352 268"> <Widget type="TabItem" skin="" position="0 28 352 268">

@ -2,7 +2,7 @@
#define LIGHTING_MODEL_SINGLE_UBO 1 #define LIGHTING_MODEL_SINGLE_UBO 1
#define LIGHTING_MODEL_PER_OBJECT_UNIFORM 2 #define LIGHTING_MODEL_PER_OBJECT_UNIFORM 2
#if !@ffpLighting #if @lightingModel != LIGHTING_MODEL_FFP
#define getLight LightBuffer #define getLight LightBuffer
float quickstep(float x) float quickstep(float x)
@ -13,7 +13,7 @@ float quickstep(float x)
return x; return x;
} }
#if @useUBO #if @lightingModel == LIGHTING_MODEL_SINGLE_UBO
const int mask = int(0xff); const int mask = int(0xff);
const ivec4 shift = ivec4(int(0), int(8), int(16), int(24)); const ivec4 shift = ivec4(int(0), int(8), int(16), int(24));
@ -33,11 +33,16 @@ vec4 unpackRGBA(int data)
,(float(((data >> shift.w) & mask)) / 255.0)); ,(float(((data >> shift.w) & mask)) / 255.0));
} }
/* Layout:
packedColors: 8-bit unsigned RGB packed as (diffuse, ambient, specular).
sign bit is stored in diffuse alpha component
attenuation: constant, linear, quadratic, light radius (as defined in content)
*/
struct LightData struct LightData
{ {
ivec4 packedColors; // diffuse, ambient, specular ivec4 packedColors;
vec4 position; vec4 position;
vec4 attenuation; // constant, linear, quadratic, radius vec4 attenuation;
}; };
uniform int PointLightIndex[@maxLights]; uniform int PointLightIndex[@maxLights];
@ -51,16 +56,15 @@ uniform LightBufferBinding
#else #else
struct LightData /* Layout:
{ --------------------------------------- -----------
vec4 position; | pos_x | ambi_r | diff_r | spec_r |
vec4 diffuse; | pos_y | ambi_g | diff_g | spec_g |
vec4 ambient; | pos_z | ambi_b | diff_b | spec_b |
vec4 specular; | att_c | att_l | att_q | radius/spec_a |
vec4 attenuation; // constant, linear, quadratic, radius --------------------------------------------------
}; */
uniform mat4 LightBuffer[@maxLights];
uniform LightData LightBuffer[@maxLights];
uniform int PointLightCount; uniform int PointLightCount;
#endif #endif
@ -71,9 +75,16 @@ uniform int PointLightCount;
void perLightSun(out vec3 ambientOut, out vec3 diffuseOut, vec3 viewPos, vec3 viewNormal) void perLightSun(out vec3 ambientOut, out vec3 diffuseOut, vec3 viewPos, vec3 viewNormal)
{ {
#if @lightingModel == LIGHTING_MODEL_PER_OBJECT_UNIFORM
vec3 lightDir = normalize(getLight[0][0].xyz);
#else
vec3 lightDir = normalize(getLight[0].position.xyz); vec3 lightDir = normalize(getLight[0].position.xyz);
#endif
#if @lightingModel == LIGHTING_MODEL_SINGLE_UBO #if @lightingModel == LIGHTING_MODEL_PER_OBJECT_UNIFORM
ambientOut = getLight[0][1].xyz;
vec3 sunDiffuse = getLight[0][2].xyz;
#elif @lightingModel == LIGHTING_MODEL_SINGLE_UBO
ivec4 data = getLight[0].packedColors; ivec4 data = getLight[0].packedColors;
ambientOut = unpackRGB(data.y); ambientOut = unpackRGB(data.y);
vec3 sunDiffuse = unpackRGB(data.x); vec3 sunDiffuse = unpackRGB(data.x);
@ -81,6 +92,7 @@ void perLightSun(out vec3 ambientOut, out vec3 diffuseOut, vec3 viewPos, vec3 vi
ambientOut = getLight[0].ambient.xyz; ambientOut = getLight[0].ambient.xyz;
vec3 sunDiffuse = getLight[0].diffuse.xyz; vec3 sunDiffuse = getLight[0].diffuse.xyz;
#endif #endif
float lambert = dot(viewNormal.xyz, lightDir); float lambert = dot(viewNormal.xyz, lightDir);
#ifndef GROUNDCOVER #ifndef GROUNDCOVER
lambert = max(lambert, 0.0); lambert = max(lambert, 0.0);
@ -98,13 +110,22 @@ 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)
{ {
#if @lightingModel == LIGHTING_MODEL_PER_OBJECT_UNIFORM
vec3 lightPos = getLight[lightIndex][0].xyz - viewPos;
#else
vec3 lightPos = getLight[lightIndex].position.xyz - viewPos; vec3 lightPos = getLight[lightIndex].position.xyz - viewPos;
#endif
float lightDistance = length(lightPos); float lightDistance = length(lightPos);
#if !@ffpLighting #if @lightingModel != LIGHTING_MODEL_FFP
// This has a *considerable* performance uplift where GPU is a bottleneck #if @lightingModel == LIGHTING_MODEL_PER_OBJECT_UNIFORM
if (lightDistance > getLight[lightIndex].attenuation.w * 2.0) float radius = getLight[lightIndex][3][3];
#else
float radius = getLight[lightIndex].attenuation.w;
#endif
if (lightDistance > radius * 2.0)
{ {
ambientOut = vec3(0.0); ambientOut = vec3(0.0);
diffuseOut = vec3(0.0); diffuseOut = vec3(0.0);
@ -114,17 +135,17 @@ void perLightPoint(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec
lightPos = normalize(lightPos); lightPos = normalize(lightPos);
#if @ffpLighting #if @lightingModel == LIGHTING_MODEL_PER_OBJECT_UNIFORM
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][0].w + getLight[lightIndex][1].w * lightDistance + getLight[lightIndex][2].w * lightDistance * lightDistance), 0.0, 1.0);
#else illumination *= 1.0 - quickstep((lightDistance / radius) - 1.0);
ambientOut = getLight[lightIndex][1].xyz * illumination;
#elif @lightingModel == LIGHTING_MODEL_SINGLE_UBO
float illumination = clamp(1.0 / (getLight[lightIndex].attenuation.x + getLight[lightIndex].attenuation.y * lightDistance + getLight[lightIndex].attenuation.z * lightDistance * lightDistance), 0.0, 1.0); float illumination = clamp(1.0 / (getLight[lightIndex].attenuation.x + getLight[lightIndex].attenuation.y * lightDistance + getLight[lightIndex].attenuation.z * lightDistance * lightDistance), 0.0, 1.0);
illumination *= 1.0 - quickstep((lightDistance / (getLight[lightIndex].attenuation.w)) - 1.0); illumination *= 1.0 - quickstep((lightDistance / radius) - 1.0);
#endif
#if @useUBO
ivec4 data = getLight[lightIndex].packedColors; ivec4 data = getLight[lightIndex].packedColors;
ambientOut = unpackRGB(data.y) * illumination; ambientOut = unpackRGB(data.y) * illumination;
#else #else
float illumination = clamp(1.0 / (getLight[lightIndex].constantAttenuation + getLight[lightIndex].linearAttenuation * lightDistance + getLight[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0);
ambientOut = getLight[lightIndex].ambient.xyz * illumination; ambientOut = getLight[lightIndex].ambient.xyz * illumination;
#endif #endif
@ -142,8 +163,10 @@ void perLightPoint(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec
lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0); lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0);
#endif #endif
#if @useUBO #if @lightingModel == LIGHTING_MODEL_SINGLE_UBO
diffuseOut = unpackRGB(data.x) * lambert * float(int(data.w)); diffuseOut = unpackRGB(data.x) * lambert * float(int(data.w));
#elif @lightingModel == LIGHTING_MODEL_PER_OBJECT_UNIFORM
diffuseOut = getLight[lightIndex][2].xyz * lambert;
#else #else
diffuseOut = getLight[lightIndex].diffuse.xyz * lambert; diffuseOut = getLight[lightIndex].diffuse.xyz * lambert;
#endif #endif
@ -191,10 +214,16 @@ void doLighting(vec3 viewPos, vec3 viewNormal, out vec3 diffuseLight, out vec3 a
vec3 getSpecular(vec3 viewNormal, vec3 viewDirection, float shininess, vec3 matSpec) vec3 getSpecular(vec3 viewNormal, vec3 viewDirection, float shininess, vec3 matSpec)
{ {
#if @lightingModel == LIGHTING_MODEL_PER_OBJECT_UNIFORM
vec3 sunDir = getLight[0][0].xyz;
#else
vec3 sunDir = getLight[0].position.xyz; vec3 sunDir = getLight[0].position.xyz;
#endif
#if @lightingModel == LIGHTING_MODEL_SINGLE_UBO #if @lightingModel == LIGHTING_MODEL_SINGLE_UBO
vec3 sunSpec = unpackRGB(getLight[0].packedColors.z); vec3 sunSpec = unpackRGB(getLight[0].packedColors.z);
#elif @lightingModel == LIGHTING_MODEL_PER_OBJECT_UNIFORM
vec3 sunSpec = getLight[0][3].xyz;
#else #else
vec3 sunSpec = getLight[0].specular.xyz; vec3 sunSpec = getLight[0].specular.xyz;
#endif #endif

@ -203,8 +203,11 @@ void main(void)
normal3 * midWaves.y + normal4 * smallWaves.x + normal5 * smallWaves.y + rippleAdd); normal3 * midWaves.y + normal4 * smallWaves.x + normal5 * smallWaves.y + rippleAdd);
normal = normalize(vec3(-normal.x * bump, -normal.y * bump, normal.z)); normal = normalize(vec3(-normal.x * bump, -normal.y * bump, normal.z));
#if @lightingModel == LIGHTING_MODEL_PER_OBJECT_UNIFORM
vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(getLight[0][0].xyz, 0.0)).xyz);
#else
vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(getLight[0].position.xyz, 0.0)).xyz); vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(getLight[0].position.xyz, 0.0)).xyz);
#endif
vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz;
vec3 vVec = normalize(position.xyz - cameraPos.xyz); vec3 vVec = normalize(position.xyz - cameraPos.xyz);
@ -241,6 +244,8 @@ void main(void)
#if @lightingModel == LIGHTING_MODEL_SINGLE_UBO #if @lightingModel == LIGHTING_MODEL_SINGLE_UBO
vec4 sunSpec = unpackRGBA(getLight[0].packedColors.z); vec4 sunSpec = unpackRGBA(getLight[0].packedColors.z);
#elif @lightingModel == LIGHTING_MODEL_PER_OBJECT_UNIFORM
vec4 sunSpec = getLight[0][3];
#else #else
vec4 sunSpec = getLight[0].specular; vec4 sunSpec = getLight[0].specular;
#endif #endif

Loading…
Cancel
Save