From 0db7163363e634ba06806198ab3e4f1c5f467255 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 20 Feb 2016 19:54:47 +0100 Subject: [PATCH] Add specular mapping for terrain --- apps/openmw/mwrender/renderingmanager.cpp | 5 +++-- apps/openmw/mwrender/terrainstorage.cpp | 4 ++-- apps/openmw/mwrender/terrainstorage.hpp | 2 +- components/esmterrain/storage.cpp | 13 +++++++------ components/esmterrain/storage.hpp | 5 ++++- components/terrain/defs.hpp | 4 +++- components/terrain/material.cpp | 1 + components/terrain/material.hpp | 1 + components/terrain/terraingrid.cpp | 5 ++++- files/settings-default.cfg | 4 ++++ files/shaders/terrain_fragment.glsl | 19 ++++++++++++++----- files/shaders/terrain_vertex.glsl | 8 ++++---- 12 files changed, 48 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index dde283b68..57f784b2c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -197,8 +197,9 @@ namespace MWRender mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath)); mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), - new TerrainStorage(mResourceSystem->getVFS(), Settings::Manager::getString("normal map pattern", "Shaders"), Settings::Manager::getBool("auto use terrain normal maps", "Shaders")), - Mask_Terrain, &mResourceSystem->getSceneManager()->getShaderManager(), mUnrefQueue.get())); + new TerrainStorage(mResourceSystem->getVFS(), Settings::Manager::getString("normal map pattern", "Shaders"), Settings::Manager::getBool("auto use terrain normal maps", "Shaders"), + Settings::Manager::getString("terrain specular map pattern", "Shaders"), Settings::Manager::getBool("auto use terrain specular maps", "Shaders")), + Mask_Terrain, &mResourceSystem->getSceneManager()->getShaderManager(), mUnrefQueue.get())); mCamera.reset(new Camera(mViewer->getCamera())); diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index 8d4bf2ea2..cc1c3a0bc 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -9,8 +9,8 @@ namespace MWRender { - TerrainStorage::TerrainStorage(const VFS::Manager* vfs, const std::string& normalMapPattern, bool autoUseNormalMaps) - : ESMTerrain::Storage(vfs, normalMapPattern, autoUseNormalMaps) + TerrainStorage::TerrainStorage(const VFS::Manager* vfs, const std::string& normalMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps) + : ESMTerrain::Storage(vfs, normalMapPattern, autoUseNormalMaps, specularMapPattern, autoUseSpecularMaps) { } diff --git a/apps/openmw/mwrender/terrainstorage.hpp b/apps/openmw/mwrender/terrainstorage.hpp index 7bd4b4fd5..759c7dfcf 100644 --- a/apps/openmw/mwrender/terrainstorage.hpp +++ b/apps/openmw/mwrender/terrainstorage.hpp @@ -14,7 +14,7 @@ namespace MWRender virtual const ESM::LandTexture* getLandTexture(int index, short plugin); public: - TerrainStorage(const VFS::Manager* vfs, const std::string& normalMapPattern = "", bool autoUseNormalMaps = false); + TerrainStorage(const VFS::Manager* vfs, const std::string& normalMapPattern = "", bool autoUseNormalMaps = false, const std::string& specularMapPattern = "", bool autoUseSpecularMaps = false); /// Get bounds of the whole terrain in cell units virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 990102070..68b32cf2a 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -18,10 +18,12 @@ namespace ESMTerrain const float defaultHeight = -2048; - Storage::Storage(const VFS::Manager *vfs, const std::string& normalMapPattern, bool autoUseNormalMaps) + Storage::Storage(const VFS::Manager *vfs, const std::string& normalMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps) : mVFS(vfs) , mNormalMapPattern(normalMapPattern) , mAutoUseNormalMaps(autoUseNormalMaps) + , mSpecularMapPattern(specularMapPattern) + , mAutoUseSpecularMaps(autoUseSpecularMaps) { } @@ -510,7 +512,7 @@ namespace ESMTerrain return found->second; Terrain::LayerInfo info; - info.mParallax = false; + //info.mParallax = false; info.mSpecular = false; info.mDiffuseMap = texture; @@ -532,17 +534,16 @@ namespace ESMTerrain info.mNormalMap = texture_; } - /* + if (mAutoUseSpecularMaps) { std::string texture_ = texture; - boost::replace_last(texture_, ".", "_diffusespec."); + boost::replace_last(texture_, ".", mSpecularMapPattern + "."); if (mVFS->exists(texture_)) { info.mDiffuseMap = texture_; info.mSpecular = true; } } - */ mLayerInfoMap[texture] = info; @@ -553,7 +554,7 @@ namespace ESMTerrain { Terrain::LayerInfo info; info.mDiffuseMap = "textures\\_land_default.dds"; - info.mParallax = false; + //info.mParallax = false; info.mSpecular = false; return info; } diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 0c8095a11..7b8b844ff 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -27,7 +27,7 @@ namespace ESMTerrain virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; public: - Storage(const VFS::Manager* vfs, const std::string& normalMapPattern = "", bool autoUseNormalMaps = false); + Storage(const VFS::Manager* vfs, const std::string& normalMapPattern = "", bool autoUseNormalMaps = false, const std::string& specularMapPattern = "", bool autoUseSpecularMaps = false); /// Data is loaded first, if necessary. Will return a 0-pointer if there is no data for /// any of the data types specified via \a flags. Will also return a 0-pointer if there @@ -112,6 +112,9 @@ namespace ESMTerrain std::string mNormalMapPattern; bool mAutoUseNormalMaps; + std::string mSpecularMapPattern; + bool mAutoUseSpecularMaps; + Terrain::LayerInfo getLayerInfo(const std::string& texture); }; diff --git a/components/terrain/defs.hpp b/components/terrain/defs.hpp index 234e05a98..10095bec0 100644 --- a/components/terrain/defs.hpp +++ b/components/terrain/defs.hpp @@ -18,8 +18,10 @@ namespace Terrain { std::string mDiffuseMap; std::string mNormalMap; - bool mParallax; // Height info in normal map alpha channel? + //bool mParallax; // Height info in normal map alpha channel? bool mSpecular; // Specular info in diffuse map alpha channel? + + bool requiresShaders() const { return !mNormalMap.empty() || mSpecular; } }; } diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 54634d5d4..b9405ef86 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -129,6 +129,7 @@ namespace Terrain defineMap["normalMap"] = (it->mNormalMap) ? "1" : "0"; defineMap["blendMap"] = !firstLayer ? "1" : "0"; defineMap["colorMode"] = "2"; + defineMap["specularMap"] = it->mSpecular ? "1" : "0"; osg::ref_ptr vertexShader = shaderManager.getShader("terrain_vertex.glsl", defineMap, osg::Shader::VERTEX); osg::ref_ptr fragmentShader = shaderManager.getShader("terrain_fragment.glsl", defineMap, osg::Shader::FRAGMENT); diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index e353e5b3a..61d5724d7 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -23,6 +23,7 @@ namespace Terrain { osg::ref_ptr mDiffuseMap; osg::ref_ptr mNormalMap; // optional + bool mSpecular; }; class FixedFunctionTechnique : public osgFX::Technique diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index e008d5e52..31cac2e9b 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -162,6 +162,7 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu for (std::vector::const_iterator it = layerList.begin(); it != layerList.end(); ++it) { TextureLayer textureLayer; + textureLayer.mSpecular = it->mSpecular; osg::ref_ptr texture = mTextureCache[it->mDiffuseMap]; if (!texture) { @@ -187,9 +188,11 @@ osg::ref_ptr TerrainGrid::buildTerrain (osg::Group* parent, float chu } textureCompileDummy->getOrCreateStateSet()->setTextureAttributeAndModes(dummyTextureCounter++, texture); textureLayer.mNormalMap = texture; - useShaders = true; } + if (it->requiresShaders()) + useShaders = true; + layers.push_back(textureLayer); } } diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 98c33e834..1fd13ecd9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -189,6 +189,8 @@ auto use object specular maps = false # See 'auto use object normal maps'. Affects terrain. auto use terrain normal maps = false +# If a file with pattern 'terrain specular map pattern' exists, use that file as a 'diffuse specular' map. The texture +# must contain the layer color in the RGB channel (as usual), and a specular multiplier in the alpha channel. auto use terrain specular maps = false # The filename pattern to probe for when detecting normal maps (see 'auto use object normal maps', 'auto use terrain normal maps') @@ -196,6 +198,8 @@ normal map pattern = _n specular map pattern = _spec +terrain specular map pattern = _diffusespec + [Input] # Capture control of the cursor prevent movement outside the window. diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 3bfd16b0e..db43cbd3e 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -19,10 +19,10 @@ varying float depth; #if !PER_PIXEL_LIGHTING varying vec4 lighting; #else -varying vec3 passViewPos; -varying vec3 passViewNormal; varying vec4 passColor; #endif +varying vec3 passViewPos; +varying vec3 passViewNormal; #include "lighting.glsl" @@ -30,16 +30,15 @@ void main() { vec2 diffuseMapUV = (gl_TextureMatrix[0] * vec4(uv, 0.0, 1.0)).xy; - gl_FragData[0] = vec4(texture2D(diffuseMap, diffuseMapUV).xyz, 1.0); + vec4 diffuseTex = texture2D(diffuseMap, diffuseMapUV); + gl_FragData[0] = vec4(diffuseTex.xyz, 1.0); #if @blendMap vec2 blendMapUV = (gl_TextureMatrix[1] * vec4(uv, 0.0, 1.0)).xy; gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a; #endif -#if PER_PIXEL_LIGHTING vec3 viewNormal = passViewNormal; -#endif #if @normalMap vec3 normalTex = texture2D(normalMap, diffuseMapUV).xyz; @@ -59,6 +58,16 @@ void main() gl_FragData[0] *= doLighting(passViewPos, normalize(viewNormal), passColor); #endif +#if @specularMap + float shininess = 128; // TODO: make configurable + vec3 matSpec = vec3(diffuseTex.a, diffuseTex.a, diffuseTex.a); +#else + float shininess = gl_FrontMaterial.shininess; + vec3 matSpec = gl_FrontMaterial.specular.xyz; +#endif + + gl_FragData[0].xyz += getSpecular(normalize(viewNormal), normalize(passViewPos), shininess, matSpec); + float fogValue = clamp((depth - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue); } diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 43cb5d31b..46071d7f0 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -8,10 +8,10 @@ varying float depth; #if !PER_PIXEL_LIGHTING varying vec4 lighting; #else -varying vec3 passViewPos; -varying vec3 passViewNormal; varying vec4 passColor; #endif +varying vec3 passViewPos; +varying vec3 passViewNormal; #include "lighting.glsl" @@ -27,10 +27,10 @@ void main(void) #if !PER_PIXEL_LIGHTING lighting = doLighting(viewPos.xyz, viewNormal, gl_Color); #else - passViewPos = viewPos.xyz; - passViewNormal = viewNormal; passColor = gl_Color; #endif + passViewNormal = viewNormal; + passViewPos = viewPos.xyz; uv = gl_MultiTexCoord0.xy; }