HQ4X Shader (like in Emulators)
Yo! NekotoArts here, and if I’m honest, I have no idea how actually useful this is.
Understanding how RetroArch and stuff are able to do the HQ4X was probably the worst nightmare I’ve had to sit through.
Seriously, take a look at this:
_x0063 = TEX0.xy*TextureSize;
_fp = fract(_x0063);
_a0065 = -5.00000000E-01 + _fp;
_val0065 = vec2(float((_a0065.x > 0.00000000E+00)), float((_a0065.y > 0.00000000E+00)));
_TMP0 = _val0065 - vec2(float((_a0065.x < 0.00000000E+00)), float((_a0065.y < 0.00000000E+00)));
_quad = vec2(float(_TMP0.x), float(_TMP0.y));
_TMP1 = COMPAT_TEXTURE(Texture, TEX0.xy);
_c0069 = TEX0.xy + vec2(VARps.x, VARps.y)*vec2(float(_quad.x), float(_quad.y));
_TMP2 = COMPAT_TEXTURE(Texture, _c0069);
_c0071 = TEX0.xy + vec2(VARps.x, 0.00000000E+00)*vec2(float(_quad.x), float(_quad.y));
_TMP3 = COMPAT_TEXTURE(Texture, _c0071);
_c0073 = TEX0.xy + vec2(0.00000000E+00, VARps.y)*vec2(float(_quad.x), float(_quad.y));
Ye… I have no idea either.
So if the shader has some artifacts… have mercy on me plz.
Made to be used with a Sprite node.
Shader code
shader_type canvas_item;
/*
Made with a whole lot of nightmare fuel.
Logic's Under Pressure and Bobby Tarantino II Albums was in rotation during
the making process.
Hope you enjoy!
You're auto-friended to me if you're a Logic fan
RattPack all day!
*/
//image mipmap level, for base upscaling
const int ML = 0;
//equality threshold of 2 colors before forming lines
uniform float THRESHOLD = 0.1;
//anti aliasing scaling, smaller value make lines more blurry
uniform float AA_SCALE = 10.0;
//draw diagonal line connecting 2 pixels if within threshold
bool diag(inout vec4 sum, vec2 uv, vec2 p1, vec2 p2, sampler2D iChannel0, float LINE_THICKNESS) {
vec4 v1 = texelFetch(iChannel0,ivec2(uv+vec2(p1.x,p1.y)),ML),
v2 = texelFetch(iChannel0,ivec2(uv+vec2(p2.x,p2.y)),ML);
if (length(v1-v2) < THRESHOLD) {
vec2 dir = p2-p1,
lp = uv-(floor(uv+p1)+.5);
dir = normalize(vec2(dir.y,-dir.x));
float l = clamp((LINE_THICKNESS-dot(lp,dir))*AA_SCALE,0.,1.);
sum = mix(sum,v1,l);
return true;
}
return false;
}
void fragment(){
//line thickness
float LINE_THICKNESS;
vec2 ip = UV * (1.0 / TEXTURE_PIXEL_SIZE);
//start with nearest pixel as 'background'
vec4 s = texelFetch(TEXTURE,ivec2(int(ip.x),int(ip.y)),ML);
//draw anti aliased diagonal lines of surrounding pixels as 'foreground'
LINE_THICKNESS = 0.4;
if (diag(s,ip,vec2(-1,0),vec2(0,1), TEXTURE, LINE_THICKNESS)) {
LINE_THICKNESS = 0.3;
diag(s,ip,vec2(-1,0),vec2(1,1), TEXTURE, LINE_THICKNESS);
diag(s,ip,vec2(-1,-1),vec2(0,1), TEXTURE, LINE_THICKNESS);
}
LINE_THICKNESS = 0.4;
if (diag(s,ip,vec2(0,1),vec2(1,0), TEXTURE, LINE_THICKNESS)) {
LINE_THICKNESS = 0.3;
diag(s,ip,vec2(0,1),vec2(1,-1), TEXTURE, LINE_THICKNESS);
diag(s,ip,vec2(-1,1),vec2(1,0), TEXTURE, LINE_THICKNESS);
}
LINE_THICKNESS = 0.4;
if (diag(s,ip,vec2(1,0),vec2(0,-1), TEXTURE, LINE_THICKNESS)) {
LINE_THICKNESS = 0.3;
diag(s,ip,vec2(1,0),vec2(-1,-1), TEXTURE, LINE_THICKNESS);
diag(s,ip,vec2(1,1),vec2(0,-1), TEXTURE, LINE_THICKNESS);
}
LINE_THICKNESS = 0.4;
if (diag(s,ip,vec2(0,-1),vec2(-1,0), TEXTURE, LINE_THICKNESS)) {
LINE_THICKNESS = 0.3;
diag(s,ip,vec2(0,-1),vec2(-1,1), TEXTURE, LINE_THICKNESS);
diag(s,ip,vec2(1,-1),vec2(-1,0), TEXTURE, LINE_THICKNESS);
}
COLOR = s;
}
I tried here but no result, maybe it only works with sprite instead of Control,ColorRect?
My bad! I forgot to mention that its made to be used with a Sprite node.
I’ll add that into the description!
Hello, used your shader in https://declivever.itch.io/wizard-jump
Oh hey! Thanks for sharing! I played your game and its really nice to see how far you’ve come with Godot, keep it up dude!
Hey, this seems like it could be really useful for something like an Animal Crossing Texture designer.
I think their texture editor clothing patterns uses a shader like this.
The number of texture samples can be reduced by saving and reusing the values to improve performance.
http://blog.pkh.me/p/19-butchering-hqx-scaling-filters.html