1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-19 23:53:52 +00:00

Merge pull request #2584 from Capostrophic/shadows

Resolving 0.46.0 release shadow-related blockers
This commit is contained in:
Andrei Kortunov 2019-11-03 08:35:30 +04:00 committed by GitHub
commit 678d2e6e7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 479 additions and 175 deletions

View file

@ -45,6 +45,7 @@ Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, Settings:
connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool)));
connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int)));
connect(framerateLimitCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFramerateLimitToggled(bool)));
connect(shadowDistanceCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShadowDistLimitToggled(bool)));
}
@ -129,6 +130,33 @@ bool Launcher::GraphicsPage::loadSettings()
framerateLimitSpinBox->setValue(fpsLimit);
}
if (mEngineSettings.getBool("actor shadows", "Shadows"))
actorShadowsCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("player shadows", "Shadows"))
playerShadowsCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("terrain shadows", "Shadows"))
objectShadowsCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("object shadows", "Shadows"))
objectShadowsCheckBox->setCheckState(Qt::Checked);
if (mEngineSettings.getBool("enable indoor shadows", "Shadows"))
indoorShadowsCheckBox->setCheckState(Qt::Checked);
int shadowDistLimit = mEngineSettings.getInt("maximum shadow map distance", "Shadows");
if (shadowDistLimit > 0)
{
shadowDistanceCheckBox->setCheckState(Qt::Checked);
shadowDistanceSpinBox->setValue(shadowDistLimit);
}
float shadowFadeStart = mEngineSettings.getFloat("shadow fade start", "Shadows");
if (shadowFadeStart != 0)
fadeStartSpinBox->setValue(shadowFadeStart);
int shadowRes = mEngineSettings.getInt("shadow map resolution", "Shadows");
int shadowResIndex = shadowResolutionComboBox->findText(QString::number(shadowRes));
if (shadowResIndex != -1)
shadowResolutionComboBox->setCurrentIndex(shadowResIndex);
return true;
}
@ -185,6 +213,52 @@ void Launcher::GraphicsPage::saveSettings()
{
mEngineSettings.setFloat("framerate limit", "Video", 0);
}
int cShadowDist = shadowDistanceCheckBox->checkState() ? shadowDistanceSpinBox->value() : 0;
if (mEngineSettings.getInt("maximum shadow map distance", "Shadows") != cShadowDist)
mEngineSettings.setInt("maximum shadow map distance", "Shadows", cShadowDist);
float cFadeStart = fadeStartSpinBox->value();
if (cShadowDist > 0 && mEngineSettings.getFloat("shadow fade start", "Shadows") != cFadeStart)
mEngineSettings.setFloat("shadow fade start", "Shadows", cFadeStart);
bool cActorShadows = actorShadowsCheckBox->checkState();
bool cObjectShadows = objectShadowsCheckBox->checkState();
bool cTerrainShadows = terrainShadowsCheckBox->checkState();
bool cPlayerShadows = playerShadowsCheckBox->checkState();
if (cActorShadows || cObjectShadows || cTerrainShadows || cPlayerShadows)
{
if (mEngineSettings.getBool("enable shadows", "Shadows") != true)
mEngineSettings.setBool("enable shadows", "Shadows", true);
if (mEngineSettings.getBool("actor shadows", "Shadows") != cActorShadows)
mEngineSettings.setBool("actor shadows", "Shadows", cActorShadows);
if (mEngineSettings.getBool("player shadows", "Shadows") != cPlayerShadows)
mEngineSettings.setBool("player shadows", "Shadows", cPlayerShadows);
if (mEngineSettings.getBool("object shadows", "Shadows") != cObjectShadows)
mEngineSettings.setBool("object shadows", "Shadows", cObjectShadows);
if (mEngineSettings.getBool("terrain shadows", "Shadows") != cTerrainShadows)
mEngineSettings.setBool("terrain shadows", "Shadows", cTerrainShadows);
}
else
{
if (mEngineSettings.getBool("enable shadows", "Shadows"))
mEngineSettings.setBool("enable shadows", "Shadows", false);
if (mEngineSettings.getBool("actor shadows", "Shadows"))
mEngineSettings.setBool("actor shadows", "Shadows", false);
if (mEngineSettings.getBool("player shadows", "Shadows"))
mEngineSettings.setBool("player shadows", "Shadows", false);
if (mEngineSettings.getBool("object shadows", "Shadows"))
mEngineSettings.setBool("object shadows", "Shadows", false);
if (mEngineSettings.getBool("terrain shadows", "Shadows"))
mEngineSettings.setBool("terrain shadows", "Shadows", false);
}
bool cIndoorShadows = indoorShadowsCheckBox->checkState();
if (mEngineSettings.getBool("enable indoor shadows", "Shadows") != cIndoorShadows)
mEngineSettings.setBool("enable indoor shadows", "Shadows", cIndoorShadows);
int cShadowRes = shadowResolutionComboBox->currentText().toInt();
if (cShadowRes != mEngineSettings.getInt("shadow map resolution", "Shadows"))
mEngineSettings.setInt("shadow map resolution", "Shadows", cShadowRes);
}
QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
@ -290,3 +364,9 @@ void Launcher::GraphicsPage::slotFramerateLimitToggled(bool checked)
{
framerateLimitSpinBox->setEnabled(checked);
}
void Launcher::GraphicsPage::slotShadowDistLimitToggled(bool checked)
{
shadowDistanceSpinBox->setEnabled(checked);
fadeStartSpinBox->setEnabled(checked);
}

