From dd473d06dffc3edc66e9311257a15da65ea4d048 Mon Sep 17 00:00:00 2001 From: Alexei Dobrohotov Date: Sat, 8 Jan 2022 05:53:10 +0300 Subject: [PATCH] Implement gloss-mapping (feature #6541) --- CHANGELOG.md | 1 + components/nifosg/nifloader.cpp | 17 ++++++++++------- components/shader/shadervisitor.cpp | 10 +++++++++- files/shaders/objects_fragment.glsl | 15 +++++++++++++-- files/shaders/objects_vertex.glsl | 8 ++++++++ 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ebd3b07e3..dd2ad0fd57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -132,6 +132,7 @@ Feature #6419: Topics shouldn't be greyed out if they can produce another topic reference Feature #6443: NiStencilProperty is not fully supported Feature #6534: Shader-based object texture blending + Feature #6541: Gloss-mapping Feature #6592: Missing support for NiTriShape particle emitters Feature #6600: Support NiSortAdjustNode Task #6201: Remove the "Note: No relevant classes found. No output generated" warnings diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 8e0a5c08ac..3007bc6cf2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1552,14 +1552,8 @@ namespace NifOsg case Nif::NiTexturingProperty::BumpTexture: case Nif::NiTexturingProperty::DetailTexture: case Nif::NiTexturingProperty::DecalTexture: - break; case Nif::NiTexturingProperty::GlossTexture: - { - // Not used by the vanilla engine. MCP (Morrowind Code Patch) adds an option to use Gloss maps: - // "- Gloss map fix. Morrowind removed gloss map entries from model files after loading them. This stops Morrowind from removing them." - // Log(Debug::Info) << "NiTexturingProperty::GlossTexture in " << mFilename << " not currently used."; - continue; - } + break; default: { Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; @@ -1651,6 +1645,12 @@ namespace NifOsg stateset->addUniform(new osg::Uniform("bumpMapMatrix", bumpMapMatrix)); stateset->addUniform(new osg::Uniform("envMapLumaBias", texprop->envMapLumaBias)); } + else if (i == Nif::NiTexturingProperty::GlossTexture) + { + // A gloss map is an environment map mask. + // Gloss maps are only implemented in the object shaders as well. + stateset->setTextureMode(texUnit, GL_TEXTURE_2D, osg::StateAttribute::OFF); + } else if (i == Nif::NiTexturingProperty::DecalTexture) { // This is only an inaccurate imitation of the original implementation, @@ -1694,6 +1694,9 @@ namespace NifOsg case Nif::NiTexturingProperty::DecalTexture: texture2d->setName("decalMap"); break; + case Nif::NiTexturingProperty::GlossTexture: + texture2d->setName("glossMap"); + break; default: break; } diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 107665369c..d8bbeeadc2 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -244,7 +244,7 @@ namespace Shader addedState->setName("addedState"); } - const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", "specularMap", "decalMap", "bumpMap" }; + const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", "specularMap", "decalMap", "bumpMap", "glossMap" }; bool isTextureNameRecognized(const std::string& name) { for (unsigned int i=0; isetTextureMode(unit, GL_TEXTURE_2D, osg::StateAttribute::ON); + } } else Log(Debug::Error) << "ShaderVisitor encountered unknown texture " << texture; diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 9b60e7c6a4..85950c7468 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -58,6 +58,11 @@ uniform vec2 envMapLumaBias; uniform mat2 bumpMapMatrix; #endif +#if @glossMap +uniform sampler2D glossMap; +varying vec2 glossMapUV; +#endif + uniform bool simpleWater; varying float euclideanDepth; @@ -168,8 +173,14 @@ void main() envLuma = clamp(bumpTex.b * envMapLumaBias.x + envMapLumaBias.y, 0.0, 1.0); #endif + vec3 envEffect = texture2D(envMap, envTexCoordGen).xyz * envMapColor.xyz * envLuma; + +#if @glossMap + envEffect *= texture2D(glossMap, glossMapUV).xyz; +#endif + #if @preLightEnv - gl_FragData[0].xyz += texture2D(envMap, envTexCoordGen).xyz * envMapColor.xyz * envLuma; + gl_FragData[0].xyz += envEffect; #endif #endif @@ -189,7 +200,7 @@ void main() gl_FragData[0].xyz *= lighting; #if @envMap && !@preLightEnv - gl_FragData[0].xyz += texture2D(envMap, envTexCoordGen).xyz * envMapColor.xyz * envLuma; + gl_FragData[0].xyz += envEffect; #endif #if @emissiveMap diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index 969fe5903e..77c7fef391 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -47,6 +47,10 @@ varying vec2 bumpMapUV; varying vec2 specularMapUV; #endif +#if @glossMap +varying vec2 glossMapUV; +#endif + varying float euclideanDepth; varying float linearDepth; @@ -120,6 +124,10 @@ void main(void) specularMapUV = (gl_TextureMatrix[@specularMapUV] * gl_MultiTexCoord@specularMapUV).xy; #endif +#if @glossMap + glossMapUV = (gl_TextureMatrix[@glossMapUV] * gl_MultiTexCoord@glossMapUV).xy; +#endif + passColor = gl_Color; passViewPos = viewPos.xyz; passNormal = gl_Normal.xyz;