Index: binaries/data/config/default.cfg =================================================================== --- binaries/data/config/default.cfg +++ binaries/data/config/default.cfg @@ -117,6 +117,10 @@ ; Use anti-aliasing techniques. antialiasing = "disabled" +; Use sharpening techniques. +sharpening = "disabled" +sharpness = 0.3 + ; Quality level of shader effects (set to 10 to display all effects) materialmgr.quality = 2.0 Index: binaries/data/mods/public/gui/options/options.json =================================================================== --- binaries/data/mods/public/gui/options/options.json +++ binaries/data/mods/public/gui/options/options.json @@ -130,6 +130,28 @@ "function": "Renderer_UpdateAntiAliasingTechnique" }, { + "type": "dropdown", + "label": "Sharpening", + "tooltip": "Reduce blurry effects.", + "dependencies": ["postproc"], + "config": "sharpening", + "list": [ + { "value": "disabled", "label": "Disabled", "tooltip": "Do not use sharpening." }, + { "value": "cas", "label": "FidelityFX CAS", "tooltip": "Contrast adaptive sharpening, a fast, contrast based sharpening pass." } + ], + "function": "Renderer_UpdateSharpeningTechnique" + }, + { + "type": "slider", + "label": "Sharpness factor", + "tooltip": "The sharpness of the choosen pass.", + "dependencies": ["postproc"], + "config": "sharpness", + "min": 0, + "max": 1, + "function": "Renderer_UpdateSharpnessFactor" + }, + { "type": "slider", "label": "Shader effects", "tooltip": "Number of shader effects. REQUIRES GAME RESTART", Index: binaries/data/mods/public/gui/options/options.xml =================================================================== --- binaries/data/mods/public/gui/options/options.xml +++ binaries/data/mods/public/gui/options/options.xml @@ -9,7 +9,7 @@ - + Game Options Index: binaries/data/mods/public/shaders/effects/cas.xml =================================================================== --- /dev/null +++ binaries/data/mods/public/shaders/effects/cas.xml @@ -0,0 +1,7 @@ + + + + + + + Index: binaries/data/mods/public/shaders/glsl/cas.fs =================================================================== --- /dev/null +++ binaries/data/mods/public/shaders/glsl/cas.fs @@ -0,0 +1,89 @@ +// LICENSE +// ======= +// Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. +// ------- +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, +// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// ------- +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +// Software. +// ------- +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE + +// GLSL port of the CasFilter() (no scaling). https://github.com/GPUOpen-Effects/FidelityFX-CAS/blob/master/ffx-cas/ffx_cas.h + +uniform sampler2D renderedTex; +uniform float width; +uniform float height; +uniform float sharpness; + +varying vec2 v_tex; + +float saturate(float inputFloat){ + return clamp(inputFloat, 0.0, 1.0); +} + +vec3 saturate(vec3 inputFloat){ + return vec3(saturate(inputFloat.x), saturate(inputFloat.y), saturate(inputFloat.z)); +} + +vec3 sharpen() +{ + vec2 invSSize = vec2(1.0 / width, 1.0 / height); + + // No scaling algorithm uses a minimal 3x3 neighborhood around the pixel 'e', + // a b c + // d(e)f + // g h i + vec3 a = texture2D(renderedTex, v_tex + vec2(-1.0, -1.0) * invSSize).rgb; + vec3 b = texture2D(renderedTex, v_tex + vec2(0.0, -1.0) * invSSize).rgb; + vec3 c = texture2D(renderedTex, v_tex + vec2(1.0, -1.0) * invSSize).rgb; + vec3 d = texture2D(renderedTex, v_tex + vec2(-1.0, 0.0) * invSSize).rgb; + vec3 e = texture2D(renderedTex, v_tex + vec2(0.0, 0.0) * invSSize).rgb; + vec3 f = texture2D(renderedTex, v_tex + vec2(1.0, 0.0) * invSSize).rgb; + vec3 g = texture2D(renderedTex, v_tex + vec2(-1.0, 1.0) * invSSize).rgb; + vec3 h = texture2D(renderedTex, v_tex + vec2(0.0, 1.0) * invSSize).rgb; + vec3 i = texture2D(renderedTex, v_tex + vec2(1.0, 1.0) * invSSize).rgb; + + // Soft min and max. + // a b c b + // d e f * 0.5 + d e f * 0.5 + // g h i h + // These are 2.0x bigger (factored out the extra multiply). + vec3 mnRGB = min(min(min(d, e), min(f, b)), h); + vec3 mnRGB2 = min(mnRGB, min(min(a, c), min(g, i))); + mnRGB += mnRGB2; + + vec3 mxRGB = max(max(max(d, e), max(f, b)), h); + vec3 mxRGB2 = max(mxRGB, max(max(a, c), max(g, i))); + mxRGB += mxRGB2; + + // Smooth minimum distance to signal limit divided by smooth max. + vec3 rcpMRGB = 1.0 / (mxRGB); + vec3 ampRGB = saturate(min(mnRGB, 2.0 - mxRGB) * rcpMRGB); + + // Shaping amount of sharpening. + ampRGB = sqrt(ampRGB); + + float peak = -1.0 / (8.0 - 3.0 * sharpness); + vec3 wRGB = ampRGB * peak; + + vec3 rcpWeightRGB = 1.0 / (1.0 + 4.0 * wRGB); + + // 0 w 0 + // Filter shape: w 1 w + // 0 w 0 + vec3 outColor = saturate(((b + d + f + h) * wRGB + e) * rcpWeightRGB); + + return outColor; +} + +void main() +{ + gl_FragColor.rgb = sharpen(); +} Index: binaries/data/mods/public/shaders/glsl/cas.xml =================================================================== --- /dev/null +++ binaries/data/mods/public/shaders/glsl/cas.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + Index: source/ps/CStrInternStatic.h =================================================================== --- source/ps/CStrInternStatic.h +++ source/ps/CStrInternStatic.h @@ -135,6 +135,7 @@ X(shadowScale) X(shadowTex) X(shadowTransform) +X(sharpness) X(skinBlendMatrices) X2(skinBlendMatrices_0, "skinBlendMatrices[0]") X(skyBoxRot) Index: source/renderer/PostprocManager.h =================================================================== --- source/renderer/PostprocManager.h +++ source/renderer/PostprocManager.h @@ -50,6 +50,8 @@ // Triggers update of shaders and FBO if needed. void UpdateAntiAliasingTechnique(); + void UpdateSharpeningTechnique(); + void UpdateSharpnessFactor(); void SetDepthBufferClipPlanes(float nearPlane, float farPlane); @@ -91,6 +93,10 @@ CStrW m_PostProcEffect; CShaderTechniquePtr m_PostProcTech; + CStr m_SharpName; + CShaderTechniquePtr m_SharpTech; + float m_Sharpness; + CStr m_AAName; CShaderTechniquePtr m_AATech; Index: source/renderer/PostprocManager.cpp =================================================================== --- source/renderer/PostprocManager.cpp +++ source/renderer/PostprocManager.cpp @@ -81,6 +81,8 @@ m_Height = g_Renderer.GetHeight(); UpdateAntiAliasingTechnique(); + UpdateSharpeningTechnique(); + UpdateSharpnessFactor(); RecreateBuffers(); m_IsInitialized = true; @@ -428,6 +430,8 @@ shader->Uniform(str_zNear, m_NearPlane); shader->Uniform(str_zFar, m_FarPlane); + shader->Uniform(str_sharpness, m_Sharpness); + shader->Uniform(str_brightness, g_LightEnv.m_Brightness); shader->Uniform(str_hdr, g_LightEnv.m_Contrast); shader->Uniform(str_saturation, g_LightEnv.m_Saturation); @@ -472,7 +476,7 @@ // Don't do anything if we are using the default effect and no AA. const bool hasEffects = m_PostProcEffect != L"default"; - if (!hasEffects && !m_AATech) + if (!hasEffects && !m_AATech && !m_SharpTech) return; pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); @@ -507,6 +511,12 @@ ApplyEffect(m_AATech, pass); } + if (m_SharpTech) + { + for (int pass = 0; pass < m_SharpTech->GetNumPasses(); ++pass) + ApplyEffect(m_SharpTech, pass); + } + pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo); pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthTex, 0); @@ -573,6 +583,29 @@ } } +void CPostprocManager::UpdateSharpeningTechnique() +{ + if (!g_RenderingOptions.GetPreferGLSL()) + return; + + CStr newSharpName; + CFG_GET_VAL("sharpening", newSharpName); + if (m_SharpName == newSharpName) + return; + m_SharpName = newSharpName; + m_SharpTech.reset(); + + if (m_SharpName == "cas") + { + m_SharpTech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern(m_SharpName)); + } +} + +void CPostprocManager::UpdateSharpnessFactor() +{ + CFG_GET_VAL("sharpness", m_Sharpness); +} + void CPostprocManager::SetDepthBufferClipPlanes(float nearPlane, float farPlane) { m_NearPlane = nearPlane; @@ -636,6 +669,14 @@ { } +void CPostprocManager::UpdateSharpeningTechnique() +{ +} + +void CPostprocManager::UpdateSharpnessFactor() +{ +} + void CPostprocManager::CaptureRenderOutput() { } Index: source/renderer/scripting/JSInterface_Renderer.h =================================================================== --- source/renderer/scripting/JSInterface_Renderer.h +++ source/renderer/scripting/JSInterface_Renderer.h @@ -29,6 +29,8 @@ std::string GetRenderPath(ScriptInterface::CxPrivate* pCxPrivate); void SetRenderPath(ScriptInterface::CxPrivate* pCxPrivate, const std::string& name); void UpdateAntiAliasingTechnique(ScriptInterface::CxPrivate* pCxPrivate); + void UpdateSharpeningTechnique(ScriptInterface::CxPrivate* pCxPrivate); + void UpdateSharpnessFactor(ScriptInterface::CxPrivate* pCxPrivate); void RecreateShadowMap(ScriptInterface::CxPrivate* pCxPrivate); bool TextureExists(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename); Index: source/renderer/scripting/JSInterface_Renderer.cpp =================================================================== --- source/renderer/scripting/JSInterface_Renderer.cpp +++ source/renderer/scripting/JSInterface_Renderer.cpp @@ -72,6 +72,16 @@ g_Renderer.GetPostprocManager().UpdateAntiAliasingTechnique(); } +void JSI_Renderer::UpdateSharpeningTechnique(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) +{ + g_Renderer.GetPostprocManager().UpdateSharpeningTechnique(); +} + +void JSI_Renderer::UpdateSharpnessFactor(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) +{ + g_Renderer.GetPostprocManager().UpdateSharpnessFactor(); +} + void JSI_Renderer::RecreateShadowMap(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) { g_Renderer.GetShadowMap().RecreateTexture(); @@ -92,6 +102,8 @@ scriptInterface.RegisterFunction("Renderer_SetRenderPath"); scriptInterface.RegisterFunction("Renderer_RecreateShadowMap"); scriptInterface.RegisterFunction("Renderer_UpdateAntiAliasingTechnique"); + scriptInterface.RegisterFunction("Renderer_UpdateSharpeningTechnique"); + scriptInterface.RegisterFunction("Renderer_UpdateSharpnessFactor"); scriptInterface.RegisterFunction("TextureExists"); REGISTER_BOOLEAN_SCRIPT_SETTING(Shadows); REGISTER_BOOLEAN_SCRIPT_SETTING(ShadowPCF);