Editing newpixie-crt shader

I’ve discovered this shader and I love it, but it creates a black frame around the image. Here is a clear example:

Messing around with the slang I got to the conclusion that it has something to do with the curvature feature, but I’m too noob with this stuff to know what I’m doing…

I think this is the code that controls the black frame:

vec2 curve( vec2 uv )
    {
    uv = (uv - 0.5);// * 2.0;
//    uv.x *= 0.75;
    uv *= vec2(0.925, 1.095);  
   uv *= params.curvature;
    uv.x *= 1.0 + pow((abs(uv.y) / 4.0), 2.0);
    uv.y *= 1.0 + pow((abs(uv.x) / 3.0), 2.0);
    uv /= params.curvature;
    uv  += 0.5;
    uv =  uv *0.92 + 0.04;
    return uv;
    }

Can someone please help me to remove the curvature feature or at least to remove the black frame?

1 Like

Have you looked in the Shader Parameters Menu while you have a game running to see if there’s a parameter to adjust/disable the curvature or adjust the zoom/scaling of the viewport.

You might also be able to adjust this from the RetroArch Video—»Scaling menu.

Also, you can take a look at my preset pack which might also have some shader presets that you like.

It uses HSM Mega Bezel Reflection Shader, which includes a Newpixie-CRT-clone which is designed to work with it.

The parameters doesn’t fix it and the video setting has nothing to do with the issue. I suppose it was included as a feature to fully emulate a CRT, but as I don’t use curvature settings, it looks bad.

1 Like

Comment this line:

//    tc = tc * vec2(1.025, 0.92) + vec2(-0.0125, 0.04);

And invert this one:

 //   uv = scuv;
    scuv = uv;

You’ll loose cuvature functionality, though.

3 Likes

Holy shit, flawless! Thank you!

1 Like

OK, here is my edited slang with curvature and frame removed if someone wants it:

#version 450

// newpixie CRT
// by Mattias Gustavsson
// adapted for slang by hunterk

layout(push_constant) uniform Push
{
	vec4 SourceSize;
	vec4 OutputSize;
	uint FrameCount;
//	float use_frame;
//	float curvature;
	float wiggle_toggle;
	float scanroll;
} params;

//#pragma parameter use_frame "Use Frame Image" 0.0 0.0 1.0 1.0
//#define use_frame params.use_frame
//#pragma parameter curvature "Curvature" 2.0 0.0001 4.0 0.25
#pragma parameter wiggle_toggle "Interference" 0.0 0.0 1.0 1.0
#pragma parameter scanroll "Rolling Scanlines" 1.0 0.0 1.0 1.0

