Add specular mapping for objects

move
scrawl 9 years ago
parent 5cf2441b10
commit f01e8a6950

@ -174,6 +174,8 @@ 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()->setAutoUseSpecularMaps(Settings::Manager::getBool("auto use object specular maps", "Shaders"));
resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::Manager::getString("specular map pattern", "Shaders"));
osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager; osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager;
sceneRoot->setLightingMask(Mask_Lighting); sceneRoot->setLightingMask(Mask_Lighting);
@ -340,7 +342,9 @@ namespace MWRender
{ {
setAmbientColour(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); setAmbientColour(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient));
mSunLight->setDiffuse(SceneUtil::colourFromRGB(cell->mAmbi.mSunlight)); osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight);
mSunLight->setDiffuse(diffuse);
mSunLight->setSpecular(diffuse);
mSunLight->setDirection(osg::Vec3f(1.f,-1.f,-1.f)); mSunLight->setDirection(osg::Vec3f(1.f,-1.f,-1.f));
} }

@ -274,6 +274,16 @@ namespace Resource
mNormalMapPattern = pattern; mNormalMapPattern = pattern;
} }
void SceneManager::setAutoUseSpecularMaps(bool use)
{
mAutoUseSpecularMaps = use;
}
void SceneManager::setSpecularMapPattern(const std::string &pattern)
{
mSpecularMapPattern = pattern;
}
SceneManager::~SceneManager() SceneManager::~SceneManager()
{ {
// this has to be defined in the .cpp file as we can't delete incomplete types // this has to be defined in the .cpp file as we can't delete incomplete types
@ -403,6 +413,8 @@ namespace Resource
shaderVisitor.setForcePerPixelLighting(mForcePerPixelLighting); shaderVisitor.setForcePerPixelLighting(mForcePerPixelLighting);
shaderVisitor.setAutoUseNormalMaps(mAutoUseNormalMaps); shaderVisitor.setAutoUseNormalMaps(mAutoUseNormalMaps);
shaderVisitor.setNormalMapPattern(mNormalMapPattern); shaderVisitor.setNormalMapPattern(mNormalMapPattern);
shaderVisitor.setAutoUseSpecularMaps(mAutoUseSpecularMaps);
shaderVisitor.setSpecularMapPattern(mSpecularMapPattern);
loaded->accept(shaderVisitor); loaded->accept(shaderVisitor);
// share state // share state

@ -63,6 +63,10 @@ namespace Resource
/// @see ShaderVisitor::setNormalMapPattern /// @see ShaderVisitor::setNormalMapPattern
void setNormalMapPattern(const std::string& pattern); void setNormalMapPattern(const std::string& pattern);
void setAutoUseSpecularMaps(bool use);
void setSpecularMapPattern(const std::string& pattern);
void setShaderPath(const std::string& path); void setShaderPath(const std::string& path);
/// Get a read-only copy of this scene "template" /// Get a read-only copy of this scene "template"
@ -134,6 +138,8 @@ namespace Resource
bool mForcePerPixelLighting; bool mForcePerPixelLighting;
bool mAutoUseNormalMaps; bool mAutoUseNormalMaps;
std::string mNormalMapPattern; std::string mNormalMapPattern;
bool mAutoUseSpecularMaps;
std::string mSpecularMapPattern;
osg::ref_ptr<MultiObjectCache> mInstanceCache; osg::ref_ptr<MultiObjectCache> mInstanceCache;

@ -21,7 +21,7 @@ namespace Shader
{ {
ShaderVisitor::ShaderRequirements::ShaderRequirements() ShaderVisitor::ShaderRequirements::ShaderRequirements()
: mHasNormalMap(false) : mShaderRequired(false)
, mColorMaterial(false) , mColorMaterial(false)
, mVertexColorMode(GL_AMBIENT_AND_DIFFUSE) , mVertexColorMode(GL_AMBIENT_AND_DIFFUSE)
, mMaterialOverridden(false) , mMaterialOverridden(false)
@ -41,6 +41,7 @@ namespace Shader
, mForcePerPixelLighting(false) , mForcePerPixelLighting(false)
, mAllowedToModifyStateSets(true) , mAllowedToModifyStateSets(true)
, mAutoUseNormalMaps(false) , mAutoUseNormalMaps(false)
, mAutoUseSpecularMaps(false)
, mShaderManager(shaderManager) , mShaderManager(shaderManager)
, mImageManager(imageManager) , mImageManager(imageManager)
, mDefaultVsTemplate(defaultVsTemplate) , mDefaultVsTemplate(defaultVsTemplate)
@ -97,6 +98,7 @@ namespace Shader
{ {
const osg::Texture* diffuseMap = NULL; const osg::Texture* diffuseMap = NULL;
const osg::Texture* normalMap = NULL; const osg::Texture* normalMap = NULL;
const osg::Texture* specularMap = NULL;
for(unsigned int unit=0;unit<texAttributes.size();++unit) for(unsigned int unit=0;unit<texAttributes.size();++unit)
{ {
const osg::StateAttribute *attr = stateset->getTextureAttribute(unit, osg::StateAttribute::TEXTURE); const osg::StateAttribute *attr = stateset->getTextureAttribute(unit, osg::StateAttribute::TEXTURE);
@ -111,7 +113,7 @@ namespace Shader
if (texture->getName() == "normalMap") if (texture->getName() == "normalMap")
{ {
mRequirements.back().mTexStageRequiringTangents = unit; mRequirements.back().mTexStageRequiringTangents = unit;
mRequirements.back().mHasNormalMap = true; mRequirements.back().mShaderRequired = true;
if (!writableStateSet) if (!writableStateSet)
writableStateSet = getWritableStateSet(node); writableStateSet = getWritableStateSet(node);
// normal maps are by default off since the FFP can't render them, now that we'll use shaders switch to On // normal maps are by default off since the FFP can't render them, now that we'll use shaders switch to On
@ -120,6 +122,8 @@ namespace Shader
} }
if (texture->getName() == "diffuseMap") if (texture->getName() == "diffuseMap")
diffuseMap = texture; diffuseMap = texture;
if (texture->getName() == "specularMap")
specularMap = texture;
} }
else else
std::cerr << "ShaderVisitor encountered unknown texture " << texture << std::endl; std::cerr << "ShaderVisitor encountered unknown texture " << texture << std::endl;
@ -154,7 +158,30 @@ namespace Shader
writableStateSet->setTextureAttributeAndModes(unit, normalMapTex, osg::StateAttribute::ON); writableStateSet->setTextureAttributeAndModes(unit, normalMapTex, osg::StateAttribute::ON);
mRequirements.back().mTextures[unit] = "normalMap"; mRequirements.back().mTextures[unit] = "normalMap";
mRequirements.back().mTexStageRequiringTangents = unit; mRequirements.back().mTexStageRequiringTangents = unit;
mRequirements.back().mHasNormalMap = true; mRequirements.back().mShaderRequired = true;
}
}
if (mAutoUseSpecularMaps && diffuseMap != NULL && specularMap == NULL)
{
std::string specularMap = diffuseMap->getImage(0)->getFileName();
boost::replace_last(specularMap, ".", mSpecularMapPattern + ".");
if (mImageManager.getVFS()->exists(specularMap))
{
std::cout << "using specmap " << specularMap << std::endl;
osg::ref_ptr<osg::Texture2D> specularMapTex (new osg::Texture2D(mImageManager.getImage(specularMap)));
specularMapTex->setWrap(osg::Texture::WRAP_S, diffuseMap->getWrap(osg::Texture::WRAP_S));
specularMapTex->setWrap(osg::Texture::WRAP_T, diffuseMap->getWrap(osg::Texture::WRAP_T));
specularMapTex->setFilter(osg::Texture::MIN_FILTER, diffuseMap->getFilter(osg::Texture::MIN_FILTER));
specularMapTex->setFilter(osg::Texture::MAG_FILTER, diffuseMap->getFilter(osg::Texture::MAG_FILTER));
specularMapTex->setMaxAnisotropy(diffuseMap->getMaxAnisotropy());
specularMapTex->setName("specularMap");
int unit = texAttributes.size();
if (!writableStateSet)
writableStateSet = getWritableStateSet(node);
writableStateSet->setTextureAttributeAndModes(unit, specularMapTex, osg::StateAttribute::ON);
mRequirements.back().mTextures[unit] = "specularMap";
mRequirements.back().mShaderRequired = true;
} }
} }
} }
@ -196,7 +223,7 @@ namespace Shader
writableStateSet = getWritableStateSet(node); writableStateSet = getWritableStateSet(node);
ShaderManager::DefineMap defineMap; ShaderManager::DefineMap defineMap;
const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap" }; const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", "specularMap" };
for (unsigned int i=0; i<sizeof(defaultTextures)/sizeof(defaultTextures[0]); ++i) for (unsigned int i=0; i<sizeof(defaultTextures)/sizeof(defaultTextures[0]); ++i)
{ {
defineMap[defaultTextures[i]] = "0"; defineMap[defaultTextures[i]] = "0";
@ -253,12 +280,19 @@ namespace Shader
if (!mRequirements.empty()) if (!mRequirements.empty())
{ {
const ShaderRequirements& reqs = mRequirements.back(); const ShaderRequirements& reqs = mRequirements.back();
if (reqs.mTexStageRequiringTangents != -1 && mAllowedToModifyStateSets)
if (mAllowedToModifyStateSets)
{ {
if (geometry.getTexCoordArray(reqs.mTexStageRequiringTangents) == NULL) // assign tex coord array for normal map if necessary // make sure that all UV sets are there
// the normal-map may be assigned on-the-fly in applyStateSet() when mAutoUseNormalMaps is true for (std::map<int, std::string>::const_iterator it = reqs.mTextures.begin(); it != reqs.mTextures.end(); ++it)
geometry.setTexCoordArray(reqs.mTexStageRequiringTangents, geometry.getTexCoordArray(0)); {
if (geometry.getTexCoordArray(it->first) == NULL)
geometry.setTexCoordArray(it->first, geometry.getTexCoordArray(0));
}
}
if (reqs.mTexStageRequiringTangents != -1 && mAllowedToModifyStateSets)
{
osg::ref_ptr<osgUtil::TangentSpaceGenerator> generator (new osgUtil::TangentSpaceGenerator); osg::ref_ptr<osgUtil::TangentSpaceGenerator> generator (new osgUtil::TangentSpaceGenerator);
generator->generate(&geometry, reqs.mTexStageRequiringTangents); generator->generate(&geometry, reqs.mTexStageRequiringTangents);
@ -266,7 +300,7 @@ namespace Shader
} }
// TODO: find a better place for the stateset // TODO: find a better place for the stateset
if (reqs.mHasNormalMap || mForceShaders) if (reqs.mShaderRequired || mForceShaders)
createProgram(reqs, geometry); createProgram(reqs, geometry);
} }
@ -289,7 +323,7 @@ namespace Shader
{ {
const ShaderRequirements& reqs = mRequirements.back(); const ShaderRequirements& reqs = mRequirements.back();
// TODO: find a better place for the stateset // TODO: find a better place for the stateset
if (reqs.mHasNormalMap || mForceShaders) if (reqs.mShaderRequired || mForceShaders)
createProgram(reqs, drawable); createProgram(reqs, drawable);
} }
@ -312,4 +346,14 @@ namespace Shader
mNormalMapPattern = pattern; mNormalMapPattern = pattern;
} }
void ShaderVisitor::setAutoUseSpecularMaps(bool use)
{
mAutoUseSpecularMaps = use;
}
void ShaderVisitor::setSpecularMapPattern(const std::string &pattern)
{
mSpecularMapPattern = pattern;
}
} }

