From 9c94058727880eabc41c5d48b2f853eeb4c3e4a8 Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sat, 4 Nov 2023 20:02:55 +0300 Subject: [PATCH] Support Oblivion parallax setup --- components/nifosg/nifloader.cpp | 1 + components/shader/shadervisitor.cpp | 10 +++++++ components/shader/shadervisitor.hpp | 1 + files/shaders/compatibility/objects.frag | 35 ++++++++++++++++-------- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 17c608f2d4..436f2e1d34 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -2363,6 +2363,7 @@ namespace NifOsg osg::StateSet* stateset = node->getOrCreateStateSet(); handleTextureProperty( texprop, node->getName(), stateset, composite, imageManager, boundTextures, animflags); + node->setUserValue("applyMode", static_cast(texprop->mApplyMode)); break; } case Nif::RC_BSShaderPPLightingProperty: diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 96e3d42f78..a08652620d 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -181,6 +181,7 @@ namespace Shader , mAlphaBlend(false) , mBlendFuncOverridden(false) , mAdditiveBlending(false) + , mDiffuseHeight(false) , mNormalHeight(false) , mTexStageRequiringTangents(-1) , mSoftParticles(false) @@ -303,6 +304,14 @@ namespace Shader if (node.getUserValue(Misc::OsgUserValues::sXSoftEffect, softEffect) && softEffect) mRequirements.back().mSoftParticles = true; + int applyMode; + // Oblivion parallax + if (node.getUserValue("applyMode", applyMode) && applyMode == 4) + { + mRequirements.back().mShaderRequired = true; + mRequirements.back().mDiffuseHeight = true; + } + // Make sure to disregard any state that came from a previous call to createProgram osg::ref_ptr addedState = getAddedState(*stateset); @@ -615,6 +624,7 @@ namespace Shader addedState->addUniform("useDiffuseMapForShadowAlpha"); } + defineMap["diffuseParallax"] = reqs.mDiffuseHeight ? "1" : "0"; defineMap["parallax"] = reqs.mNormalHeight ? "1" : "0"; writableStateSet->addUniform(new osg::Uniform("colorMode", reqs.mColorMode)); diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index 66bd8c2a9d..a8e79ec995 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -108,6 +108,7 @@ namespace Shader bool mBlendFuncOverridden; bool mAdditiveBlending; + bool mDiffuseHeight; // true if diffuse map has height info in alpha channel bool mNormalHeight; // true if normal map has height info in alpha channel // -1 == no tangents required diff --git a/files/shaders/compatibility/objects.frag b/files/shaders/compatibility/objects.frag index b86678af87..6de1f6d02f 100644 --- a/files/shaders/compatibility/objects.frag +++ b/files/shaders/compatibility/objects.frag @@ -113,10 +113,6 @@ void main() applyOcclusionDiscard(orthoDepthMapCoord, texture2D(orthoDepthMap, orthoDepthMapCoord.xy * 0.5 + 0.5).r); #endif -#if @diffuseMap - vec2 adjustedDiffuseUV = diffuseMapUV; -#endif - vec3 normal = normalize(passNormal); vec3 viewVec = normalize(passViewPos.xyz); @@ -131,11 +127,24 @@ void main() normal = normalize(tbnTranspose * (normalTex.xyz * 2.0 - 1.0)); #endif -#if @parallax +#if !@diffuseMap + gl_FragData[0] = vec4(1.0); +#else + vec2 adjustedDiffuseUV = diffuseMapUV; + +#if @normalMap && (@parallax || @diffuseParallax) vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; vec3 objectPos = (gl_ModelViewMatrixInverse * vec4(passViewPos, 1)).xyz; vec3 eyeDir = normalize(cameraPos - objectPos); - vec2 offset = getParallaxOffset(eyeDir, tbnTranspose, normalTex.a, (passTangent.w > 0.0) ? -1.f : 1.f); +#if @parallax + float height = normalTex.a; + float flipY = (passTangent.w > 0.0) ? -1.f : 1.f; +#else + float height = texture2D(diffuseMap, diffuseMapUV).a; + // FIXME: shouldn't be necessary, but in this path false-positives are common + float flipY = -1.f; +#endif + vec2 offset = getParallaxOffset(eyeDir, tbnTranspose, height, flipY); adjustedDiffuseUV += offset; // only offset diffuse for now, other textures are more likely to be using a completely different UV set // TODO: check not working as the same UV buffer is being bound to different targets @@ -149,14 +158,16 @@ void main() #endif -vec3 viewNormal = normalize(gl_NormalMatrix * normal); - -#if @diffuseMap - gl_FragData[0] = texture2D(diffuseMap, adjustedDiffuseUV); - gl_FragData[0].a *= coveragePreservingAlphaScale(diffuseMap, adjustedDiffuseUV); + vec4 diffuseTex = texture2D(diffuseMap, adjustedDiffuseUV); + gl_FragData[0].xyz = diffuseTex.xyz; +#if !@diffuseParallax + gl_FragData[0].a = diffuseTex.a * coveragePreservingAlphaScale(diffuseMap, adjustedDiffuseUV); #else - gl_FragData[0] = vec4(1.0); + gl_FragData[0].a = 1.0; #endif +#endif + + vec3 viewNormal = normalize(gl_NormalMatrix * normal); vec4 diffuseColor = getDiffuseColor(); gl_FragData[0].a *= diffuseColor.a;