mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-09-22 11:23:27 -04:00
Merge branch 'bmd-scaling' into 'master'
Added support for `Video -> resolution scale = 0.1 to 1.0`. See merge request OpenMW/openmw!4896
This commit is contained in:
commit
0f2a79fa79
@ -96,6 +96,10 @@ namespace MWLua
|
||||
api["setViewDistance"]
|
||||
= [renderingManager](const FiniteFloat d) { renderingManager->setViewDistance(d, true); };
|
||||
|
||||
api["getResolutionScale"] = [renderingManager]() { return renderingManager->getResolutionScale(); };
|
||||
api["setResolutionScale"]
|
||||
= [renderingManager](const FiniteFloat scale) { renderingManager->setResolutionScale(scale); };
|
||||
|
||||
api["getViewTransform"] = [camera]() { return LuaUtil::TransformM{ camera->getViewMatrix() }; };
|
||||
|
||||
api["viewportToWorldVector"] = [camera, renderingManager](osg::Vec2f pos) -> osg::Vec3f {
|
||||
|
@ -125,6 +125,8 @@ namespace MWRender
|
||||
, mSamples(Settings::video().mAntialiasing)
|
||||
, mPingPongCull(new PingPongCull(this))
|
||||
, mDistortionCallback(new DistortionCallback)
|
||||
, mScaledViewportStateSet(new osg::StateSet)
|
||||
, mScaledViewport(new osg::Viewport)
|
||||
{
|
||||
auto& shaderManager = mRendering.getResourceSystem()->getSceneManager()->getShaderManager();
|
||||
|
||||
@ -148,6 +150,8 @@ namespace MWRender
|
||||
mHUDCamera->setCullCallback(new HUDCullCallback);
|
||||
mViewer->getCamera()->addCullCallback(mPingPongCull);
|
||||
|
||||
mScaledViewportStateSet->setAttribute(mScaledViewport);
|
||||
|
||||
// resolves the multisampled depth buffer and optionally draws an additional depth postpass
|
||||
mTransparentDepthPostPass
|
||||
= new TransparentDepthBinCallback(mRendering.getResourceSystem()->getSceneManager()->getShaderManager(),
|
||||
@ -276,13 +280,26 @@ namespace MWRender
|
||||
void PostProcessor::traverse(osg::NodeVisitor& nv)
|
||||
{
|
||||
size_t frameId = nv.getTraversalNumber() % 2;
|
||||
bool pushedStateSet = false;
|
||||
|
||||
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
||||
cull(frameId, static_cast<osgUtil::CullVisitor*>(&nv));
|
||||
{
|
||||
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);
|
||||
mScaledViewport->setViewport(0, 0, renderWidth(), renderHeight());
|
||||
cv->pushStateSet(mScaledViewportStateSet.get());
|
||||
pushedStateSet = true;
|
||||
|
||||
cull(frameId, cv);
|
||||
}
|
||||
else if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
|
||||
update(frameId);
|
||||
|
||||
osg::Group::traverse(nv);
|
||||
|
||||
if (pushedStateSet)
|
||||
{
|
||||
static_cast<osgUtil::CullVisitor*>(&nv)->popStateSet();
|
||||
}
|
||||
}
|
||||
|
||||
void PostProcessor::cull(size_t frameId, osgUtil::CullVisitor* cv)
|
||||
@ -567,8 +584,11 @@ namespace MWRender
|
||||
|
||||
std::vector<Fx::Types::RenderTarget> attachmentsToDirty;
|
||||
|
||||
for (const auto& technique : mTechniques)
|
||||
// Filter techniques to only include valid ones
|
||||
std::vector<std::shared_ptr<Fx::Technique>> validTechniques;
|
||||
for (auto techIt = mTechniques.begin(); techIt != mTechniques.end(); ++techIt)
|
||||
{
|
||||
const auto& technique = *techIt;
|
||||
if (!technique->isValid())
|
||||
continue;
|
||||
|
||||
@ -578,6 +598,12 @@ namespace MWRender
|
||||
<< technique->getGLSLVersion() << " which is unsupported by your hardware.";
|
||||
continue;
|
||||
}
|
||||
validTechniques.push_back(technique);
|
||||
}
|
||||
|
||||
for (size_t techIdx = 0; techIdx < validTechniques.size(); ++techIdx)
|
||||
{
|
||||
const auto& technique = validTechniques[techIdx];
|
||||
|
||||
Fx::DispatchNode node;
|
||||
|
||||
@ -635,8 +661,10 @@ namespace MWRender
|
||||
uniform->mName.c_str(), *type, uniform->getNumElements()));
|
||||
}
|
||||
|
||||
for (const auto& pass : technique->getPasses())
|
||||
const auto& passes = technique->getPasses();
|
||||
for (size_t passIdx = 0; passIdx < passes.size(); ++passIdx)
|
||||
{
|
||||
const auto& pass = passes[passIdx];
|
||||
int subTexUnit = texUnit;
|
||||
Fx::DispatchNode::SubPass subPass;
|
||||
|
||||
@ -644,6 +672,8 @@ namespace MWRender
|
||||
|
||||
node.mHandle = technique;
|
||||
|
||||
bool isFinalPass = (techIdx == validTechniques.size() - 1 && passIdx == passes.size() - 1);
|
||||
|
||||
if (!pass->getTarget().empty())
|
||||
{
|
||||
auto& renderTarget = technique->getRenderTargetsMap()[pass->getTarget()];
|
||||
@ -676,6 +706,10 @@ namespace MWRender
|
||||
attachmentsToDirty.push_back(Fx::Types::RenderTarget(renderTarget));
|
||||
}
|
||||
}
|
||||
else if (!isFinalPass)
|
||||
{
|
||||
subPass.mStateSet->setAttribute(new osg::Viewport(0, 0, renderWidth(), renderHeight()));
|
||||
}
|
||||
|
||||
for (const auto& name : pass->getRenderTargets())
|
||||
{
|
||||
@ -858,16 +892,16 @@ namespace MWRender
|
||||
|
||||
int PostProcessor::renderWidth() const
|
||||
{
|
||||
if (Stereo::getStereo())
|
||||
return Stereo::Manager::instance().eyeResolution().x();
|
||||
return mWidth;
|
||||
float scale = static_cast<float>(Settings::video().mResolutionScale);
|
||||
int baseWidth = Stereo::getStereo() ? Stereo::Manager::instance().eyeResolution().x() : mWidth;
|
||||
return std::max(1, static_cast<int>(baseWidth * scale));
|
||||
}
|
||||
|
||||
int PostProcessor::renderHeight() const
|
||||
{
|
||||
if (Stereo::getStereo())
|
||||
return Stereo::Manager::instance().eyeResolution().y();
|
||||
return mHeight;
|
||||
float scale = static_cast<float>(Settings::video().mResolutionScale);
|
||||
int baseHeight = Stereo::getStereo() ? Stereo::Manager::instance().eyeResolution().y() : mHeight;
|
||||
return std::max(1, static_cast<int>(baseHeight * scale));
|
||||
}
|
||||
|
||||
void PostProcessor::triggerShaderReload()
|
||||
|
@ -268,6 +268,8 @@ namespace MWRender
|
||||
std::array<osg::ref_ptr<PingPongCanvas>, 2> mCanvases;
|
||||
osg::ref_ptr<TransparentDepthBinCallback> mTransparentDepthPostPass;
|
||||
osg::ref_ptr<DistortionCallback> mDistortionCallback;
|
||||
osg::ref_ptr<osg::StateSet> mScaledViewportStateSet;
|
||||
osg::ref_ptr<osg::Viewport> mScaledViewport;
|
||||
|
||||
Fx::DispatchArray mTemplateData;
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "renderingmanager.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
|
||||
@ -1382,15 +1383,18 @@ namespace MWRender
|
||||
|
||||
mSharedUniformStateUpdater->setNear(mNearClip);
|
||||
mSharedUniformStateUpdater->setFar(mViewDistance);
|
||||
|
||||
float scale = static_cast<float>(Settings::video().mResolutionScale);
|
||||
|
||||
if (Stereo::getStereo())
|
||||
{
|
||||
auto res = Stereo::Manager::instance().eyeResolution();
|
||||
mSharedUniformStateUpdater->setScreenRes(res.x(), res.y());
|
||||
mSharedUniformStateUpdater->setScreenRes(res.x() * scale, res.y() * scale);
|
||||
Stereo::Manager::instance().setMasterProjectionMatrix(mPerViewUniformStateUpdater->getProjectionMatrix());
|
||||
}
|
||||
else
|
||||
{
|
||||
mSharedUniformStateUpdater->setScreenRes(width, height);
|
||||
mSharedUniformStateUpdater->setScreenRes(width * scale, height * scale);
|
||||
}
|
||||
|
||||
// Since our fog is not radial yet, we should take FOV in account, otherwise terrain near viewing distance may
|
||||
@ -1520,6 +1524,10 @@ namespace MWRender
|
||||
{
|
||||
updateProjection = true;
|
||||
}
|
||||
else if (it->first == "Video" && it->second == "resolution scale")
|
||||
{
|
||||
mPostProcessor->resize();
|
||||
}
|
||||
else if (it->first == "Camera" && it->second == "viewing distance")
|
||||
{
|
||||
setViewDistance(Settings::camera().mViewingDistance);
|
||||
@ -1610,6 +1618,22 @@ namespace MWRender
|
||||
updateProjectionMatrix();
|
||||
}
|
||||
|
||||
float RenderingManager::getResolutionScale() const
|
||||
{
|
||||
return Settings::video().mResolutionScale;
|
||||
}
|
||||
|
||||
void RenderingManager::setResolutionScale(float scale)
|
||||
{
|
||||
scale = std::clamp(scale, 0.1f, 1.0f);
|
||||
Settings::video().mResolutionScale.set(scale);
|
||||
|
||||
if (mPostProcessor)
|
||||
{
|
||||
mPostProcessor->resize();
|
||||
}
|
||||
}
|
||||
|
||||
float RenderingManager::getTerrainHeightAt(const osg::Vec3f& pos, ESM::RefId worldspace)
|
||||
{
|
||||
return getWorldspaceChunkMgr(worldspace).mTerrain->getHeightAt(pos);
|
||||
|
@ -230,6 +230,9 @@ namespace MWRender
|
||||
|
||||
void setViewDistance(float distance, bool delay = false);
|
||||
|
||||
float getResolutionScale() const;
|
||||
void setResolutionScale(float scale);
|
||||
|
||||
float getTerrainHeightAt(const osg::Vec3f& pos, ESM::RefId worldspace);
|
||||
|
||||
// camera stuff
|
||||
|
@ -22,6 +22,8 @@ namespace Settings
|
||||
|
||||
SettingValue<int> mResolutionX{ mIndex, "Video", "resolution x", makeMaxSanitizerInt(1) };
|
||||
SettingValue<int> mResolutionY{ mIndex, "Video", "resolution y", makeMaxSanitizerInt(1) };
|
||||
SettingValue<float> mResolutionScale{ mIndex, "Video", "resolution scale",
|
||||
makeClampStrictMaxSanitizerFloat(0.1, 1.0) };
|
||||
SettingValue<WindowMode> mWindowMode{ mIndex, "Video", "window mode" };
|
||||
SettingValue<int> mScreen{ mIndex, "Video", "screen", makeMaxSanitizerInt(0) };
|
||||
SettingValue<bool> mMinimizeOnFocusLoss{ mIndex, "Video", "minimize on focus loss" };
|
||||
|
@ -23,6 +23,23 @@ Video Settings
|
||||
Larger values produce more detailed images within the constraints of your graphics hardware,
|
||||
but may reduce the frame rate.
|
||||
|
||||
.. omw-setting::
|
||||
:title: resolution scale
|
||||
:type: float
|
||||
:range: 0.1 to 1.0
|
||||
:default: 1.0
|
||||
:location: :bdg-info:`In Game > Options > Video`
|
||||
|
||||
This setting controls the internal rendering resolution as a percentage of the window resolution.
|
||||
Values below 1.0 render the game at a lower resolution and upscale to the window size.
|
||||
For example, 0.5 on a 2560x1440 display would render at 1280x720 internally,
|
||||
providing substantial performance improvements on GPU-limited systems while maintaining UI elements at full resolution.
|
||||
|
||||
.. note::
|
||||
This setting is primarily intended for low-powered devices with high-DPI displays
|
||||
(such as retro handhelds or low-powered Android phones). On desktop systems with adequate GPUs,
|
||||
this should typically remain at 1.0 for optimal image quality.
|
||||
|
||||
.. omw-setting::
|
||||
:title: window mode
|
||||
:type: int
|
||||
|
@ -176,6 +176,7 @@ ReflectionShaderDetailTerrain: "Terrain"
|
||||
ReflectionShaderDetailWorld: "Welt"
|
||||
Refraction: "Lichtbrechung"
|
||||
ResetControls: "Tastenbelegungen zurücksetzen"
|
||||
ResolutionScale: "Auflösungsskalierung"
|
||||
Screenshot: "Screenshot"
|
||||
Scripts: "Skripte"
|
||||
ScriptsDisabled: "Laden Sie einen Spielstand, um auf die Skripteinstellungen zugreifen zu können."
|
||||
|
@ -176,6 +176,7 @@ ReflectionShaderDetailTerrain: "Terrain"
|
||||
ReflectionShaderDetailWorld: "World"
|
||||
Refraction: "Refraction"
|
||||
ResetControls: "Reset Controls"
|
||||
ResolutionScale: "Resolution Scale"
|
||||
Screenshot: "Screenshot"
|
||||
Scripts: "Scripts"
|
||||
ScriptsDisabled: "Load a game to access script settings."
|
||||
|
@ -176,6 +176,7 @@ ReflectionShaderDetailTerrain: "Terrain"
|
||||
ReflectionShaderDetailWorld: "Monde"
|
||||
Refraction: "Réfraction"
|
||||
ResetControls: "Réinitialiser les contrôles"
|
||||
ResolutionScale: "Échelle de résolution"
|
||||
Screenshot: "Capture d'écran"
|
||||
Scripts: "Scripts"
|
||||
ScriptsDisabled: "Chargez une sauvegarde pour accéder aux paramètres des scripts."
|
||||
|
@ -176,6 +176,7 @@ ReflectionShaderDetailTerrain: "Teren"
|
||||
ReflectionShaderDetailWorld: "Świat"
|
||||
Refraction: "Załamanie światła"
|
||||
ResetControls: "Przywróć sterowanie"
|
||||
ResolutionScale: "Skalowanie rozdzielczości"
|
||||
Screenshot: "Zrzut ekranu"
|
||||
Scripts: "Skrypty"
|
||||
ScriptsDisabled: "Wczytaj grę, aby uzyskać dostęp do ustawień skryptów."
|
||||
|
@ -176,6 +176,7 @@ ReflectionShaderDetailTerrain: "Ландшафт"
|
||||
ReflectionShaderDetailWorld: "Мир"
|
||||
Refraction: "Рефракция"
|
||||
ResetControls: "Сбросить"
|
||||
ResolutionScale: "Масштаб разрешения"
|
||||
Screenshot: "Снимок экрана"
|
||||
Scripts: "Скрипты"
|
||||
ScriptsDisabled: "Загрузите игру, чтобы получить доступ к настройкам скриптов."
|
||||
|
@ -177,6 +177,7 @@ ReflectionShaderDetailTerrain: "Terräng"
|
||||
ReflectionShaderDetailWorld: "Värld"
|
||||
Refraction: "Refraktion"
|
||||
ResetControls: "Återställ kontroller"
|
||||
ResolutionScale: "Upplösningsskala"
|
||||
Screenshot: "Skärmdump"
|
||||
Scripts: "Skript"
|
||||
ScriptsDisabled: "Ladda ett spel för att nå skriptinställningar."
|
||||
|
@ -327,9 +327,33 @@
|
||||
<Property key="Caption" value="#{OMWEngine:WindowModeHint}"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="TextBox" skin="NormalText" position="0 238 352 18" align="Left Top" name="FovText">
|
||||
<Widget type="TextBox" skin="NormalText" position="0 258 352 18" align="Left Top" name="ResolutionScaleText">
|
||||
<Property key="Caption" value="#{OMWEngine:ResolutionScale}"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="0 262 352 18" align="HStretch Top">
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="0 282 352 18" align="HStretch Top">
|
||||
<Property key="Range" value="10000"/>
|
||||
<Property key="Page" value="100"/>
|
||||
<UserString key="SettingType" value="Slider"/>
|
||||
<UserString key="SettingCategory" value="Video"/>
|
||||
<UserString key="SettingName" value="resolution scale"/>
|
||||
<UserString key="SettingValueType" value="Float"/>
|
||||
<UserString key="SettingMin" value="0.1"/>
|
||||
<UserString key="SettingMax" value="1.0"/>
|
||||
<UserString key="SettingLabelWidget" value="ResolutionScaleText"/>
|
||||
<UserString key="SettingLabelCaption" value="#{OMWEngine:ResolutionScale} (%s)"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="0 306 352 18" align="Left Top">
|
||||
<Property key="Caption" value="10%"/>
|
||||
<Property key="TextAlign" value="Left"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="0 306 352 18" align="Right Top">
|
||||
<Property key="Caption" value="100%"/>
|
||||
<Property key="TextAlign" value="Right"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="TextBox" skin="NormalText" position="0 334 352 18" align="Left Top" name="FovText">
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="0 358 352 18" align="HStretch Top">
|
||||
<Property key="Range" value="81"/>
|
||||
<Property key="Page" value="1"/>
|
||||
<UserString key="SettingType" value="Slider"/>
|
||||
@ -341,18 +365,18 @@
|
||||
<UserString key="SettingLabelWidget" value="FovText"/>
|
||||
<UserString key="SettingLabelCaption" value="#{OMWEngine:FieldOfView} (%s)"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="0 286 352 18" align="Left Top">
|
||||
<Widget type="TextBox" skin="SandText" position="0 382 352 18" align="Left Top">
|
||||
<Property key="Caption" value="#{OMWEngine:FieldOfViewLow}"/>
|
||||
<Property key="TextAlign" value="Left"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="0 286 352 18" align="Right Top">
|
||||
<Widget type="TextBox" skin="SandText" position="0 382 352 18" align="Right Top">
|
||||
<Property key="Caption" value="#{OMWEngine:FieldOfViewHigh}"/>
|
||||
<Property key="TextAlign" value="Right"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="NormalText" position="0 308 352 18" align="Left Top" name="GammaText">
|
||||
<Widget type="TextBox" skin="NormalText" position="0 404 352 18" align="Left Top" name="GammaText">
|
||||
<Property key="Caption" value="#{OMWEngine:GammaCorrection}"/>
|
||||
</Widget>
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="0 332 352 18" align="HStretch Top" name="GammaSlider">
|
||||
<Widget type="ScrollBar" skin="MW_HScroll" position="0 428 352 18" align="HStretch Top" name="GammaSlider">
|
||||
<Property key="Range" value="10000"/>
|
||||
<Property key="Page" value="300"/>
|
||||
<UserString key="SettingType" value="Slider"/>
|
||||
@ -362,11 +386,11 @@
|
||||
<UserString key="SettingMin" value="0.1"/>
|
||||
<UserString key="SettingMax" value="3.0"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="0 356 352 18" align="Left Top" name="GammaTextDark">
|
||||
<Widget type="TextBox" skin="SandText" position="0 452 352 18" align="Left Top" name="GammaTextDark">
|
||||
<Property key="Caption" value="#{OMWEngine:GammaDark}"/>
|
||||
<Property key="TextAlign" value="Left"/>
|
||||
</Widget>
|
||||
<Widget type="TextBox" skin="SandText" position="0 356 352 18" align="Right Top" name="GammaTextLight">
|
||||
<Widget type="TextBox" skin="SandText" position="0 452 352 18" align="Right Top" name="GammaTextLight">
|
||||
<Property key="Caption" value="#{OMWEngine:GammaLight}"/>
|
||||
<Property key="TextAlign" value="Right"/>
|
||||
</Widget>
|
||||
|
@ -639,6 +639,9 @@ doppler factor = 0.25
|
||||
resolution x = 800
|
||||
resolution y = 600
|
||||
|
||||
# Resolution scaling
|
||||
resolution scale = 1.0
|
||||
|
||||
# Specify the window mode.
|
||||
# 0 = Fullscreen, 1 = Windowed Fullscreen, 2 = Windowed
|
||||
window mode = 2
|
||||
|
Loading…
x
Reference in New Issue
Block a user