From 6999f1fd28e4bfba2ae7a17a384e59cf346fdfdd Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 3 Mar 2020 20:08:59 +0300 Subject: [PATCH] Add an option to apply lighting to environment maps --- apps/opencs/model/world/data.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 1 + components/nifosg/nifloader.cpp | 28 +++++++++-- .../reference/modding/settings/shaders.rst | 11 +++++ .../convert-bump-mapped-mods.rst | 19 ++++--- files/settings-default.cfg | 4 ++ files/shaders/objects_fragment.glsl | 49 +++++++++++-------- 7 files changed, 81 insertions(+), 32 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 0753569bf..f609e6999 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -81,6 +81,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat Shader::ShaderManager::DefineMap shadowDefines = SceneUtil::ShadowManager::getShadowsDisabledDefines(); defines["forcePPL"] = "0"; defines["clamp"] = "1"; + defines["preLightEnv"] = "0"; for (const auto& define : shadowDefines) defines[define.first] = define.second; mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1f53ff3d6..dd570f558 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -253,6 +253,7 @@ namespace MWRender globalDefines["forcePPL"] = Settings::Manager::getBool("force per pixel lighting", "Shaders") ? "1" : "0"; globalDefines["clamp"] = Settings::Manager::getBool("clamp lighting", "Shaders") ? "1" : "0"; + globalDefines["preLightEnv"] = Settings::Manager::getBool("apply lighting to environment maps", "Shaders") ? "1" : "0"; // It is unnecessary to stop/start the viewer as no frames are being rendered yet. mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 644e82484..91232d03a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include "particle.hpp" #include "userdata.hpp" @@ -427,12 +428,29 @@ namespace NifOsg texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE); texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP_TO_EDGE); + static const bool preLightEnv = Settings::Manager::getBool("apply lighting to environment maps", "Shaders"); osg::ref_ptr texEnv = new osg::TexEnvCombine; - texEnv->setCombine_Alpha(osg::TexEnvCombine::REPLACE); - texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); - texEnv->setCombine_RGB(osg::TexEnvCombine::ADD); - texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); - texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + if (!preLightEnv) + { + texEnv->setCombine_Alpha(osg::TexEnvCombine::REPLACE); + texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnv->setCombine_RGB(osg::TexEnvCombine::ADD); + texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); + } + else + { + texEnv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); + texEnv->setSource0_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); + texEnv->setSource1_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); + texEnv->setSource2_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA); + texEnv->setCombine_Alpha(osg::TexEnvCombine::REPLACE); + texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); + } int texUnit = 3; // FIXME diff --git a/docs/source/reference/modding/settings/shaders.rst b/docs/source/reference/modding/settings/shaders.rst index b36f64285..8f1040225 100644 --- a/docs/source/reference/modding/settings/shaders.rst +++ b/docs/source/reference/modding/settings/shaders.rst @@ -124,3 +124,14 @@ terrain specular map pattern :Default: _diffusespec The filename pattern to probe for when detecting terrain specular maps (see 'auto use terrain specular maps') + +apply lighting to environment maps +---------------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Normally environment map reflections aren't affected by lighting, which makes environment-mapped (and thus bump-mapped objects) glow in the dark. +Morrowind Code Patch includes an option to remedy that by doing environment-mapping before applying lighting, this is the equivalent of that option. +This also affects fixed function pipeline rendering. diff --git a/docs/source/reference/modding/texture-modding/convert-bump-mapped-mods.rst b/docs/source/reference/modding/texture-modding/convert-bump-mapped-mods.rst index 5a77e81ce..0ad35d7a5 100644 --- a/docs/source/reference/modding/texture-modding/convert-bump-mapped-mods.rst +++ b/docs/source/reference/modding/texture-modding/convert-bump-mapped-mods.rst @@ -75,13 +75,18 @@ Morrowind bump-mapping **Conversion difficulty:** *Varies. Sometimes quick and easy, sometimes time-consuming and hard.* -You might have bumped (pun intended) on a few bump-mapped texture packs for Morrowind that require the -Morrowind Code Patch (MCP). OpenMW does support the legacy bump-maps, -but bump-mapped models may look brighter than intended if they were designed with Morrowind Code Patch in mind -because MCP can optionally apply lighting after environment maps are processed which makes bump-mapped models look a bit better, -and can make use of the gloss map channel in the bump map. It also makes skinned mesh bump-mapping possible. -We chose not to replicate the difference in environment map handling, but gloss map channel as well as skinned mesh bump-mapping are supported. +You might have bumped (pun intended) on a few bump-mapped texture packs for Morrowind that require +Morrowind Code Patch (MCP). OpenMW supports them, and like MCP can optionally apply lighting after environment maps +are processed which makes bump-mapped models look a bit better, +can make use of the gloss map channel in the bump map and can apply bump-mapping to skinned models. +Add this to settings.cfg_-file: +:: + + [Shaders] + apply lighting to environment maps = true + +But sometimes you may want them to look a bit better than in vanilla. Technically you aren't supposed to convert bump maps because they shouldn't be normal maps that are supported by OpenMW as well, but artists may use actual normal maps as bump maps either because they look better in vanilla... or because they're lazy. In this case you can benefit from OpenMW's normal-mapping support by using these bump maps the way normal maps are used. @@ -203,7 +208,7 @@ Since we want the glory of normal-mapping in our OpenMW setup, we will go with t #. Start by downloading Apel's `Various Things - Sacks`_ from Nexus. #. Once downloaded, install it the way you'd normally install your mods (**Pro tip**: Install using OpenMW's `Multiple data folders`_ function!). -#. Now, if you ran the mod right away, your sacks may look... wetter than expected. This is because the mod assumes you have the MCP feature which makes the sacks less shiny enabled. Which you can't have enabled. +#. Now, if you ran the mod right away, your sacks may look... wetter than expected. This is because the mod assumes you have the MCP feature which makes the sacks less shiny enabled. You can have its equivalent enabled to make the sacks look like in Morrowind with MCP, or you may proceed on the tutorial. #. We need to fix this by removing some tags in the model files. You need to download NifSkope_ for this, which, again, only have binaries available for Windows. #. Go the place where you installed the mod and go to ``./Meshes/o/`` to find the model files. - If you installed the mod like I suggested, finding the files will be easy as a pie, but if you installed it by dropping everything into your main Morrowind Data Files folder, then you'll have to scroll a lot to find them. Check the mod's zip file for the file names of the models if this is the case. The same thing applies to when fixing the textures. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d3458d293..b7e0eb6c2 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -346,6 +346,10 @@ specular map pattern = _spec # The filename pattern to probe for when detecting terrain specular maps (see 'auto use terrain specular maps') terrain specular map pattern = _diffusespec +# Apply lighting to environment map reflections on the rendered objects like in Morrowind Code Patch. +# Also affects fixed function pipeline. +apply lighting to environment maps = false + [Input] # Capture control of the cursor prevent movement outside the window. diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index f6f3bc792..a222d9c7b 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -119,6 +119,31 @@ void main() #if @decalMap vec4 decalTex = texture2D(decalMap, decalMapUV); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a); +#endif + +#if @envMap + + vec2 envTexCoordGen = envMapUV; + float envLuma = 1.0; + +#if @normalMap + // if using normal map + env map, take advantage of per-pixel normals for envTexCoordGen + vec3 viewVec = normalize(passViewPos.xyz); + vec3 r = reflect( viewVec, viewNormal ); + float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) ); + envTexCoordGen = vec2(r.x/m + 0.5, r.y/m + 0.5); +#endif + +#if @bumpMap + vec4 bumpTex = texture2D(bumpMap, bumpMapUV); + envTexCoordGen += bumpTex.rg * bumpMapMatrix; + envLuma = clamp(bumpTex.b * envMapLumaBias.x + envMapLumaBias.y, 0.0, 1.0); +#endif + +#if @preLightEnv + gl_FragData[0].xyz += texture2D(envMap, envTexCoordGen).xyz * envMapColor.xyz * envLuma; +#endif + #endif float shadowing = unshadowedLightRatio(depth); @@ -135,30 +160,14 @@ void main() gl_FragData[0] *= doLighting(passViewPos, normalize(viewNormal), passColor, shadowing); #endif +#if @envMap && !@preLightEnv + gl_FragData[0].xyz += texture2D(envMap, envTexCoordGen).xyz * envMapColor.xyz * envLuma; +#endif + #if @emissiveMap gl_FragData[0].xyz += texture2D(emissiveMap, emissiveMapUV).xyz; #endif -#if @envMap - vec2 texCoordGen = envMapUV; - float envLuma = 1.0; - -#if @normalMap - // if using normal map + env map, take advantage of per-pixel normals for texCoordGen - vec3 viewVec = normalize(passViewPos.xyz); - vec3 r = reflect( viewVec, viewNormal ); - float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) ); - texCoordGen = vec2(r.x/m + 0.5, r.y/m + 0.5); -#endif - -#if @bumpMap - vec4 bumpTex = texture2D(bumpMap, bumpMapUV); - texCoordGen += bumpTex.rg * bumpMapMatrix; - envLuma = clamp(bumpTex.b * envMapLumaBias.x + envMapLumaBias.y, 0.0, 1.0); -#endif - gl_FragData[0].xyz += texture2D(envMap, texCoordGen).xyz * envMapColor.xyz * envLuma; -#endif - #if @specularMap vec4 specTex = texture2D(specularMap, specularMapUV); float shininess = specTex.a * 255;