Hey, that’s a nice idea! Looks like a smart resampler.
This example looks like a really nice antialiasing effect
Here are the shader files with some presets for the “new” Lanczos resampler.
Download link:
https://mega.nz/file/whAlFDYJ#H68MzUoJxR7jmppfQU3mTuVAQKKHjwJOIVuabKaAPVc
It’s a two pass composition, but can be also used separately if needed.
The benefits are that filter range can be adjusted, which can be really nice for downsampling…
Good use cases:
- downsampling to a low resolution
- downsampling super-sampled sources to viewport
- antialiasing scaled graphics (xbr, scalefx…)
- edge smoothing on high resolution content (PSX, PS2, DC,…)
- can be also used as an ordinary resampler
I was looking at screenshots from my CRT to better match what it does on filtering, and i think windowed are the closest indeed.
raw screenshot
After applied gaussian on GIMP to “remove” mask etc to view shapes better.
bright pixels definitely enlarge, mostly horizontally “shaping” a kind of curve, or “spikes” to better describe it
Tested here and they worked as expected! Very useful for downsampling! Congrats!
Tried with ps1 @1080p internal resolution,
- filter range 3.5
- sharpness 1.3
- downsample 5
“240p” content
raw
shader onwith “hi res” content I like double scan ON
raw
shader onAs single pass resamplers have some benefits, i have developed a new “g-sharp2” single pass resampler.
Compared with the first version, the benefits are:
- much faster with same filter range (approx 2x)
- better image processing
- can be much faster with downsampling (due to range boost with same # of lookups)
@HyperspaceMadness can you do some “DREZ” testings? Should do quite better then the first version. I belive it could be a good upgrade.
Edit: 2-pass version added.
Screenie (2-pass version):
Edit: 2-pass version tweak, better AR
Download link:
https://mega.nz/file/4kxVhawQ#N_GMHOnzqudbX4vL3jkyRmomYlDIrKGsgJDr1AaNVrU
That’s a nice flexible shader. Is there any possibility to derivate some fast bilateral from these ones? I think we lack more bilateral options for now.
Hey @Hyllian (and everybody else interested), can you test it a bit? Should run nicely with base resolution. I added some options, so it isn’t so boring.
#version 450
/*
Bilateral filter - dynamic range (upscaler, downsampler)
Copyright (C) 2024 guest(r)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
layout(push_constant) uniform Push
{
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
float FRANGE;
float FBSMOOTH;
float FBOOST;
} params;
#pragma parameter FRANGE "Filter Range" 1.0 0.5 5.0 0.5
#define FRANGE params.FRANGE
#pragma parameter FBSMOOTH "Filter Base Smoothing" 0.55 0.05 1.0 0.025
#define FBSMOOTH params.FBSMOOTH
#pragma parameter FBOOST "Boost Smoothing w. dist" 0.0 0.0 5.0 0.25
#define FBOOST params.FBOOST
layout(std140, set = 0, binding = 0) uniform UBO
{
mat4 MVP;
} global;
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = TexCoord * 1.00001;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;
#define COMPAT_TEXTURE(c,d) texture(c,d)
#define SourceSize params.SourceSize
float wt(vec3 A, vec3 B)
{
return clamp(FBSMOOTH - ((6.0+0.25)/3.0) * dot(pow(abs(A-B),vec3(1.0/1.0)),1.0.xxx)/(dot(A+B,1.0.xxx)+0.25), 0.0001, 0.25);
}
float getw(float x, vec3 c, vec3 p)
{
float y = max(2.0-x, 0.0) + FBOOST;
float d = wt(c,p);
return y*d;
}
void main()
{
vec2 pos = vTexCoord * SourceSize.xy;
vec2 f = 0.5-fract(pos);
vec2 tex = floor(pos)*SourceSize.zw + 0.5*SourceSize.zw;
vec3 color = 0.0.xxx;
vec2 dx = vec2(SourceSize.z, 0.0);
vec2 dy = vec2(0.0, SourceSize.w);
float w, fp;
float wsum = 0.0;
vec3 pixel;
float FPR = FRANGE;
float FPR2 = 2.0*FPR;
float FPR3 = FPR2*FPR2;
float LOOPSIZE = FPR2;
float y = -LOOPSIZE;
float x = 0.0;
vec3 comp = COMPAT_TEXTURE(Source, tex).rgb;
do
{
x = -LOOPSIZE;
do
{
fp = dot(vec2(x+f.x,y+f.y),vec2(x+f.x,y+f.y));
if (fp >= FPR3) w = 0.0;
else
{
pixel = COMPAT_TEXTURE(Source, tex + x*dx + y*dy).rgb;
fp = sqrt(fp)/FPR;
w = getw(fp,comp,pixel);
color = color + w * pixel;
wsum = wsum + w;
}
x = x + 1.0;
} while (x <= LOOPSIZE);
y = y + 1.0;
} while (y <= LOOPSIZE);
color = color / wsum;
FragColor = vec4(color, 1.0);
}
Hey! Nice shader! I just tested here and it works great! For my tests and taste, the most sane options for me (tested with survival games) were these:
#pragma parameter FRANGE “Filter Range” 0.5 0.5 5.0 0.5 #pragma parameter FBSMOOTH “Filter Base Smoothing” 0.50 0.05 1.0 0.025 #pragma parameter FBOOST “Boost Smoothing w. dist” 1.0 0.0 5.0 0.25
I try to adjust the parameters to get rid of noise and let texture alone.
For instance, you can spot the transition between the sidewalk and the wall/door clearly at the original image here:
Using default params they are blended:
Using 0.5, 0.5 and 1.0 you can still see the transition between sidewalk and wall/door:
Thanks for testing!
The shader framework is OK i guess, but the effect largely depends on the metric. Please feel free to add something different (the float wt(vec3 A, vec3 B)
function), maybe it could look better…
Small but nice update to g-sharp_resampler 2.0.
Small speed gains with somewhat nicer appearance.
Update:
- filtering quality improvements
- kernel optimizations, notable performance increase
- dedithering (source-1x) preset added, needs some parameter tweaks
Download link:
https://mega.nz/file/U1YHmIzS#KDhQceABx9g4oYvf3HkNHANTymyGt0X3fUDYIxDeXFg
I made a slightly change to the wt formula and I think it preserves more some details. No idea if it’s just placebo, though. Using luma to calc intensity differences instead adding color channels:
float wt(vec3 A, vec3 B)
{
// return clamp(FBSMOOTH - ((6.0+0.25)/3.0) * dot(pow(abs(A-B),vec3(1.0/1.0)),1.0.xxx)/(dot(A+B,1.0.xxx)+0.25), 0.0001, 0.25);
return clamp(FBSMOOTH - ((6.0+0.25)/1.0) * dot(pow(abs(A-B),vec3(1.0/1.0)),luma)/(dot(A+B,luma)+0.25), 0.0001, 0.25);
}
EDIT: seeing some more examples now, I think it isn’t better or worse, just different. First formula prioritize color changes and the second, luma changes.