diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 7fadb0db8b..606a4bcec2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -2206,7 +2206,7 @@ namespace NifOsg { auto texprop = static_cast(property); bool shaderRequired = true; - node->setUserValue("shaderPrefix", std::string("nv_nolighting")); + node->setUserValue("shaderPrefix", std::string("bs/nolighting")); node->setUserValue("shaderRequired", shaderRequired); osg::StateSet* stateset = node->getOrCreateStateSet(); if (!texprop->mSourceTexture.empty()) diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 4e9fb86960..0c9b13a9b8 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -37,6 +37,18 @@ namespace throw std::runtime_error("unrecognized shader template name: " + templateName); } + + std::string getRootPrefix(const std::string& path) + { + if (path.starts_with("lib")) + return "lib"; + else if (path.starts_with("compatibility")) + return "compatibility"; + else if (path.starts_with("core")) + return "core"; + else + return ""; + } } namespace Shader @@ -129,11 +141,15 @@ namespace Shader return false; } std::string includeFilename = source.substr(start + 1, end - (start + 1)); - std::filesystem::path includePath - = shaderPath / std::filesystem::path(fileName).parent_path() / includeFilename; - if (!std::filesystem::exists(includePath)) - includePath = shaderPath / includeFilename; + // Check if this include is a relative path + // TODO: We shouldn't be relying on soft-coded root prefixes, just check if the path exists and fallback to + // searching root if it doesn't + if (getRootPrefix(includeFilename).empty()) + includeFilename + = Files::pathToUnicodeString(std::filesystem::path(fileName).parent_path() / includeFilename); + + std::filesystem::path includePath = shaderPath / includeFilename; // Determine the line number that will be used for the #line directive following the included source size_t lineDirectivePosition = source.rfind("#line", foundPos); @@ -504,8 +520,7 @@ namespace Shader // TODO: Implement mechanism to switch to core or compatibility profile shaders. // This logic is temporary until core support is supported. - if (!templateName.starts_with("lib") && !templateName.starts_with("compatibility") - && !templateName.starts_with("core")) + if (getRootPrefix(templateName).empty()) templateName = "compatibility/" + templateName; // read the template if we haven't already diff --git a/files/shaders/compatibility/bs/default.frag b/files/shaders/compatibility/bs/default.frag index d1461eb821..240ff0907f 100644 --- a/files/shaders/compatibility/bs/default.frag +++ b/files/shaders/compatibility/bs/default.frag @@ -9,6 +9,8 @@ #extension GL_EXT_gpu_shader4: require #endif +#define PER_PIXEL_LIGHTING 1 + #if @diffuseMap uniform sampler2D diffuseMap; varying vec2 diffuseMapUV; @@ -28,24 +30,22 @@ varying vec4 passTangent; varying float euclideanDepth; varying float linearDepth; -#define PER_PIXEL_LIGHTING 1 - varying vec3 passViewPos; varying vec3 passNormal; uniform vec2 screenRes; uniform float far; uniform float alphaRef; - -#include "vertexcolors.glsl" -#include "shadows_fragment.glsl" -#include "lib/light/lighting.glsl" -#include "lib/material/alpha.glsl" -#include "fog.glsl" - uniform float emissiveMult; uniform float specStrength; +#include "lib/light/lighting.glsl" +#include "lib/material/alpha.glsl" + +#include "compatibility/vertexcolors.glsl" +#include "compatibility/shadows_fragment.glsl" +#include "compatibility/fog.glsl" + void main() { vec3 normal = normalize(passNormal); @@ -59,7 +59,7 @@ void main() vec4 diffuseColor = getDiffuseColor(); gl_FragData[0].a *= diffuseColor.a; - gl_FragData[0].a = alphaTest(gl_FragData[0].a); + gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); #if @normalMap vec4 normalTex = texture2D(normalMap, normalMapUV); diff --git a/files/shaders/compatibility/bs/default.vert b/files/shaders/compatibility/bs/default.vert index c2df86eb73..712a3f3d0c 100644 --- a/files/shaders/compatibility/bs/default.vert +++ b/files/shaders/compatibility/bs/default.vert @@ -8,7 +8,10 @@ #extension GL_EXT_gpu_shader4: require #endif +#define PER_PIXEL_LIGHTING 1 + #include "lib/core/vertex.h.glsl" + #if @diffuseMap varying vec2 diffuseMapUV; #endif @@ -28,13 +31,12 @@ varying float linearDepth; varying vec3 passViewPos; varying vec3 passNormal; -#define PER_PIXEL_LIGHTING 1 - -#include "vertexcolors.glsl" -#include "shadows_vertex.glsl" #include "lib/light/lighting.glsl" #include "lib/view/depth.glsl" +#include "compatibility/vertexcolors.glsl" +#include "compatibility/shadows_vertex.glsl" + void main(void) { gl_Position = modelToClip(gl_Vertex); diff --git a/files/shaders/compatibility/bs/nolighting.frag b/files/shaders/compatibility/bs/nolighting.frag index dc038d491c..9572088876 100644 --- a/files/shaders/compatibility/bs/nolighting.frag +++ b/files/shaders/compatibility/bs/nolighting.frag @@ -1,6 +1,10 @@ #version 120 #pragma import_defines(FORCE_OPAQUE) +#if @useUBO + #extension GL_ARB_uniform_buffer_object : require +#endif + #if @useGPUShader4 #extension GL_EXT_gpu_shader4: require #endif @@ -10,20 +14,22 @@ uniform sampler2D diffuseMap; varying vec2 diffuseMapUV; #endif +varying vec3 passNormal; varying float euclideanDepth; varying float linearDepth; +varying float passFalloff; -uniform bool useFalloff; uniform vec2 screenRes; +uniform bool useFalloff; uniform float emissiveMult; uniform float far; uniform float alphaRef; -varying float passFalloff; - #include "lib/material/alpha.glsl" -#include "vertexcolors.glsl" -#include "fog.glsl" + +#include "compatibility/vertexcolors.glsl" +#include "compatibility/fog.glsl" +#include "compatibility/shadows_fragment.glsl" void main() { @@ -43,11 +49,18 @@ void main() gl_FragData[0].rgb *= emissionColor.rgb * emissiveMult; gl_FragData[0].a *= emissionColor.a * emissionColor.a; // sic - gl_FragData[0].a = alphaTest(gl_FragData[0].a); + gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); + + gl_FragData[0] = applyFogAtDist(gl_FragData[0], euclideanDepth, linearDepth, far); #if defined(FORCE_OPAQUE) && FORCE_OPAQUE gl_FragData[0].a = 1.0; #endif - gl_FragData[0] = applyFogAtDist(gl_FragData[0], euclideanDepth, linearDepth, far); +#if !defined(FORCE_OPAQUE) && !@disableNormals + vec3 viewNormal = normalize(gl_NormalMatrix * passNormal); + gl_FragData[1].xyz = viewNormal * 0.5 + 0.5; +#endif + + applyShadowDebugOverlay(); } diff --git a/files/shaders/compatibility/bs/nolighting.vert b/files/shaders/compatibility/bs/nolighting.vert index 039017b53b..27be3396ce 100644 --- a/files/shaders/compatibility/bs/nolighting.vert +++ b/files/shaders/compatibility/bs/nolighting.vert @@ -1,42 +1,48 @@ #version 120 +#if @useUBO + #extension GL_ARB_uniform_buffer_object : require +#endif + +#if @useGPUShader4 + #extension GL_EXT_gpu_shader4: require +#endif + #include "lib/core/vertex.h.glsl" #if @diffuseMap varying vec2 diffuseMapUV; #endif -#if @radialFog +varying vec3 passNormal; varying float euclideanDepth; -#else varying float linearDepth; -#endif +varying float passFalloff; uniform bool useFalloff; uniform vec4 falloffParams; -varying float passFalloff; - -#include "vertexcolors.glsl" #include "lib/view/depth.glsl" +#include "compatibility/vertexcolors.glsl" +#include "compatibility/shadows_vertex.glsl" + void main(void) { gl_Position = modelToClip(gl_Vertex); vec4 viewPos = modelToView(gl_Vertex); gl_ClipVertex = viewPos; -#if @radialFog euclideanDepth = length(viewPos.xyz); -#else linearDepth = getLinearDepth(gl_Position.z, viewPos.z); -#endif #if @diffuseMap diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy; #endif passColor = gl_Color; + passNormal = gl_Normal.xyz; + if (useFalloff) { vec3 viewNormal = gl_NormalMatrix * normalize(gl_Normal.xyz); @@ -53,4 +59,9 @@ void main(void) { passFalloff = 1.0; } + +#if @shadows_enabled + vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz); + setupShadowCoords(viewPos, viewNormal); +#endif } diff --git a/files/shaders/compatibility/groundcover.frag b/files/shaders/compatibility/groundcover.frag index d975a71785..9dfd71b32e 100644 --- a/files/shaders/compatibility/groundcover.frag +++ b/files/shaders/compatibility/groundcover.frag @@ -70,7 +70,7 @@ void main() if (euclideanDepth > @groundcoverFadeStart) gl_FragData[0].a *= 1.0-smoothstep(@groundcoverFadeStart, @groundcoverFadeEnd, euclideanDepth); - gl_FragData[0].a = alphaTest(gl_FragData[0].a); + gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); float shadowing = unshadowedLightRatio(linearDepth); diff --git a/files/shaders/compatibility/objects.frag b/files/shaders/compatibility/objects.frag index 5690309937..4ef463cb34 100644 --- a/files/shaders/compatibility/objects.frag +++ b/files/shaders/compatibility/objects.frag @@ -84,12 +84,13 @@ varying vec3 passNormal; #define ADDITIVE_BLENDING #endif -#include "vertexcolors.glsl" -#include "shadows_fragment.glsl" #include "lib/light/lighting.glsl" #include "lib/material/parallax.glsl" #include "lib/material/alpha.glsl" + #include "fog.glsl" +#include "vertexcolors.glsl" +#include "shadows_fragment.glsl" #if @softParticles #include "lib/particle/soft.glsl" @@ -164,7 +165,7 @@ vec3 viewNormal = normalize(gl_NormalMatrix * normal); gl_FragData[0].a *= coveragePreservingAlphaScale(darkMap, darkMapUV); #endif - gl_FragData[0].a = alphaTest(gl_FragData[0].a); + gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); #if @detailMap gl_FragData[0].xyz *= texture2D(detailMap, detailMapUV).xyz * 2.0; diff --git a/files/shaders/compatibility/shadowcasting.frag b/files/shaders/compatibility/shadowcasting.frag index 19cca14951..5e550e99fb 100644 --- a/files/shaders/compatibility/shadowcasting.frag +++ b/files/shaders/compatibility/shadowcasting.frag @@ -23,7 +23,7 @@ void main() else gl_FragData[0].a = alphaPassthrough; - gl_FragData[0].a = alphaTest(gl_FragData[0].a); + gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); // Prevent translucent things casting shadow (including the player using an invisibility effect). // This replaces alpha blending, which obviously doesn't work with depth buffers diff --git a/files/shaders/lib/material/alpha.glsl b/files/shaders/lib/material/alpha.glsl index 5adfa18e88..62722e52a1 100644 --- a/files/shaders/lib/material/alpha.glsl +++ b/files/shaders/lib/material/alpha.glsl @@ -33,10 +33,10 @@ float coveragePreservingAlphaScale(sampler2D diffuseMap, vec2 uv) #endif } -float alphaTest(float alpha) +float alphaTest(float alpha, float ref) { #if @alphaToCoverage - float coverageAlpha = (alpha - clamp(alphaRef, 0.0001, 0.9999)) / max(fwidth(alpha), 0.0001) + 0.5; + float coverageAlpha = (alpha - clamp(ref, 0.0001, 0.9999)) / max(fwidth(alpha), 0.0001) + 0.5; // Some functions don't make sense with A2C or are a pain to think about and no meshes use them anyway // Use regular alpha testing in such cases until someone complains. @@ -45,14 +45,14 @@ float alphaTest(float alpha) #elif @alphaFunc == FUNC_LESS return 1.0 - coverageAlpha; #elif @alphaFunc == FUNC_EQUAL - if (alpha != alphaRef) + if (alpha != ref) discard; #elif @alphaFunc == FUNC_LEQUAL return 1.0 - coverageAlpha; #elif @alphaFunc == FUNC_GREATER return coverageAlpha; #elif @alphaFunc == FUNC_NOTEQUAL - if (alpha == alphaRef) + if (alpha == ref) discard; #elif @alphaFunc == FUNC_GEQUAL return coverageAlpha; @@ -61,22 +61,22 @@ float alphaTest(float alpha) #if @alphaFunc == FUNC_NEVER discard; #elif @alphaFunc == FUNC_LESS - if (alpha >= alphaRef) + if (alpha >= ref) discard; #elif @alphaFunc == FUNC_EQUAL - if (alpha != alphaRef) + if (alpha != ref) discard; #elif @alphaFunc == FUNC_LEQUAL - if (alpha > alphaRef) + if (alpha > ref) discard; #elif @alphaFunc == FUNC_GREATER - if (alpha <= alphaRef) + if (alpha <= ref) discard; #elif @alphaFunc == FUNC_NOTEQUAL - if (alpha == alphaRef) + if (alpha == ref) discard; #elif @alphaFunc == FUNC_GEQUAL - if (alpha < alphaRef) + if (alpha < ref) discard; #endif #endif