Skip to content

Instantly share code, notes, and snippets.

@Xynonners
Last active April 10, 2024 01:26
Show Gist options
  • Save Xynonners/6e50a27d562829469281be45b039ec93 to your computer and use it in GitHub Desktop.
Save Xynonners/6e50a27d562829469281be45b039ec93 to your computer and use it in GitHub Desktop.
gdshader LXAA implementation, put in full rect ColorRect across entire screen
/* Fast antialiasing shader by G.Rebord (mod by Xynon for Godot)
Based on FXAA3 CONSOLE version by TIMOTHY LOTTES
------------------------------------------------------------------------------
THIS 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
AUTHOR OR CONTRIBUTORS 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.
============================================================================*/
shader_type canvas_item;
// Edge detection threshold. With lower values more edges are detected.
// The form of edge detection used here is much better than a simple luma
// delta, improving both fidelity and performance.
// Range: [0;1]. Default: 0.375 (thorough)
uniform float LXAA_EDGE_THRES : hint_range(0, 1) = 0.375;
// Enable to make near-horizontal/near-vertical lines smoother, which
// requires additional checks. This brings a substantial jump in quality.
uniform bool LXAA_LINE_CHECK = true;
// Capture the screen via sampler2D, filtering may be useful but disabled for now.
uniform sampler2D BackBufferTex: hint_screen_texture, repeat_disable;
const ivec2 OffSW = ivec2(-1, 1);
const ivec2 OffSE = ivec2(1, 1);
const ivec2 OffNE = ivec2(1, -1);
const ivec2 OffNW = ivec2(-1, -1);
const float LXAA_OFF_MIN = 0.0625;
const float LXAA_PROP_MAIN = 0.4;
const float LXAA_PROP_EACH_NP = 0.3;
float GetLuma(vec3 color) {
return dot(color, vec3(0.299, 0.587, 0.114));
}
vec3 SampleColor(vec2 p) {
return texture(BackBufferTex, p).rgb;
}
float SampleLumaOff(vec2 p, ivec2 o) {
vec2 size = vec2(textureSize(BackBufferTex, 0));
vec2 RCP2 = 2.0 / size;
return GetLuma(texture(BackBufferTex, p + vec2(o) * RCP2).rgb);
}
void fragment() {
vec2 size = vec2(textureSize(BackBufferTex, 0));
vec2 RCP2 = 2.0 / size;
vec2 tco = FRAGCOORD.xy / size;
vec4 lumaA;
lumaA.x = SampleLumaOff(tco, OffSW);
lumaA.y = SampleLumaOff(tco, OffSE);
lumaA.z = SampleLumaOff(tco, OffNE);
lumaA.w = SampleLumaOff(tco, OffNW);
float gradientSWNE = lumaA.x - lumaA.z;
float gradientSENW = lumaA.y - lumaA.w;
vec2 dir = vec2(gradientSWNE + gradientSENW, gradientSWNE - gradientSENW);
vec2 dirM = abs(dir);
float lumaAMax = max(max(lumaA.x, lumaA.y), max(lumaA.z, lumaA.w));
float localLumaFactor = lumaAMax * 0.5 + 0.5;
float localThres = LXAA_EDGE_THRES * localLumaFactor;
bool lowDelta = abs(dirM.x - dirM.y) < localThres;
if (lowDelta) {
discard;
}
float dirMMin = min(dirM.x, dirM.y);
vec2 offM = clamp(vec2(LXAA_OFF_MIN) * dirM / dirMMin, 0.0, 1.0);
vec2 offMult = RCP2 * sign(dir);
if (LXAA_LINE_CHECK) {
float offMMax = max(offM.x, offM.y);
if (offMMax == 1.0) {
bool horSpan = offM.x == 1.0;
bool negSpan = horSpan ? offMult.x < 0.0 : offMult.y < 0.0;
bool sowSpan = horSpan == negSpan;
vec2 tcoC = tco;
if (horSpan) tcoC.x += 2.0 * offMult.x;
if (!horSpan) tcoC.y += 2.0 * offMult.y;
vec4 lumaAC = lumaA;
if (sowSpan) lumaAC.x = SampleLumaOff(tcoC, OffSW);
if (!negSpan) lumaAC.y = SampleLumaOff(tcoC, OffSE);
if (!sowSpan) lumaAC.z = SampleLumaOff(tcoC, OffNE);
if (negSpan) lumaAC.w = SampleLumaOff(tcoC, OffNW);
float gradientSWNEC = lumaAC.x - lumaAC.z;
float gradientSENWC = lumaAC.y - lumaAC.w;
vec2 dirC = vec2(gradientSWNEC + gradientSENWC, gradientSWNEC - gradientSENWC);
if (!horSpan) dirC = dirC.yx;
bool passC = abs(dirC.x) > 2.0 * abs(dirC.y);
if (passC) offMult *= 2.0;
}
}
vec2 offset = offM * offMult;
vec3 rgbM = SampleColor(tco);
vec3 rgbN = SampleColor(tco - offset);
vec3 rgbP = SampleColor(tco + offset);
vec3 rgbR = (rgbN + rgbP) * LXAA_PROP_EACH_NP + rgbM * LXAA_PROP_MAIN;
float lumaR = GetLuma(rgbR);
float lumaAMin = min(min(lumaA.x, lumaA.y), min(lumaA.z, lumaA.w));
bool outOfRange = (lumaR < lumaAMin) || (lumaR > lumaAMax);
if (outOfRange) {
discard;
}
COLOR = vec4(rgbR, 1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment