Add terrain parallax mapping

move
scrawl 9 years ago
parent e381957105
commit 157c11398d

@ -174,6 +174,7 @@ namespace MWRender
resourceSystem->getSceneManager()->setForcePerPixelLighting(Settings::Manager::getBool("force per pixel lighting", "Shaders")); resourceSystem->getSceneManager()->setForcePerPixelLighting(Settings::Manager::getBool("force per pixel lighting", "Shaders"));
resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders")); resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders"));
resourceSystem->getSceneManager()->setNormalMapPattern(Settings::Manager::getString("normal map pattern", "Shaders")); resourceSystem->getSceneManager()->setNormalMapPattern(Settings::Manager::getString("normal map pattern", "Shaders"));
resourceSystem->getSceneManager()->setNormalHeightMapPattern(Settings::Manager::getString("normal height map pattern", "Shaders"));
resourceSystem->getSceneManager()->setAutoUseSpecularMaps(Settings::Manager::getBool("auto use object specular maps", "Shaders")); resourceSystem->getSceneManager()->setAutoUseSpecularMaps(Settings::Manager::getBool("auto use object specular maps", "Shaders"));
resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::Manager::getString("specular map pattern", "Shaders")); resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::Manager::getString("specular map pattern", "Shaders"));
@ -197,7 +198,8 @@ namespace MWRender
mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath)); mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath));
mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), 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"), new TerrainStorage(mResourceSystem->getVFS(), Settings::Manager::getString("normal map pattern", "Shaders"), Settings::Manager::getString("normal height 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")), Settings::Manager::getString("terrain specular map pattern", "Shaders"), Settings::Manager::getBool("auto use terrain specular maps", "Shaders")),
Mask_Terrain, &mResourceSystem->getSceneManager()->getShaderManager(), mUnrefQueue.get())); Mask_Terrain, &mResourceSystem->getSceneManager()->getShaderManager(), mUnrefQueue.get()));

