1
0
forked from 0ad/0ad

Adds contrast-adaptiv-sharpening filter, also helps to partly remove FXAA texture blurring.

Patch By: OptimusShepard
Tested By: Stan
Differential Revision: https://code.wildfiregames.com/D2642
This was SVN commit r23947.
This commit is contained in:
Vladislav Belov 2020-08-07 22:16:55 +00:00
parent 8d90636306
commit 26ae55cad0
12 changed files with 207 additions and 4 deletions

View File

@ -29,6 +29,9 @@ in particular, let us know and we can try to clarify it.
/binaries/data/mods/public/shaders/glsl/fxaa.fs
BSD
/binaries/data/mods/public/shaders/glsl/cas.fs
MIT
/binaries/system
Various (unspecified)

View File

@ -110,6 +110,10 @@ postproc = false
; 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

View File

@ -129,6 +129,28 @@
],
"function": "Renderer_UpdateAntiAliasingTechnique"
},
{
"type": "dropdown",
"label": "Sharpening",
"tooltip": "Reduce blurry effects.",
"dependencies": ["postproc", "preferglsl"],
"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", "preferglsl"],
"config": "sharpness",
"min": 0,
"max": 1,
"function": "Renderer_UpdateSharpnessFactor"
},
{
"type": "slider",
"label": "Shader effects",

View File

@ -9,7 +9,7 @@
<object type="image" sprite="ModernFade"/>
<!-- Settings Window -->
<object name="options" type="image" style="ModernDialog" size="50%-350 50%-344 50%+350 50%+344">
<object name="options" type="image" style="ModernDialog" size="50%-350 50%-374 50%+350 50%+374">
<object style="ModernLabelText" type="text" size="50%-128 -16 50%+128 16">
<translatableAttribute id="caption">Game Options</translatableAttribute>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<effect>
<technique>
<require shaders="glsl"/>
<pass shader="glsl/cas"/>
</technique>
</effect>

View File

@ -0,0 +1,91 @@
#version 110
// 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();
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<program type="glsl">
<vertex file="glsl/simple.vs">
<stream name="pos"/>
<stream name="uv0"/>
<attrib name="a_vertex" semantics="gl_Vertex"/>
<attrib name="a_uv0" semantics="gl_MultiTexCoord0"/>
</vertex>
<fragment file="glsl/cas.fs"/>
</program>

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2014 Wildfire Games.
/* Copyright (C) 2020 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -135,6 +135,7 @@ X(shadingColor)
X(shadowScale)
X(shadowTex)
X(shadowTransform)
X(sharpness)
X(skinBlendMatrices)
X2(skinBlendMatrices_0, "skinBlendMatrices[0]")
X(skyBoxRot)

View File

@ -38,7 +38,7 @@
CPostprocManager::CPostprocManager()
: m_IsInitialized(false), m_PingFbo(0), m_PongFbo(0), m_PostProcEffect(L"default"), m_ColorTex1(0), m_ColorTex2(0),
m_DepthTex(0), m_BloomFbo(0), m_BlurTex2a(0), m_BlurTex2b(0), m_BlurTex4a(0), m_BlurTex4b(0),
m_BlurTex8a(0), m_BlurTex8b(0), m_WhichBuffer(true)
m_BlurTex8a(0), m_BlurTex8b(0), m_WhichBuffer(true), m_Sharpness(0.3f)
{
}
@ -81,6 +81,8 @@ void CPostprocManager::Initialize()
m_Height = g_Renderer.GetHeight();
UpdateAntiAliasingTechnique();
UpdateSharpeningTechnique();
UpdateSharpnessFactor();
RecreateBuffers();
m_IsInitialized = true;
@ -428,6 +430,8 @@ void CPostprocManager::ApplyEffect(CShaderTechniquePtr &shaderTech1, int pass)
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);
@ -473,7 +477,8 @@ void CPostprocManager::ApplyPostproc()
// Don't do anything if we are using the default effect and no AA.
const bool hasEffects = m_PostProcEffect != L"default";
const bool hasAA = m_AATech && g_RenderingOptions.GetPreferGLSL();
if (!hasEffects && !hasAA)
const bool hasSharp = m_SharpTech && g_RenderingOptions.GetPreferGLSL();
if (!hasEffects && !hasAA && !hasSharp)
return;
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo);
@ -508,6 +513,12 @@ void CPostprocManager::ApplyPostproc()
ApplyEffect(m_AATech, pass);
}
if (hasSharp)
{
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);
@ -574,6 +585,29 @@ void CPostprocManager::UpdateAntiAliasingTechnique()
}
}
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;
@ -637,6 +671,14 @@ void CPostprocManager::UpdateAntiAliasingTechnique()
{
}
void CPostprocManager::UpdateSharpeningTechnique()
{
}
void CPostprocManager::UpdateSharpnessFactor()
{
}
void CPostprocManager::CaptureRenderOutput()
{
}

View File

@ -50,6 +50,8 @@ public:
// Triggers update of shaders and FBO if needed.
void UpdateAntiAliasingTechnique();
void UpdateSharpeningTechnique();
void UpdateSharpnessFactor();
void SetDepthBufferClipPlanes(float nearPlane, float farPlane);
@ -91,6 +93,10 @@ private:
CStrW m_PostProcEffect;
CShaderTechniquePtr m_PostProcTech;
CStr m_SharpName;
CShaderTechniquePtr m_SharpTech;
float m_Sharpness;
CStr m_AAName;
CShaderTechniquePtr m_AATech;

View File

@ -72,6 +72,16 @@ void JSI_Renderer::UpdateAntiAliasingTechnique(ScriptInterface::CxPrivate* UNUSE
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 @@ void JSI_Renderer::RegisterScriptFunctions(const ScriptInterface& scriptInterfac
scriptInterface.RegisterFunction<void, std::string, &JSI_Renderer::SetRenderPath>("Renderer_SetRenderPath");
scriptInterface.RegisterFunction<void, &JSI_Renderer::RecreateShadowMap>("Renderer_RecreateShadowMap");
scriptInterface.RegisterFunction<void, &JSI_Renderer::UpdateAntiAliasingTechnique>("Renderer_UpdateAntiAliasingTechnique");
scriptInterface.RegisterFunction<void, &JSI_Renderer::UpdateSharpeningTechnique>("Renderer_UpdateSharpeningTechnique");
scriptInterface.RegisterFunction<void, &JSI_Renderer::UpdateSharpnessFactor>("Renderer_UpdateSharpnessFactor");
scriptInterface.RegisterFunction<bool, std::wstring, &JSI_Renderer::TextureExists>("TextureExists");
REGISTER_BOOLEAN_SCRIPT_SETTING(Shadows);
REGISTER_BOOLEAN_SCRIPT_SETTING(ShadowPCF);

View File

@ -29,6 +29,8 @@ namespace JSI_Renderer
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);