From a73512afb73ec7b4a29ebcc07cd05f3db80cef02 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Feb 2016 17:08:18 +0100 Subject: [PATCH] Add shader settings to settings.cfg --- apps/openmw/mwrender/renderingmanager.cpp | 3 +++ components/resource/scenemanager.cpp | 21 +++++++++++++++ components/resource/scenemanager.hpp | 13 +++++++++ components/shader/shadervisitor.cpp | 32 ++++++++++++++++++++--- components/shader/shadervisitor.hpp | 17 ++++++++++++ files/settings-default.cfg | 21 +++++++++++++++ files/shaders/lighting.glsl | 9 ++++--- files/shaders/objects_fragment.glsl | 7 +++-- files/shaders/objects_vertex.glsl | 2 +- 9 files changed, 115 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6b5cf460c..dfc1743f0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -169,6 +169,9 @@ namespace MWRender { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); + resourceSystem->getSceneManager()->setForceShaders(Settings::Manager::getBool("force shaders", "Shaders")); + resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); + resourceSystem->getSceneManager()->setForcePerPixelLighting(Settings::Manager::getBool("force per pixel lighting", "Shaders")); osg::ref_ptr sceneRoot = new SceneUtil::LightManager; sceneRoot->setLightingMask(Mask_Lighting); diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index f4846a8a0..be0cd7dd7 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -209,6 +209,9 @@ namespace Resource SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) : ResourceManager(vfs) , mShaderManager(new Shader::ShaderManager) + , mForceShaders(false) + , mClampLighting(false) + , mForcePerPixelLighting(false) , mInstanceCache(new MultiObjectCache) , mImageManager(imageManager) , mNifFileManager(nifFileManager) @@ -220,6 +223,21 @@ namespace Resource { } + void SceneManager::setForceShaders(bool force) + { + mForceShaders = force; + } + + void SceneManager::setClampLighting(bool clamp) + { + mClampLighting = clamp; + } + + void SceneManager::setForcePerPixelLighting(bool force) + { + mForcePerPixelLighting = force; + } + SceneManager::~SceneManager() { // this has to be defined in the .cpp file as we can't delete incomplete types @@ -339,6 +357,9 @@ namespace Resource loaded->accept(setFilterSettingsControllerVisitor); Shader::ShaderVisitor shaderVisitor(*mShaderManager.get(), "objects_vertex.glsl", "objects_fragment.glsl"); + shaderVisitor.setForceShaders(mForceShaders); + shaderVisitor.setClampLighting(mClampLighting); + shaderVisitor.setForcePerPixelLighting(mForcePerPixelLighting); loaded->accept(shaderVisitor); // share state diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index d86c746d7..2ef9f614b 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -40,6 +40,15 @@ namespace Resource SceneManager(const VFS::Manager* vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager); ~SceneManager(); + /// @see ShaderVisitor::setForceShaders + void setForceShaders(bool force); + + /// @see ShaderVisitor::setClampLighting + void setClampLighting(bool clamp); + + /// @see ShaderVisitor::setForcePerPixelLighting + void setForcePerPixelLighting(bool force); + void setShaderPath(const std::string& path); /// Get a read-only copy of this scene "template" @@ -106,6 +115,10 @@ namespace Resource osg::ref_ptr createInstance(const std::string& name); std::auto_ptr mShaderManager; + bool mForceShaders; + bool mClampLighting; + bool mForcePerPixelLighting; + osg::ref_ptr mInstanceCache; OpenThreads::Mutex mSharedStateMutex; diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index a077cb09e..67362e0c6 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -16,7 +16,8 @@ namespace Shader { ShaderVisitor::ShaderRequirements::ShaderRequirements() - : mColorMaterial(false) + : mHasNormalMap(false) + , mColorMaterial(false) , mVertexColorMode(GL_AMBIENT_AND_DIFFUSE) , mTexStageRequiringTangents(-1) { @@ -24,6 +25,9 @@ namespace Shader ShaderVisitor::ShaderVisitor(ShaderManager& shaderManager, const std::string &defaultVsTemplate, const std::string &defaultFsTemplate) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , mForceShaders(false) + , mClampLighting(false) + , mForcePerPixelLighting(false) , mShaderManager(shaderManager) , mDefaultVsTemplate(defaultVsTemplate) , mDefaultFsTemplate(defaultFsTemplate) @@ -31,6 +35,21 @@ namespace Shader mRequirements.push_back(ShaderRequirements()); } + void ShaderVisitor::setForceShaders(bool force) + { + mForceShaders = force; + } + + void ShaderVisitor::setClampLighting(bool clamp) + { + mClampLighting = clamp; + } + + void ShaderVisitor::setForcePerPixelLighting(bool force) + { + mForcePerPixelLighting = force; + } + void ShaderVisitor::apply(osg::Node& node) { if (node.getStateSet()) @@ -61,6 +80,7 @@ namespace Shader if (texture->getName() == "normalMap") { mRequirements.back().mTexStageRequiringTangents = unit; + mRequirements.back().mHasNormalMap = true; // normal maps are by default off since the FFP can't render them, now that we'll use shaders switch to On stateset->setTextureMode(unit, GL_TEXTURE_2D, osg::StateAttribute::ON); } @@ -126,6 +146,9 @@ namespace Shader } } + defineMap["forcePPL"] = mForcePerPixelLighting ? "1" : "0"; + defineMap["clamp"] = mClampLighting ? "1" : "0"; + osg::ref_ptr vertexShader (mShaderManager.getShader(mDefaultVsTemplate, defineMap, osg::Shader::VERTEX)); osg::ref_ptr fragmentShader (mShaderManager.getShader(mDefaultFsTemplate, defineMap, osg::Shader::FRAGMENT)); @@ -161,7 +184,8 @@ namespace Shader } // TODO: find a better place for the stateset - createProgram(reqs, geometry.getOrCreateStateSet()); + if (reqs.mHasNormalMap || mForceShaders) + createProgram(reqs, geometry.getOrCreateStateSet()); } if (needPop) @@ -181,8 +205,10 @@ namespace Shader if (!mRequirements.empty()) { + const ShaderRequirements& reqs = mRequirements.back(); // TODO: find a better place for the stateset - createProgram(mRequirements.back(), drawable.getOrCreateStateSet()); + if (reqs.mHasNormalMap || mForceShaders) + createProgram(reqs, drawable.getOrCreateStateSet()); } if (needPop) diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index 507f1417e..fb29d503f 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -14,6 +14,17 @@ namespace Shader public: ShaderVisitor(ShaderManager& shaderManager, const std::string& defaultVsTemplate, const std::string& defaultFsTemplate); + /// By default, only bump mapped objects will have a shader added to them. + /// Setting force = true will cause all objects to render using shaders, regardless of having a bump map. + void setForceShaders(bool force); + + /// Set whether lighting is clamped for visual compatibility with the fixed function pipeline. + void setClampLighting(bool clamp); + + /// By default, only bump mapped objects use per-pixel lighting. + /// Setting force = true will cause all shaders to use per-pixel lighting, regardless of having a bump map. + void setForcePerPixelLighting(bool force); + virtual void apply(osg::Node& node); virtual void apply(osg::Drawable& drawable); @@ -25,6 +36,10 @@ namespace Shader void popRequirements(); private: + bool mForceShaders; + bool mClampLighting; + bool mForcePerPixelLighting; + ShaderManager& mShaderManager; struct ShaderRequirements @@ -34,6 +49,8 @@ namespace Shader // std::map mTextures; + bool mHasNormalMap; + bool mColorMaterial; // osg::Material::ColorMode int mVertexColorMode; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f6c5d29fc..e450f6518 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -157,6 +157,27 @@ texture min filter = linear # Texture mipmap type. (none, nearest, or linear). texture mipmap = nearest +[Shaders] + +# Force rendering with shaders. By default, only bump-mapped objects will use shaders. +# Enabling this option may cause slightly different visuals if the "clamp lighting" option +# is set to false. Otherwise, there should not be a visual difference. +force shaders = false + +# Force the use of per pixel lighting. By default, only bump mapped objects use per-pixel lighting. +# Has no effect if the 'force shaders' option is false. +# Enabling per-pixel lighting can result in visual differences to the original MW engine. It is not +# recommended to enable this option when using vanilla Morrowind files, because certain lights in Morrowind +# rely on vertex lighting to look as intended. +force per pixel lighting = false + +# Restrict the amount of lighting that an object can receive to a maximum of (1,1,1). +# Only affects objects that render with shaders (see 'force shaders' option). +# Setting this option to 'true' results in fixed-function compatible lighting, but the lighting +# may appear 'dull' and there might be color shifts. +# Setting this option to 'false' results in more realistic lighting. +clamp lighting = false + [Input] # Capture control of the cursor prevent movement outside the window. diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index f856bc6bd..d3c51d3cd 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -33,9 +33,10 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) lightResult.xyz += gl_FrontMaterial.emission.xyz; #endif - // TODO: make clamp configurable - // the following produces fixed-function compatible lighting, w/o clamp arguably looks better - //lightResult = clamp(lightResult, vec4(0.0, 0.0, 0.0, 0.0), vec4(1.0, 1.0, 1.0, 1.0)); - +#if @clamp + lightResult = clamp(lightResult, vec4(0.0, 0.0, 0.0, 0.0), vec4(1.0, 1.0, 1.0, 1.0)); +#else + lightResult = max(lightResult, 0.0); +#endif return lightResult; } diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 6346aa499..37c715e1a 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -28,7 +28,7 @@ varying vec3 viewTangent; varying float depth; -#define PER_PIXEL_LIGHTING @normalMap +#define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) #if !PER_PIXEL_LIGHTING varying vec4 lighting; @@ -56,8 +56,11 @@ void main() gl_FragData[0].xyz *= texture2D(darkMap, darkMapUV).xyz; #endif -#if @normalMap +#if PER_PIXEL_LIGHTING vec3 viewNormal = passViewNormal; +#endif + +#if @normalMap vec3 normalTex = texture2D(normalMap, normalMapUV).xyz; vec3 viewBinormal = cross(viewTangent, viewNormal); diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index 08fdb4ef8..940a2306e 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -23,7 +23,7 @@ varying vec3 viewTangent; varying float depth; -#define PER_PIXEL_LIGHTING @normalMap +#define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) #if !PER_PIXEL_LIGHTING varying vec4 lighting;