@ -9,8 +9,8 @@
namespace MWRender namespace MWRender
{ {
TerrainStorage::TerrainStorage(const VFS::Manager* vfs, const std::string& normalMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps) TerrainStorage::TerrainStorage(const VFS::Manager* vfs, const std::string& normalMapPattern, const std::string& normalHeightMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps)
: ESMTerrain::Storage(vfs, normalMapPattern, autoUseNormalMaps, specularMapPattern, autoUseSpecularMaps) : ESMTerrain::Storage(vfs, normalMapPattern, normalHeightMapPattern, autoUseNormalMaps, specularMapPattern, autoUseSpecularMaps)
{ {
} }

@ -14,7 +14,7 @@ namespace MWRender
virtual const ESM::LandTexture* getLandTexture(int index, short plugin); virtual const ESM::LandTexture* getLandTexture(int index, short plugin);
public: public:
TerrainStorage(const VFS::Manager* vfs, const std::string& normalMapPattern = "", bool autoUseNormalMaps = false, const std::string& specularMapPattern = "", bool autoUseSpecularMaps = false); TerrainStorage(const VFS::Manager* vfs, const std::string& normalMapPattern = "", const std::string& normalHeightMapPatteern = "", bool autoUseNormalMaps = false, const std::string& specularMapPattern = "", bool autoUseSpecularMaps = false);
/// Get bounds of the whole terrain in cell units /// Get bounds of the whole terrain in cell units
virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY); virtual void getBounds(float& minX, float& maxX, float& minY, float& maxY);

@ -18,9 +18,10 @@ namespace ESMTerrain
const float defaultHeight = ESM::Land::DEFAULT_HEIGHT; const float defaultHeight = ESM::Land::DEFAULT_HEIGHT;
Storage::Storage(const VFS::Manager *vfs, const std::string& normalMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps) Storage::Storage(const VFS::Manager *vfs, const std::string& normalMapPattern, const std::string& normalHeightMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps)
: mVFS(vfs) : mVFS(vfs)
, mNormalMapPattern(normalMapPattern) , mNormalMapPattern(normalMapPattern)
, mNormalHeightMapPattern(normalHeightMapPattern)
, mAutoUseNormalMaps(autoUseNormalMaps) , mAutoUseNormalMaps(autoUseNormalMaps)
, mSpecularMapPattern(specularMapPattern) , mSpecularMapPattern(specularMapPattern)
, mAutoUseSpecularMaps(autoUseSpecularMaps) , mAutoUseSpecularMaps(autoUseSpecularMaps)
@ -512,26 +513,26 @@ namespace ESMTerrain
return found->second; return found->second;
Terrain::LayerInfo info; Terrain::LayerInfo info;
//info.mParallax = false; info.mParallax = false;
info.mSpecular = false; info.mSpecular = false;
info.mDiffuseMap = texture; info.mDiffuseMap = texture;
/*
std::string texture_ = texture;
boost::replace_last(texture_, ".", "_nh.");
if (mVFS->exists(texture_))
{
info.mNormalMap = texture_;
info.mParallax = true;
}
*/
if (mAutoUseNormalMaps) if (mAutoUseNormalMaps)
{ {
std::string texture_ = texture; std::string texture_ = texture;
boost::replace_last(texture_, ".", mNormalMapPattern + "."); boost::replace_last(texture_, ".", mNormalHeightMapPattern + ".");
if (mVFS->exists(texture_)) if (mVFS->exists(texture_))
{
info.mNormalMap = texture_; info.mNormalMap = texture_;
info.mParallax = true;
}
else
{
texture_ = texture;
boost::replace_last(texture_, ".", mNormalMapPattern + ".");
if (mVFS->exists(texture_))
info.mNormalMap = texture_;
}
} }
if (mAutoUseSpecularMaps) if (mAutoUseSpecularMaps)
@ -554,7 +555,7 @@ namespace ESMTerrain
{ {
Terrain::LayerInfo info; Terrain::LayerInfo info;
info.mDiffuseMap = "textures\\_land_default.dds"; info.mDiffuseMap = "textures\\_land_default.dds";
//info.mParallax = false; info.mParallax = false;
info.mSpecular = false; info.mSpecular = false;
return info; return info;
} }

@ -27,7 +27,7 @@ namespace ESMTerrain
virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0; virtual const ESM::LandTexture* getLandTexture(int index, short plugin) = 0;
public: public:
Storage(const VFS::Manager* vfs, const std::string& normalMapPattern = "", bool autoUseNormalMaps = false, const std::string& specularMapPattern = "", bool autoUseSpecularMaps = false); Storage(const VFS::Manager* vfs, const std::string& normalMapPattern = "", const std::string& normalHeightMapPattern = "", 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 /// 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 /// any of the data types specified via \a flags. Will also return a 0-pointer if there
@ -110,6 +110,7 @@ namespace ESMTerrain
OpenThreads::Mutex mLayerInfoMutex; OpenThreads::Mutex mLayerInfoMutex;
std::string mNormalMapPattern; std::string mNormalMapPattern;
std::string mNormalHeightMapPattern;
bool mAutoUseNormalMaps; bool mAutoUseNormalMaps;
std::string mSpecularMapPattern; std::string mSpecularMapPattern;

@ -241,6 +241,11 @@ namespace Resource
mNormalMapPattern = pattern; mNormalMapPattern = pattern;
} }
void SceneManager::setNormalHeightMapPattern(const std::string &pattern)
{
mNormalHeightMapPattern = pattern;
}
void SceneManager::setAutoUseSpecularMaps(bool use) void SceneManager::setAutoUseSpecularMaps(bool use)
{ {
mAutoUseSpecularMaps = use; mAutoUseSpecularMaps = use;

@ -63,6 +63,9 @@ namespace Resource
/// @see ShaderVisitor::setNormalMapPattern /// @see ShaderVisitor::setNormalMapPattern
void setNormalMapPattern(const std::string& pattern); void setNormalMapPattern(const std::string& pattern);
/// @see ShaderVisitor::setNormalHeightMapPattern
void setNormalHeightMapPattern(const std::string& pattern);
void setAutoUseSpecularMaps(bool use); void setAutoUseSpecularMaps(bool use);
void setSpecularMapPattern(const std::string& pattern); void setSpecularMapPattern(const std::string& pattern);
@ -138,6 +141,7 @@ namespace Resource
bool mForcePerPixelLighting; bool mForcePerPixelLighting;
bool mAutoUseNormalMaps; bool mAutoUseNormalMaps;
std::string mNormalMapPattern; std::string mNormalMapPattern;
std::string mNormalHeightMapPattern;
bool mAutoUseSpecularMaps; bool mAutoUseSpecularMaps;
std::string mSpecularMapPattern; std::string mSpecularMapPattern;

@ -18,7 +18,7 @@ namespace Terrain
{ {
std::string mDiffuseMap; std::string mDiffuseMap;
std::string mNormalMap; 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 mSpecular; // Specular info in diffuse map alpha channel?
bool requiresShaders() const { return !mNormalMap.empty() || mSpecular; } bool requiresShaders() const { return !mNormalMap.empty() || mSpecular; }

@ -157,6 +157,7 @@ namespace Terrain
defineMap["blendMap"] = !firstLayer ? "1" : "0"; defineMap["blendMap"] = !firstLayer ? "1" : "0";
defineMap["colorMode"] = "2"; defineMap["colorMode"] = "2";
defineMap["specularMap"] = it->mSpecular ? "1" : "0"; defineMap["specularMap"] = it->mSpecular ? "1" : "0";
defineMap["parallax"] = (it->mNormalMap && it->mParallax) ? "1" : "0";
osg::ref_ptr<osg::Shader> vertexShader = shaderManager.getShader("terrain_vertex.glsl", defineMap, osg::Shader::VERTEX); osg::ref_ptr<osg::Shader> vertexShader = shaderManager.getShader("terrain_vertex.glsl", defineMap, osg::Shader::VERTEX);
osg::ref_ptr<osg::Shader> fragmentShader = shaderManager.getShader("terrain_fragment.glsl", defineMap, osg::Shader::FRAGMENT); osg::ref_ptr<osg::Shader> fragmentShader = shaderManager.getShader("terrain_fragment.glsl", defineMap, osg::Shader::FRAGMENT);

@ -23,6 +23,7 @@ namespace Terrain
{ {
osg::ref_ptr<osg::Texture2D> mDiffuseMap; osg::ref_ptr<osg::Texture2D> mDiffuseMap;
osg::ref_ptr<osg::Texture2D> mNormalMap; // optional osg::ref_ptr<osg::Texture2D> mNormalMap; // optional
bool mParallax;
bool mSpecular; bool mSpecular;
}; };

@ -160,6 +160,7 @@ osg::ref_ptr<osg::Node> TerrainGrid::buildTerrain (osg::Group* parent, float chu
for (std::vector<LayerInfo>::const_iterator it = layerList.begin(); it != layerList.end(); ++it) for (std::vector<LayerInfo>::const_iterator it = layerList.begin(); it != layerList.end(); ++it)
{ {
TextureLayer textureLayer; TextureLayer textureLayer;
textureLayer.mParallax = it->mParallax;
textureLayer.mSpecular = it->mSpecular; textureLayer.mSpecular = it->mSpecular;
osg::ref_ptr<osg::Texture2D> texture = mTextureCache[it->mDiffuseMap]; osg::ref_ptr<osg::Texture2D> texture = mTextureCache[it->mDiffuseMap];
if (!texture) if (!texture)

@ -200,6 +200,10 @@ 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') # The filename pattern to probe for when detecting normal maps (see 'auto use object normal maps', 'auto use terrain normal maps')
normal map pattern = _n normal map pattern = _n
# Alternative filename pattern to probe for when detecting normal maps. Files with this pattern are expected to include 'height' in the alpha channel.
# This height is used for parallax effects. Works for both terrain and objects.
normal height map pattern = _nh
# The filename pattern to probe for when detecting object specular maps (see 'auto use object specular maps') # The filename pattern to probe for when detecting object specular maps (see 'auto use object specular maps')
specular map pattern = _spec specular map pattern = _spec

@ -22,35 +22,53 @@ varying vec4 lighting;
varying vec4 passColor; varying vec4 passColor;
#endif #endif
varying vec3 passViewPos; varying vec3 passViewPos;
varying vec3 passViewNormal; varying vec3 passNormal;
#if @parallax
#define PARALLAX_SCALE 0.04
#define PARALLAX_BIAS -0.02
uniform mat4 osg_ViewMatrixInverse;
#endif
#include "lighting.glsl" #include "lighting.glsl"
void main() void main()
{ {
vec2 diffuseMapUV = (gl_TextureMatrix[0] * vec4(uv, 0.0, 1.0)).xy; vec2 adjustedUV = (gl_TextureMatrix[0] * vec4(uv, 0.0, 1.0)).xy;
vec4 diffuseTex = texture2D(diffuseMap, diffuseMapUV); #if @normalMap
gl_FragData[0] = vec4(diffuseTex.xyz, 1.0); vec4 normalTex = texture2D(normalMap, adjustedUV);
#if @blendMap vec3 normalizedNormal = normalize(passNormal);
vec2 blendMapUV = (gl_TextureMatrix[1] * vec4(uv, 0.0, 1.0)).xy; vec3 tangent = vec3(1.0, 0.0, 0.0);
gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a; vec3 binormal = normalize(cross(tangent, normalizedNormal));
#endif tangent = normalize(cross(normalizedNormal, binormal)); // note, now we need to re-cross to derive tangent again because it wasn't orthonormal
mat3 tbn = mat3(tangent, binormal, normalizedNormal);
vec3 viewNormal = passViewNormal; vec3 viewNormal = normalize(gl_NormalMatrix * (tbn * (normalTex.xyz * 2.0 - 1.0)));
#else
vec3 viewNormal = normalize(gl_NormalMatrix * passNormal);
#endif
#if @normalMap #if @parallax
vec3 normalTex = texture2D(normalMap, diffuseMapUV).xyz; vec3 cameraPos = osg_ViewMatrixInverse[3].xyz;
vec3 eyeDir = normalize(cameraPos - (osg_ViewMatrixInverse * vec4(passViewPos, 1)).xyz);
vec3 TSeyeDir = normalize((vec4(normalize(tbn * eyeDir),0)).xyz);
vec3 viewTangent = (gl_ModelViewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz; adjustedUV += TSeyeDir.xy * ( normalTex.a * PARALLAX_SCALE + PARALLAX_BIAS );
vec3 viewBinormal = normalize(cross(viewTangent, viewNormal));
viewTangent = normalize(cross(viewNormal, viewBinormal)); // note, now we need to re-cross to derive tangent again because it wasn't orthonormal
mat3 tbn = mat3(viewTangent, viewBinormal, viewNormal);
viewNormal = normalize(tbn * (normalTex * 2.0 - 1.0)); // update normal using new coordinates
normalTex = texture2D(normalMap, adjustedUV);
viewNormal = normalize(gl_NormalMatrix * (tbn * (normalTex.xyz * 2.0 - 1.0)));
#endif #endif
vec4 diffuseTex = texture2D(diffuseMap, adjustedUV);
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 #if !PER_PIXEL_LIGHTING
gl_FragData[0] *= lighting; gl_FragData[0] *= lighting;

@ -11,7 +11,7 @@ varying vec4 lighting;
varying vec4 passColor; varying vec4 passColor;
#endif #endif
varying vec3 passViewPos; varying vec3 passViewPos;
varying vec3 passViewNormal; varying vec3 passNormal;
#include "lighting.glsl" #include "lighting.glsl"
@ -22,14 +22,14 @@ void main(void)
vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex); vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex);
gl_ClipVertex = viewPos; gl_ClipVertex = viewPos;
vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz);
#if !PER_PIXEL_LIGHTING #if !PER_PIXEL_LIGHTING
vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz);
lighting = doLighting(viewPos.xyz, viewNormal, gl_Color); lighting = doLighting(viewPos.xyz, viewNormal, gl_Color);
#else #else
passColor = gl_Color; passColor = gl_Color;
#endif #endif
passViewNormal = viewNormal; passNormal = gl_Normal.xyz;
passViewPos = viewPos.xyz; passViewPos = viewPos.xyz;
uv = gl_MultiTexCoord0.xy; uv = gl_MultiTexCoord0.xy;

Loading…
Cancel
Save