#define gl_FragCoord (vTexCoord.xy * params.OutputSize.xy)
#define backbuffer accum1
#define blurbuffer blur2
//#define frametexture frametexture

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()
{
   vec4 modpos = vec4(Position.x, 1.-Position.y, Position.z, Position.w);
   gl_Position = global.MVP * modpos;
   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;
layout(set = 0, binding = 3) uniform sampler2D accum1;
layout(set = 0, binding = 4) uniform sampler2D blur2;
//layout(set = 0, binding = 5) uniform sampler2D frametexture;

vec3 tsample( sampler2D samp, vec2 tc, float offs, vec2 resolution )
    {
//    tc = tc * vec2(1.025, 0.92) + vec2(-0.0125, 0.04);
    vec3 s = pow( abs( texture( samp, vec2( tc.x, 1.0-tc.y ) ).rgb), vec3( 2.2 ) );
    return s*vec3(1.25);
    }
		
vec3 filmic( vec3 LinearColor )
    {
    vec3 x = max( vec3(0.0), LinearColor-vec3(0.004));
    return (x*(6.2*x+0.5))/(x*(6.2*x+1.7)+0.06);
    }
		
vec2 curve( vec2 uv )
    {
    uv = (uv - 0.5);
    uv *= vec2(0.925, 1.095);  
//    uv *= params.curvature;
    uv.x *= 1.0 + pow((abs(uv.y) / 4.0), 2.0);
    uv.y *= 1.0 + pow((abs(uv.x) / 3.0), 2.0);
//    uv /= params.curvature;
    uv  += 0.5;
    uv =  uv *0.92 + 0.04;
    return uv;
    }
		
float rand(vec2 co)
    {
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
    }
    
#define resolution params.OutputSize.xy

void main()
{
    float time = mod(params.FrameCount, 849.0) *36.;
    vec2 uv = vTexCoord.xy;

    /* Curve */
    vec2 curved_uv = mix( curve( uv ), uv, 0.4 );
    float scale = -0.101;
    vec2 scuv = curved_uv*(1.0-scale)+scale/2.0+vec2(0.003, -0.001);

//    uv = scuv;
    scuv = uv;
		
    /* Main color, Bleed */
    vec3 col;
    float x = params.wiggle_toggle* sin(0.1*time+curved_uv.y*13.0)*sin(0.23*time+curved_uv.y*19.0)*sin(0.3+0.11*time+curved_uv.y*23.0)*0.0012;
    float o =sin(gl_FragCoord.y*1.5)/resolution.x;
    x+=o*0.25;
    time = float(mod(params.FrameCount, 640) * 1); 
    col.r = tsample(backbuffer,vec2(x+scuv.x+0.0009,scuv.y+0.0009),resolution.y/800.0, resolution ).x+0.02;
    col.g = tsample(backbuffer,vec2(x+scuv.x+0.0000,scuv.y-0.0011),resolution.y/800.0, resolution ).y+0.02;
    col.b = tsample(backbuffer,vec2(x+scuv.x-0.0015,scuv.y+0.0000),resolution.y/800.0, resolution ).z+0.02;
    float i = clamp(col.r*0.299 + col.g*0.587 + col.b*0.114, 0.0, 1.0 );
    i = pow( 1.0 - pow(i,2.0), 1.0 );
    i = (1.0-i) * 0.85 + 0.15; 
    
    /* Ghosting */
    float ghs = 0.15;
    vec3 r = tsample(blurbuffer, vec2(x-0.014*1.0, -0.027)*0.85+0.007*vec2( 0.35*sin(1.0/7.0 + 15.0*curved_uv.y + 0.9*time), 
        0.35*sin( 2.0/7.0 + 10.0*curved_uv.y + 1.37*time) )+vec2(scuv.x+0.001,scuv.y+0.001),
        5.5+1.3*sin( 3.0/9.0 + 31.0*curved_uv.x + 1.70*time),resolution).xyz*vec3(0.5,0.25,0.25);
    vec3 g = tsample(blurbuffer, vec2(x-0.019*1.0, -0.020)*0.85+0.007*vec2( 0.35*cos(1.0/9.0 + 15.0*curved_uv.y + 0.5*time), 
        0.35*sin( 2.0/9.0 + 10.0*curved_uv.y + 1.50*time) )+vec2(scuv.x+0.000,scuv.y-0.002),
        5.4+1.3*sin( 3.0/3.0 + 71.0*curved_uv.x + 1.90*time),resolution).xyz*vec3(0.25,0.5,0.25);
    vec3 b = tsample(blurbuffer, vec2(x-0.017*1.0, -0.003)*0.85+0.007*vec2( 0.35*sin(2.0/3.0 + 15.0*curved_uv.y + 0.7*time), 
        0.35*cos( 2.0/3.0 + 10.0*curved_uv.y + 1.63*time) )+vec2(scuv.x-0.002,scuv.y+0.000),
        5.3+1.3*sin( 3.0/7.0 + 91.0*curved_uv.x + 1.65*time),resolution).xyz*vec3(0.25,0.25,0.5);
		
    col += vec3(ghs*(1.0-0.299))*pow(clamp(vec3(3.0)*r,vec3(0.0),vec3(1.0)),vec3(2.0))*vec3(i);
    col += vec3(ghs*(1.0-0.587))*pow(clamp(vec3(3.0)*g,vec3(0.0),vec3(1.0)),vec3(2.0))*vec3(i);
    col += vec3(ghs*(1.0-0.114))*pow(clamp(vec3(3.0)*b,vec3(0.0),vec3(1.0)),vec3(2.0))*vec3(i);
		
    /* Level adjustment (curves) */
    col *= vec3(0.95,1.05,0.95);
    col = clamp(col*1.3 + 0.75*col*col + 1.25*col*col*col*col*col,vec3(0.0),vec3(10.0));
		
    /* Vignette */
    float vig = (0.1 + 1.0*16.0*curved_uv.x*curved_uv.y*(1.0-curved_uv.x)*(1.0-curved_uv.y));
    vig = 1.3*pow(vig,0.5);
    col *= vig;
    
    time *= params.scanroll;
		
    /* Scanlines */
    float scans = clamp( 0.35+0.18*sin(6.0*time-curved_uv.y*resolution.y*1.5), 0.0, 1.0);
    float s = pow(scans,0.9);
    col = col * vec3(s);
		
    /* Vertical lines (shadow mask) */
    col*=1.0-0.23*(clamp((mod(gl_FragCoord.xy.x, 3.0))/2.0,0.0,1.0));
		
    /* Tone map */
    col = filmic( col );
		
    /* Noise */
    vec2 seed = curved_uv*resolution.xy;;
    col -= 0.015*pow(vec3(rand( seed +time ), rand( seed +time*2.0 ), rand( seed +time * 3.0 ) ), vec3(1.5) );
		
    /* Flicker */
    col *= (1.0-0.004*(sin(50.0*time+curved_uv.y*2.0)*0.5+0.5));

    uv = curved_uv;

    /* Frame */
//    vec2 fscale = vec2( 0.026, -0.018);//vec2( -0.018, -0.013 );
//    uv = vec2(uv.x, 1.-uv.y);
//    vec4 f=texture(frametexture,vTexCoord.xy);//*((1.0)+2.0*fscale)-fscale-vec2(-0.0, 0.005));
//    f.xyz = mix( f.xyz, vec3(0.5,0.5,0.5), 0.5 );
//    float fvig = clamp( -0.00+512.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y), 0.2, 0.8 );
//    col = mix( col, mix( max( col, 0.0), pow( abs( f.xyz ), vec3( 1.4 ) ) * fvig, f.w * f.w), vec3( use_frame ) );
    
    FragColor = vec4( col, 1.0 );
}
3 Likes

Is it possible someone to add an interlacing functionality to this shader or perhaps show us how?

it’s not really possible due to the rolling scanlines, which itself is a sort of replacement for interlacing flicker. That is, I believe the entire notion of rolling scanlines comes from an optical illusion that can happen when you look at interlacing flicker on a blank screen. Your brain can interpret it as the scanlines rolling down (or up, I guess) the screen.

3 Likes

Hi there!! I’m just in love with this shader. One of the effects that really take me back to my teenage days is the “interference” effect.

Could you help me modify this parameter, to make it more subtle. Or failing that, name me which other shader has the same or similar effect? Thank you

The line that has ‘params.wiggle_toggle’ is where that happens. If you change the parameter line:

#pragma parameter wiggle_toggle "Interference" 0.0 0.0 1.0 1.0

to change that last 1.0 to, say, 0.05, that should let you dial in the intensity you want between the normal OFF/ON.

Wow thanx for this!!! you mean #pragma parameter wiggle_toggle “Interference” 0.0 0.0 0.05 0.05? thanx again

No just the last one. Those numbers mean:

default value, minimum value, maximum value, “step”

and “step” is how much the value changes on each tick as you cycle through, which is what you want to change. When the only options are 1 and 0, it’s essentially “on” for 1 and “off” for 0. So, you want to be able to change it to values in between 0 and 1.

1 Like

Amazing!! thanx thanx a lot!

I love this shader but I noticed that ‘blacks’ become greyish, is there anything that can be done to get true blacks? Also is there a parameter in the slang file to adjust convergence?

Those rolling scanlines never actually existed. You would see that if you would take a video of a crt screen on interlacing mode I believe. That’s why crt-consumer that mimics this look a bit doesn’t have any rolling scanlines.

2 Likes