@ -40,6 +40,10 @@ namespace Shader
void setNormalMapPattern(const std::string& pattern); void setNormalMapPattern(const std::string& pattern);
void setAutoUseSpecularMaps(bool use);
void setSpecularMapPattern(const std::string& pattern);
virtual void apply(osg::Node& node); virtual void apply(osg::Node& node);
virtual void apply(osg::Drawable& drawable); virtual void apply(osg::Drawable& drawable);
@ -59,6 +63,9 @@ namespace Shader
bool mAutoUseNormalMaps; bool mAutoUseNormalMaps;
std::string mNormalMapPattern; std::string mNormalMapPattern;
bool mAutoUseSpecularMaps;
std::string mSpecularMapPattern;
ShaderManager& mShaderManager; ShaderManager& mShaderManager;
Resource::ImageManager& mImageManager; Resource::ImageManager& mImageManager;
@ -72,7 +79,7 @@ namespace Shader
osg::ref_ptr<osg::Texture> mDiffuseMap; osg::ref_ptr<osg::Texture> mDiffuseMap;
bool mHasNormalMap; bool mShaderRequired;
bool mColorMaterial; bool mColorMaterial;
// osg::Material::ColorMode // osg::Material::ColorMode

@ -184,12 +184,18 @@ clamp lighting = true
# Affects objects. # Affects objects.
auto use object normal maps = false auto use object normal maps = false
auto use object specular maps = false
# See 'auto use object normal maps'. Affects terrain. # See 'auto use object normal maps'. Affects terrain.
auto use terrain normal maps = false auto use terrain normal maps = false
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
specular map pattern = _spec
[Input] [Input]
# Capture control of the cursor prevent movement outside the window. # Capture control of the cursor prevent movement outside the window.

