Help removing geometry distortion from crt-mattias

Today I’ve discovered this great shader, i am really enjoying it but since nothing is perfect there’s one aspect of it i’d like to change. It looks like the shader simulates a geometry distortion, which results in a not so pleasant effect especially in games with relevant scrolling images.

Below is a screenshot from 240p suite showing the distortion, the shader doesn’t have preferences to configure too. The shader was added by hunterk on Aug 13 2018.

It looks like the shader apparently works really well for 480p, i’d love to see it converted to glsl too, wish i could try it with reicast too.

1 Like

Just comment out line 116, like this:

//uv = mix( curve( uv ), uv, 0.5 );

I’ve tried a few times, first i’ve just added the the 2 slashes, didn’t work, then i copied your entire line and saved, still nothing.

What you think i might be doing wrong ?

Seems to work find on my end, though there’s still some waviness in the y axis.

I’ve changed the value from 0.5 to 0 and 1 and what changed was the curvature not the distortion, is there another parameter to change which can affect the distortion ?

EDIT: it looks like this at 1.0

Ok, yeah, I thought the curvature was what you were wanting to get rid of. You can get rid of the wavy distortion by removing all of the instances of the ‘x’ variable from the sampling lines. Here’s the whole shader with them removed:

#version 450

// CRT Emulation
// by Mattias
// https://www.shadertoy.com/view/lsB3DV

layout(push_constant) uniform Push
{
	vec4 SourceSize;
	vec4 OriginalSize;
	vec4 OutputSize;
	uint FrameCount;
} params;

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;
}

#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;

#define iChannel0 Source
#define iTime (float(params.FrameCount) / 60.0)
#define iResolution params.OutputSize.xy
#define fragCoord (vTexCoord.xy * params.OutputSize.xy)

vec3 sample_( sampler2D tex, vec2 tc )
{
	vec3 s = pow(texture(tex,tc).rgb, vec3(2.2));
	return s;
}

vec3 blur(sampler2D tex, vec2 tc, float offs)
{
	vec4 xoffs = offs * vec4(-2.0, -1.0, 1.0, 2.0) / iResolution.x;
	vec4 yoffs = offs * vec4(-2.0, -1.0, 1.0, 2.0) / iResolution.y;
	
	vec3 color = vec3(0.0, 0.0, 0.0);
	color += sample_(tex,tc + vec2(xoffs.x, yoffs.x)) * 0.00366;
	color += sample_(tex,tc + vec2(xoffs.y, yoffs.x)) * 0.01465;
	color += sample_(tex,tc + vec2(    0.0, yoffs.x)) * 0.02564;
	color += sample_(tex,tc + vec2(xoffs.z, yoffs.x)) * 0.01465;
	color += sample_(tex,tc + vec2(xoffs.w, yoffs.x)) * 0.00366;
	
	color += sample_(tex,tc + vec2(xoffs.x, yoffs.y)) * 0.01465;
	color += sample_(tex,tc + vec2(xoffs.y, yoffs.y)) * 0.05861;
	color += sample_(tex,tc + vec2(    0.0, yoffs.y)) * 0.09524;
	color += sample_(tex,tc + vec2(xoffs.z, yoffs.y)) * 0.05861;
	color += sample_(tex,tc + vec2(xoffs.w, yoffs.y)) * 0.01465;
	
	color += sample_(tex,tc + vec2(xoffs.x, 0.0)) * 0.02564;
	color += sample_(tex,tc + vec2(xoffs.y, 0.0)) * 0.09524;
	color += sample_(tex,tc + vec2(    0.0, 0.0)) * 0.15018;
	color += sample_(tex,tc + vec2(xoffs.z, 0.0)) * 0.09524;
	color += sample_(tex,tc + vec2(xoffs.w, 0.0)) * 0.02564;
	
	color += sample_(tex,tc + vec2(xoffs.x, yoffs.z)) * 0.01465;
	color += sample_(tex,tc + vec2(xoffs.y, yoffs.z)) * 0.05861;
	color += sample_(tex,tc + vec2(    0.0, yoffs.z)) * 0.09524;
	color += sample_(tex,tc + vec2(xoffs.z, yoffs.z)) * 0.05861;
	color += sample_(tex,tc + vec2(xoffs.w, yoffs.z)) * 0.01465;
	
	color += sample_(tex,tc + vec2(xoffs.x, yoffs.w)) * 0.00366;
	color += sample_(tex,tc + vec2(xoffs.y, yoffs.w)) * 0.01465;
	color += sample_(tex,tc + vec2(    0.0, yoffs.w)) * 0.02564;
	color += sample_(tex,tc + vec2(xoffs.z, yoffs.w)) * 0.01465;
	color += sample_(tex,tc + vec2(xoffs.w, yoffs.w)) * 0.00366;

	return color;
}

//Canonical noise function; replaced to prevent precision errors
//float rand(vec2 co){
//    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
//}

float rand(vec2 co)
{
    float a = 12.9898;
    float b = 78.233;
    float c = 43758.5453;
    float dt= dot(co.xy ,vec2(a,b));
    float sn= mod(dt,3.14);
    return fract(sin(sn) * c);
}

vec2 curve(vec2 uv)
{
	uv = (uv - 0.5) * 2.0;
	uv *= 1.1;	
	uv.x *= 1.0 + pow((abs(uv.y) / 5.0), 2.0);
	uv.y *= 1.0 + pow((abs(uv.x) / 4.0), 2.0);
	uv  = (uv / 2.0) + 0.5;
	uv =  uv *0.92 + 0.04;
	return uv;
}