View file

@ -32,6 +32,7 @@ namespace Launcher
void slotFullScreenChanged(int state);
void slotStandardToggled(bool checked);
void slotFramerateLimitToggled(bool checked);
void slotShadowDistLimitToggled(bool checked);
private:
Files::ConfigurationManager &mCfgMgr;

View file

@ -843,6 +843,11 @@ void SceneUtil::MWShadowTechnique::setPolygonOffset(float factor, float units)
}
}
void SceneUtil::MWShadowTechnique::setShadowFadeStart(float shadowFadeStart)
{
_shadowFadeStart = shadowFadeStart;
}
void SceneUtil::MWShadowTechnique::enableFrontFaceCulling()
{
_useFrontFaceCulling = true;
@ -1493,6 +1498,9 @@ void MWShadowTechnique::createShaders()
osg::ref_ptr<osg::Uniform> baseTextureUnit = new osg::Uniform("baseTextureUnit",(int)_baseTextureUnit);
_uniforms.push_back(baseTextureUnit.get());
_uniforms.push_back(new osg::Uniform("maximumShadowMapDistance", (float)settings->getMaximumShadowMapDistance()));
_uniforms.push_back(new osg::Uniform("shadowFadeStart", (float)_shadowFadeStart));
for(unsigned int sm_i=0; sm_i<settings->getNumShadowMapsPerLight(); ++sm_i)
{
{

View file

@ -76,6 +76,8 @@ namespace SceneUtil {
virtual void setPolygonOffset(float factor, float units);
virtual void setShadowFadeStart(float shadowFadeStart);
virtual void enableFrontFaceCulling();
virtual void disableFrontFaceCulling();
@ -257,6 +259,8 @@ namespace SceneUtil {
bool _useFrontFaceCulling = true;
float _shadowFadeStart = 0.0;
class DebugHUD : public osg::Referenced
{
public:

View file

@ -27,6 +27,14 @@ namespace SceneUtil
mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight);
mShadowSettings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight);
const float maximumShadowMapDistance = Settings::Manager::getFloat("maximum shadow map distance", "Shadows");
if (maximumShadowMapDistance > 0)
{
const float shadowFadeStart = std::min(std::max(0.f, Settings::Manager::getFloat("shadow fade start", "Shadows")), 1.f);
mShadowSettings->setMaximumShadowMapDistance(maximumShadowMapDistance);
mShadowTechnique->setShadowFadeStart(maximumShadowMapDistance * shadowFadeStart);
}
mShadowSettings->setMinimumShadowMapNearFarRatio(Settings::Manager::getFloat("minimum lispsm near far ratio", "Shadows"));
if (Settings::Manager::getBool("compute tight scene bounds", "Shadows"))
mShadowSettings->setComputeNearFarModeOverride(osg::CullSettings::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
@ -117,6 +125,8 @@ namespace SceneUtil
definesWithShadows["shadowNormalOffset"] = std::to_string(Settings::Manager::getFloat("normal offset distance", "Shadows"));
definesWithShadows["limitShadowMapDistance"] = Settings::Manager::getFloat("maximum shadow map distance", "Shadows") > 0 ? "1" : "0";
return definesWithShadows;
}
@ -138,6 +148,8 @@ namespace SceneUtil
definesWithoutShadows["shadowNormalOffset"] = "0.0";
definesWithoutShadows["limitShadowMapDistance"] = "0";
return definesWithoutShadows;
}

View file

@ -16,7 +16,6 @@ Unlike in the original Morrowind engine, 'Shadow Mapping' is used, which can hav
Bear in mind that this will force OpenMW to use shaders as if :ref:`force shaders` was enabled.
A keen developer may be able to implement compatibility with fixed-function mode using the advice of `this post <https://github.com/OpenMW/openmw/pull/1547#issuecomment-369657381>`_, but it may be more difficult than it seems.
number of shadow maps
---------------------
@ -28,6 +27,28 @@ Control how many shadow maps to use - more of these means each shadow map texel
Using too many shadow maps will lead to them overriding texture slots used for other effects, producing unpleasant artefacts.
A value of three is recommended in most cases, but other values may produce better results or performance.
maximum shadow map distance
---------------------------
:Type: float
:Range: The whole range of 32-bit floating point
:Default: 8192
The maximum distance from the camera shadows cover, limiting their overall area coverage
and improving their quality and performance at the cost of removing shadows of distant objects or terrain.
Set this to a non-positive value to remove the limit.
shadow fade start
-------------------
:Type: float
:Range: 0.0-1.0
:Default: 0.9
The fraction of the maximum shadow map distance at which the shadows will begin to fade away.
Tweaking it will make the transition proportionally more or less smooth.
This setting has no effect if the maximum shadow map distance is non-positive (infinite).
allow shadow map overlap
------------------------
@ -213,4 +234,4 @@ minimum lispsm near far ratio
Controls the minimum near/far ratio for the Light Space Perspective Shadow Map transformation.
Helps prevent too much detail being brought towards the camera at the expense of detail further from the camera.
Increasing this pushes detail further away by moving the frustum apex further from the near plane.
Increasing this pushes detail further away by moving the frustum apex further from the near plane.

View file

@ -746,6 +746,12 @@ enable shadows = false
# How many shadow maps to use - more of these means each shadow map texel covers less area, producing better looking shadows, but may decrease performance.
number of shadow maps = 3
# The distance from the camera at which shadows fade away completely. Set to 0 to make the distance infinite.
maximum shadow map distance = 8192
# Fraction of the maximum distance at which shadows begin to gradually fade away.
shadow fade start = 0.9
# If true, allow shadow maps to overlap. Counter-intuitively, will produce better results when the light is behind the camera. When enabled, OpenMW uses Cascaded Shadow Maps and when disabled, it uses Parallel Split Shadow Maps.
allow shadow map overlap = true

View file

@ -114,7 +114,7 @@ void main()
gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a);
#endif
float shadowing = unshadowedLightRatio();
float shadowing = unshadowedLightRatio(depth);
#if !PER_PIXEL_LIGHTING

View file

@ -1,6 +1,8 @@
#define SHADOWS @shadows_enabled
#if SHADOWS
uniform float maximumShadowMapDistance;
uniform float shadowFadeStart;
@foreach shadow_texture_unit_index @shadow_texture_unit_list
uniform sampler2DShadow shadowTexture@shadow_texture_unit_index;
varying vec4 shadowSpaceCoords@shadow_texture_unit_index;
@ -11,10 +13,15 @@
@endforeach
#endif // SHADOWS
float unshadowedLightRatio()
float unshadowedLightRatio(float distance)
{
float shadowing = 1.0;
#if SHADOWS
#if @limitShadowMapDistance
float fade = clamp((distance - shadowFadeStart) / (maximumShadowMapDistance - shadowFadeStart), 0.0, 1.0);
if (fade == 1.0)
return shadowing;
#endif
#if @shadowMapsOverlap
bool doneShadows = false;
@foreach shadow_texture_unit_index @shadow_texture_unit_list
@ -41,6 +48,9 @@ float unshadowedLightRatio()
shadowing = min(shadow2DProj(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index).r, shadowing);
@endforeach
#endif
#if @limitShadowMapDistance
shadowing = mix(shadowing, 1.0, fade);
#endif
#endif // SHADOWS
return shadowing;
}

View file

@ -66,7 +66,7 @@ void main()
gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a;
#endif
float shadowing = unshadowedLightRatio();
float shadowing = unshadowedLightRatio(depth);
#if !PER_PIXEL_LIGHTING

View file

@ -160,7 +160,7 @@ void main(void)
vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0;
UV.y *= -1.0;
float shadow = unshadowedLightRatio();
float shadow = unshadowedLightRatio(depthPassthrough);
vec2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z;
screenCoords.y = (1.0-screenCoords.y);

View file

@ -6,191 +6,353 @@
<rect>
<x>0</x>
<y>0</y>
<width>437</width>
<height>343</height>
<width>650</width>
<height>340</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="displayGroup">
<property name="title">
<string>Display</string>
<widget class="QTabWidget" name="DisplayTabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<layout class="QGridLayout" name="gridLayout_4" columnstretch="1,1">
<item row="0" column="0">
<widget class="QCheckBox" name="vSyncCheckBox">
<property name="text">
<string>Vertical Sync</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="fullScreenCheckBox">
<property name="text">
<string>Full Screen</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="windowBorderCheckBox">
<property name="text">
<string>Window Border</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="antiAliasingLabel">
<property name="text">
<string>Anti-aliasing:</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="screenLabel">
<property name="text">
<string>Screen:</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="resolutionLabel">
<property name="text">
<string>Resolution:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="framerateLimitCheckBox">
<property name="text">
<string>Framerate Limit:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="antiAliasingComboBox">
<item>
<property name="text">
<string>0</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
<item>
<property name="text">
<string>4</string>
</property>
</item>
<item>
<property name="text">
<string>8</string>
</property>
</item>
<item>
<property name="text">
<string>16</string>
</property>
</item>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="screenComboBox"/>
</item>
<item row="5" column="1">
<layout class="QGridLayout" name="resolutionLayout">
<item row="1" column="2">
<layout class="QHBoxLayout" name="customResolutionLayout" stretch="1,0,1">
<item>
<widget class="QSpinBox" name="customWidthSpinBox">
<property name="minimum">
<number>800</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="multiplyLabel">
<widget class="QWidget" name="DisplayWrapper">
<attribute name="title">
<string>Display</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QWidget" name="DisplayWidget">
<layout class="QGridLayout" name="gridLayout_4" columnstretch="1,0">
<item row="3" column="0">
<widget class="QLabel" name="antiAliasingLabel">
<property name="text">
<string> x </string>
<string>Anti-aliasing:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="customHeightSpinBox">
<item row="6" column="0">
<widget class="QCheckBox" name="framerateLimitCheckBox">
<property name="text">
<string>Framerate Limit:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QGridLayout" name="resolutionLayout">
<item row="1" column="2">
<layout class="QHBoxLayout" name="customResolutionLayout" stretch="1,0,1">
<item>
<widget class="QSpinBox" name="customWidthSpinBox">
<property name="minimum">
<number>800</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="multiplyLabel">
<property name="text">
<string> x </string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="customHeightSpinBox">
<property name="minimum">
<number>600</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="QRadioButton" name="customRadioButton">
<property name="text">
<string>Custom:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="standardRadioButton">
<property name="text">
<string>Standard:</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="resolutionComboBox"/>
</item>
</layout>
</item>
<item row="6" column="1">
<widget class="QDoubleSpinBox" name="framerateLimitSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> FPS</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<number>600</number>
<double>1</double>
</property>
<property name="maximum">
<double>1000</double>
</property>
<property name="singleStep">
<double>15</double>
</property>
<property name="value">
<double>300</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="windowBorderCheckBox">
<property name="text">
<string>Window Border</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="fullScreenCheckBox">
<property name="text">
<string>Full Screen</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="resolutionLabel">
<property name="text">
<string>Resolution:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="screenComboBox"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="screenLabel">
<property name="text">
<string>Screen:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="antiAliasingComboBox">
<item>
<property name="text">
<string>0</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
<item>
<property name="text">
<string>4</string>
</property>
</item>
<item>
<property name="text">
<string>8</string>
</property>
</item>
<item>
<property name="text">
<string>16</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="vSyncCheckBox">
<property name="text">
<string>Vertical Sync</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<widget class="QRadioButton" name="customRadioButton">
<property name="text">
<string>Custom:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="standardRadioButton">
<property name="text">
<string>Standard:</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="resolutionComboBox"/>
</item>
</layout>
</item>
<item row="6" column="1">
<widget class="QDoubleSpinBox" name="framerateLimitSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> FPS</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>1</double>
</property>
<property name="maximum">
<double>1000</double>
</property>
<property name="singleStep">
<double>15</double>
</property>
<property name="value">
<double>300</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="ShadowWrapper">
<attribute name="title">
<string>Shadows</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QWidget" name="ShadowWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="shadowsLayout" columnstretch="0,0">
<item row="6" column="0">
<widget class="QCheckBox" name="shadowDistanceCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The distance from the camera at which shadows completely disappear.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Shadow Distance Limit:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QSpinBox" name="shadowDistanceSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;64 game units is 1 real life yard or about 0.9 m&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="suffix">
<string> unit(s)</string>
</property>
<property name="minimum">
<number>512</number>
</property>
<property name="maximum">
<number>81920</number>
</property>
<property name="value">
<number>8192</number>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="fadeStartLabel">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The fraction of the limit above at which shadows begin to gradually fade away.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Fade Start Multiplier:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="shadowResolutionComboBox">
<item>
<property name="text">
<string>512</string>
</property>
</item>
<item>
<property name="text">
<string>1024</string>
</property>
</item>
<item>
<property name="text">
<string>2048</string>
</property>
</item>
<item>
<property name="text">
<string>4096</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="actorShadowsCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable shadows for NPCs and creatures besides the player character. May have a minor performance impact.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable Actor Shadows</string>
</property>
</widget>
</item>
<item row="3" column="0" alignment="Qt::AlignLeft">
<widget class="QCheckBox" name="terrainShadowsCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable shadows for the terrain including distant terrain. May have a significant performance and shadow quality impact.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable Terrain Shadows</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QDoubleSpinBox" name="fadeStartSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="minimum">
<double>0</double>
</property>
<property name="maximum">
<double>1</double>
</property>
<property name="value">
<double>0.90</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="playerShadowsCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable shadows exclusively for the player character. May have a very minor performance impact.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable Player Shadows</string>
</property>
</widget>
</item>
<item row="5" column="0" alignment="Qt::AlignLeft">
<widget class="QLabel" name="shadowResolutionLabel">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The resolution of each individual shadow map. Increasing it significantly improves shadow quality but may have a minor performance impact.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Shadow Map Resolution:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="objectShadowsCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable shadows for primarily inanimate objects. May have a significant performance impact.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable Object Shadows</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="indoorShadowsCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Due to limitations with Morrowind's data, only actors can cast shadows indoors, which some might feel is distracting.&lt;/p&gt;&lt;p&gt;Has no effect if actor/player shadows are not enabled.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable Indoor Shadows</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>61</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>