@ -40,3 +40,14 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor)
#endif #endif
return lightResult; return lightResult;
} }
vec3 getSpecular(vec3 viewNormal, vec3 viewPos, float shininess, vec3 matSpec)
{
vec3 lightDir = normalize(gl_LightSource[0].position.xyz);
float NdotL = max(dot(viewNormal, lightDir), 0.0);
if (NdotL < 0)
return vec3(0,0,0);
vec3 halfVec = normalize(lightDir - viewPos);
return pow(max(dot(viewNormal, halfVec), 0.0), 128) * gl_LightSource[0].specular.xyz * matSpec;
}

@ -32,6 +32,11 @@ varying vec2 envMapUV;
uniform vec4 envMapColor; uniform vec4 envMapColor;
#endif #endif
#if @specularMap
uniform sampler2D specularMap;
varying vec2 specularMapUV;
#endif
varying float depth; varying float depth;
#define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) #define PER_PIXEL_LIGHTING (@normalMap || @forcePPL)
@ -39,10 +44,10 @@ varying float depth;
#if !PER_PIXEL_LIGHTING #if !PER_PIXEL_LIGHTING
varying vec4 lighting; varying vec4 lighting;
#else #else
varying vec3 passViewPos;
varying vec3 passViewNormal;
varying vec4 passColor; varying vec4 passColor;
#endif #endif
varying vec3 passViewPos;
varying vec3 passViewNormal;
#include "lighting.glsl" #include "lighting.glsl"
@ -62,9 +67,7 @@ void main()
gl_FragData[0].xyz *= texture2D(darkMap, darkMapUV).xyz; gl_FragData[0].xyz *= texture2D(darkMap, darkMapUV).xyz;
#endif #endif
#if PER_PIXEL_LIGHTING
vec3 viewNormal = passViewNormal; vec3 viewNormal = passViewNormal;
#endif
#if @normalMap #if @normalMap
vec3 normalTex = texture2D(normalMap, normalMapUV).xyz; vec3 normalTex = texture2D(normalMap, normalMapUV).xyz;
@ -90,6 +93,17 @@ void main()
gl_FragData[0].xyz += texture2D(envMap, envMapUV).xyz * envMapColor.xyz; gl_FragData[0].xyz += texture2D(envMap, envMapUV).xyz * envMapColor.xyz;
#endif #endif
#if @specularMap
vec4 specTex = texture2D(specularMap, specularMapUV);
float shininess = specTex.a * 255;
vec3 matSpec = specTex.xyz;
#else
float shininess = gl_FrontMaterial.shininess;
vec3 matSpec = gl_FrontMaterial.specular.xyz;
#endif
gl_FragData[0].xyz += getSpecular(normalize(viewNormal), normalize(passViewPos.xyz), shininess, matSpec);
float fogValue = clamp((depth - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); 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); gl_FragData[0].xyz = mix(gl_FragData[0].xyz, gl_Fog.color.xyz, fogValue);
} }