void main()
{
    vec2 q = fragCoord.xy / iResolution.xy;
    vec2 uv = q;
//    uv = mix( curve( uv ), uv, 0.5 );
    vec3 oricol = texture( iChannel0, vec2(q.x,q.y) ).xyz;
    vec3 col;
	float x =  sin(0.1*iTime+uv.y*21.0)*sin(0.23*iTime+uv.y*29.0)*sin(0.3+0.11*iTime+uv.y*31.0)*0.0017;
	float o =2.0*mod(fragCoord.y,2.0)/iResolution.x;
	x+=o;
    col.r = 1.0*blur(iChannel0,vec2(uv.x+0.0009,uv.y+0.0009),1.2).x+0.005;
    col.g = 1.0*blur(iChannel0,vec2(uv.x+0.000,uv.y-0.0015),1.2).y+0.005;
    col.b = 1.0*blur(iChannel0,vec2(uv.x-0.0015,uv.y+0.000),1.2).z+0.005;
    col.r += 0.2*blur(iChannel0,vec2(uv.x+0.0009,uv.y+0.0009),2.25).x-0.005;
    col.g += 0.2*blur(iChannel0,vec2(uv.x+0.000,uv.y-0.0015),1.75).y-0.005;
    col.b += 0.2*blur(iChannel0,vec2(uv.x-0.0015,uv.y+0.000),1.25).z-0.005;
    float ghs = 0.05;
	col.r += ghs*(1.0-0.299)*blur(iChannel0,0.75*vec2(0.01, -0.027)+vec2(uv.x+0.001,uv.y+0.001),7.0).x;
    col.g += ghs*(1.0-0.587)*blur(iChannel0,0.75*vec2(-0.022, -0.02)+vec2(uv.x+0.000,uv.y-0.002),5.0).y;
    col.b += ghs*(1.0-0.114)*blur(iChannel0,0.75*vec2(-0.02, -0.0)+vec2(uv.x-0.002,uv.y+0.000),3.0).z;

    col = clamp(col*0.4+0.6*col*col*1.0,0.0,1.0);

    float vig = (0.0 + 1.0*16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y));
	vig = pow(vig,0.3);
	col *= vec3(vig);

    col *= vec3(0.95,1.05,0.95);
	col = mix( col, col * col, 0.3) * 3.8;

	float scans = clamp( 0.35+0.15*sin(3.5*iTime+uv.y*iResolution.y*1.5), 0.0, 1.0);
	
	float s = pow(scans,0.9);
	col = col*vec3( s) ;

    col *= 1.0+0.0015*sin(300.0*iTime);
	
	col*=1.0-0.15*vec3(clamp((mod(fragCoord.x+o, 2.0)-1.0)*2.0,0.0,1.0));
	col *= vec3( 1.0 ) - 0.25*vec3( rand( uv+0.0001*iTime),  rand( uv+0.0001*iTime + 0.3 ),  rand( uv+0.0001*iTime+ 0.5 )  );
	col = pow(col, vec3(0.45));

	if (uv.x < 0.0 || uv.x > 1.0)
		col *= 0.0;
	if (uv.y < 0.0 || uv.y > 1.0)
		col *= 0.0;
	

    float comp = smoothstep( 0.1, 0.9, sin(iTime) );

    FragColor = vec4(col,1.0);
}
3 Likes

Perfect! the wavy distortion is now gone and also the curvature : ( , is it possible keep the curvature and get rid of only the distortion ?

EDIT! It worked! I’ve removed the 2 slashes from your previous post and now it’s curved and aligned! Thanks a lot!!!

2 Likes

Remove // from this and it should fix it, I think.

// uv = mix( curve( uv ), uv, 0.5 );

EDIT: Crap. I’ve been ninja’d. Well at least you got it working.

: D Thanks! Do you have any plans to port/convert it to glsl ?

Nice looking shader! Did not know about its existence. I like the vignette effect of the shadow to give depth to the curvature.

1 Like

Yes, i am pretty happy with it, combined with a good overlay it looks wonderful

3 Likes

Looks great!

@hunterk can it be ported to glsl? Or is there a diy guide somewhere? I would love to have this shader in glsl.

EDIT: Nevermind, I just saw it in the shaders repo! Thanks :smiley:

1 Like

@hunterk Thanks a lot! I really like the look of this shader and this made it even better :blush:

oh I was trying to do this on my own and failing. by far the best looking CRT shader imo.

Glad I have found this post :slight_smile: all be it bit late :stuck_out_tongue:

Thanks you!

Hi Peeps

Does anyone know how to reduce the shadowing / ghosting type effect? or at least point me in the right direction?

thanks in advance.

nvm I found it.

I adjust the value of the line below until it got looking like it want :slight_smile: float ghs = 0.05;

@hunterk

Did you use basically this update for the actual repo? (Except adding a curvature toggle?)

I’m asking because I’m trying to recreate the distortion/wavy effect (in crt-guest-dr-venom) and looking over the code in the repo (for crt-mattias) I can’t find the x samples you reference here.

Any assistance would be a godsend, as the majority of the time I feel like a monkey just bashing keys on the keyboard hoping things work.

looks like it, yeah: https://github.com/libretro/slang-shaders/commit/969a763d35aca2626d3b61990f4b041a96b17b3f

You can see the older version in the git history:

1 Like

Any suggestions on moving this type of effect into crt-guest-dr-venom?

It’s just offsetting the horizontal value of the texture coordinate by a pseudo-random amount when it’s being sampled. You could probably do the same thing in crt-guest-dr-venom, but i’m not sure how good it would look, as it uses far fewer sample functions.

1 Like