From 58afe1ba23fe7c0fafd4e163fedf161ffd6bf9a1 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 23 Mar 2024 19:46:31 +0300 Subject: [PATCH] Support red-green normal maps --- apps/opencs/model/world/data.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 1 + components/resource/imagemanager.cpp | 3 +-- components/shader/shadervisitor.cpp | 20 ++++++++++++++++++++ components/shader/shadervisitor.hpp | 1 + files/shaders/compatibility/bs/default.frag | 3 +++ files/shaders/compatibility/groundcover.frag | 6 +++++- files/shaders/compatibility/objects.frag | 6 +++++- files/shaders/compatibility/terrain.frag | 6 +++++- 9 files changed, 42 insertions(+), 5 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 470ce04131..4198e1b980 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -152,6 +152,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data mResourceSystem = std::make_unique(mVFS.get(), expiryDelay, &mEncoder.getStatelessEncoder()); + // FIXME: this is severely out of date (see #7595) Shader::ShaderManager::DefineMap defines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); Shader::ShaderManager::DefineMap shadowDefines = SceneUtil::ShadowManager::getShadowsDisabledDefines(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index dc71e455b2..d5c5321f8e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -446,6 +446,7 @@ namespace MWRender globalDefines["useOVR_multiview"] = "0"; globalDefines["numViews"] = "1"; globalDefines["disableNormals"] = "1"; + globalDefines["reconstructNormalZ"] = "0"; for (auto itr = lightDefines.begin(); itr != lightDefines.end(); itr++) globalDefines[itr->first] = itr->second; diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index a7d2ef61a1..e7cc9f03e5 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -78,8 +78,7 @@ namespace Resource } break; } - // not bothering with checks for other compression formats right now, we are unlikely to ever use those - // anyway + // not bothering with checks for other compression formats right now default: return true; } diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 7bce9de2a6..3867f1f43e 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -184,6 +184,7 @@ namespace Shader , mAdditiveBlending(false) , mDiffuseHeight(false) , mNormalHeight(false) + , mReconstructNormalZ(false) , mTexStageRequiringTangents(-1) , mSoftParticles(false) , mNode(nullptr) @@ -429,6 +430,7 @@ namespace Shader normalMapTex->setFilter(osg::Texture::MAG_FILTER, diffuseMap->getFilter(osg::Texture::MAG_FILTER)); normalMapTex->setMaxAnisotropy(diffuseMap->getMaxAnisotropy()); normalMapTex->setName("normalMap"); + normalMap = normalMapTex; int unit = texAttributes.size(); if (!writableStateSet) @@ -440,6 +442,23 @@ namespace Shader mRequirements.back().mNormalHeight = normalHeight; } } + + if (normalMap != nullptr && normalMap->getImage(0)) + { + // Special handling for red-green normal maps (e.g. BC5 or R8G8). + switch (normalMap->getImage(0)->getPixelFormat()) + { + case GL_RG: + case GL_RG_INTEGER: + case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: + case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: + { + mRequirements.back().mReconstructNormalZ = true; + mRequirements.back().mNormalHeight = false; + } + } + } + if (mAutoUseSpecularMaps && diffuseMap != nullptr && specularMap == nullptr && diffuseMap->getImage(0)) { std::string specularMapFileName = diffuseMap->getImage(0)->getFileName(); @@ -629,6 +648,7 @@ namespace Shader defineMap["diffuseParallax"] = reqs.mDiffuseHeight ? "1" : "0"; defineMap["parallax"] = reqs.mNormalHeight ? "1" : "0"; + defineMap["reconstructNormalZ"] = reqs.mReconstructNormalZ ? "1" : "0"; writableStateSet->addUniform(new osg::Uniform("colorMode", reqs.mColorMode)); addedState->addUniform("colorMode"); diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index a8e79ec995..9ce0819bd3 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -110,6 +110,7 @@ namespace Shader bool mDiffuseHeight; // true if diffuse map has height info in alpha channel bool mNormalHeight; // true if normal map has height info in alpha channel + bool mReconstructNormalZ; // used for red-green normal maps (e.g. BC5) // -1 == no tangents required int mTexStageRequiringTangents; diff --git a/files/shaders/compatibility/bs/default.frag b/files/shaders/compatibility/bs/default.frag index 77131c6a52..d2c8de0b22 100644 --- a/files/shaders/compatibility/bs/default.frag +++ b/files/shaders/compatibility/bs/default.frag @@ -77,6 +77,9 @@ void main() vec3 specularColor = getSpecularColor().xyz; #if @normalMap vec4 normalTex = texture2D(normalMap, normalMapUV); +#if @reconstructNormalZ + normalTex.z = sqrt(1.0 - dot(normalTex.xy, normalTex.xy)); +#endif vec3 viewNormal = normalToView(normalTex.xyz * 2.0 - 1.0); specularColor *= normalTex.a; #else diff --git a/files/shaders/compatibility/groundcover.frag b/files/shaders/compatibility/groundcover.frag index dfdd6518c3..aab37d465d 100644 --- a/files/shaders/compatibility/groundcover.frag +++ b/files/shaders/compatibility/groundcover.frag @@ -59,7 +59,11 @@ void main() gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); #if @normalMap - vec3 viewNormal = normalToView(texture2D(normalMap, normalMapUV).xyz * 2.0 - 1.0); + vec4 normalTex = texture2D(normalMap, normalMapUV); +#if @reconstructNormalZ + normalTex.z = sqrt(1.0 - dot(normalTex.xy, normalTex.xy)); +#endif + vec3 viewNormal = normalToView(normalTex.xyz * 2.0 - 1.0); #else vec3 viewNormal = normalToView(normalize(passNormal)); #endif diff --git a/files/shaders/compatibility/objects.frag b/files/shaders/compatibility/objects.frag index 56c7abf27c..eb5b79a0c2 100644 --- a/files/shaders/compatibility/objects.frag +++ b/files/shaders/compatibility/objects.frag @@ -167,7 +167,11 @@ vec2 screenCoords = gl_FragCoord.xy / screenRes; gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); #if @normalMap - vec3 viewNormal = normalToView(texture2D(normalMap, normalMapUV + offset).xyz * 2.0 - 1.0); + vec4 normalTex = texture2D(normalMap, normalMapUV + offset); +#if @reconstructNormalZ + normalTex.z = sqrt(1.0 - dot(normalTex.xy, normalTex.xy)); +#endif + vec3 viewNormal = normalToView(normalTex.xyz * 2.0 - 1.0); #else vec3 viewNormal = normalize(gl_NormalMatrix * passNormal); #endif diff --git a/files/shaders/compatibility/terrain.frag b/files/shaders/compatibility/terrain.frag index abc7425eb0..f45f1f024e 100644 --- a/files/shaders/compatibility/terrain.frag +++ b/files/shaders/compatibility/terrain.frag @@ -63,7 +63,11 @@ void main() #endif #if @normalMap - vec3 viewNormal = normalToView(texture2D(normalMap, adjustedUV).xyz * 2.0 - 1.0); + vec4 normalTex = texture2D(normalMap, adjustedUV); +#if @reconstructNormalZ + normalTex.z = sqrt(1.0 - dot(normalTex.xy, normalTex.xy)); +#endif + vec3 viewNormal = normalToView(normalTex.xyz * 2.0 - 1.0); #else vec3 viewNormal = normalize(gl_NormalMatrix * passNormal); #endif