@ -25,6 +25,10 @@ varying vec3 viewTangent;
varying vec2 envMapUV; varying vec2 envMapUV;
#endif #endif
#if @specularMap
varying vec2 specularMapUV;
#endif
varying float depth; varying float depth;
#define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) #define PER_PIXEL_LIGHTING (@normalMap || @forcePPL)
@ -32,10 +36,10 @@ varying float depth;
#if !PER_PIXEL_LIGHTING #if !PER_PIXEL_LIGHTING
varying vec4 lighting; varying vec4 lighting;
#else #else
varying vec3 passViewPos;
varying vec3 passViewNormal;
varying vec4 passColor; varying vec4 passColor;
#endif #endif
varying vec3 passViewPos;
varying vec3 passViewNormal;
#include "lighting.glsl" #include "lighting.glsl"
@ -76,11 +80,15 @@ void main(void)
viewTangent = normalize(gl_NormalMatrix * gl_MultiTexCoord7.xyz); viewTangent = normalize(gl_NormalMatrix * gl_MultiTexCoord7.xyz);
#endif #endif
#if @specularMap
specularMapUV = (gl_TextureMatrix[@specularMapUV] * gl_MultiTexCoord@specularMapUV).xy;
#endif
#if !PER_PIXEL_LIGHTING #if !PER_PIXEL_LIGHTING
lighting = doLighting(viewPos.xyz, viewNormal, gl_Color); lighting = doLighting(viewPos.xyz, viewNormal, gl_Color);
#else #else
passViewPos = viewPos.xyz;
passViewNormal = viewNormal;
passColor = gl_Color; passColor = gl_Color;
#endif #endif
passViewPos = viewPos.xyz;
passViewNormal = viewNormal;
} }

Loading…
Cancel
Save