Simple scanline effect via glsl shader?

While I’m very happy with the results achieved using the crt shaders currently available, I couldn’t find any shaders that just do simple, uniform scanlines with adjustable opacity and no other effects, as you would get using an overlay or an external scanline generator. Some might prefer sharp pixels but still want scanlines in their games. I looked at “scanlines.glsl,” but found the parameter options to not be very user-friendly and couldn’t figure out how to achieve the desired effect. Overlays caused performance issues on my NUC6CAYS. I don’t know code, but I was imagining something like the following:

Parameter options: scanline width - “thick” or “thin” scanline opacity - 0 to 100

“thin” scanlines- blank 2 rows of pixels, skip 2 rows, blank 2 rows of pixels, etc. Used for 3x and 4x integer scale.

“thick” scanlines - blank 3 rows of pixels, skip 2 rows, blank 3 rows of pixels, etc. Used for 5x integer scale.

scanline opacity - adjusts how transparent the scanlines are, with 100 being completely black.

Try this one (if it does what you need, I’ll add it to the repos). The ‘thickness’ parameter represents pixels on your display, so 4x and 5x should get a value of 2, 2x and 3x should get a value of 1, etc. This probably goes without saying, but it looks awful at non-integer scales, so don’t even bother:

#pragma parameter THICKNESS "Scanline Thickness" 1.0 1.0 12.0 1.0
#pragma parameter DARKNESS "Scanline Darkness" 0.50 0.0 1.0 0.01
#pragma parameter BRIGHTBOOST "Scanline Boost Bright" 1.1 1.0 2.0 0.01

#if defined(VERTEX)

#if __VERSION__ >= 130
#define COMPAT_VARYING out
#define COMPAT_ATTRIBUTE in
#define COMPAT_TEXTURE texture
#else
#define COMPAT_VARYING varying 
#define COMPAT_ATTRIBUTE attribute 
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

COMPAT_ATTRIBUTE vec4 VertexCoord;
COMPAT_ATTRIBUTE vec4 COLOR;
COMPAT_ATTRIBUTE vec4 TexCoord;
COMPAT_VARYING vec4 COL0;
COMPAT_VARYING vec4 TEX0;

vec4 _oPosition1; 
uniform mat4 MVPMatrix;
uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;

// compatibility #defines
#define vTexCoord TEX0.xy
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

void main()
{
    gl_Position = MVPMatrix * VertexCoord;
    TEX0.xy = TexCoord.xy * 1.0004;
}

#elif defined(FRAGMENT)

#if __VERSION__ >= 130
#define COMPAT_VARYING in
#define COMPAT_TEXTURE texture
out vec4 FragColor;
#else
#define COMPAT_VARYING varying
#define FragColor gl_FragColor
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;
uniform sampler2D Texture;
COMPAT_VARYING vec4 TEX0;

// compatibility #defines
#define Source Texture
#define vTexCoord TEX0.xy
#define texture(c, d) COMPAT_TEXTURE(c, d)
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

#ifdef PARAMETER_UNIFORM
// All parameter floats need to have COMPAT_PRECISION in front of them
uniform COMPAT_PRECISION float THICKNESS;
uniform COMPAT_PRECISION float DARKNESS;
uniform COMPAT_PRECISION float BRIGHTBOOST;
#else
#define THICKNESS 1.0
#define DARKNESS 0.5
#define BRIGHTBOOST 1.1
#endif

vec3 RGBtoYIQ(vec3 RGB){
	const mat3 yiqmat = mat3(
		0.2989, 0.5870, 0.1140,
		0.5959, -0.2744, -0.3216,
		0.2115, -0.5229, 0.3114);
	return RGB * yiqmat;
}

vec3 YIQtoRGB(vec3 YIQ){
	const mat3 rgbmat = mat3(
		1.0, 0.956, 0.6210,
		1.0, -0.2720, -0.6474,
		1.0, -1.1060, 1.7046);
	return YIQ * rgbmat;
}

void main()
{
	float lines = fract(vTexCoord.y * SourceSize.y);
	float scale_factor = OutputSize.y / InputSize.y;
	vec4 screen = texture(Source, vTexCoord);
	screen.rgb = RGBtoYIQ(screen.rgb);
	screen.r *= BRIGHTBOOST;
	screen.rgb = YIQtoRGB(screen.rgb);

    FragColor = (lines > (1.0 / scale_factor * THICKNESS)) ? screen : screen * vec4(1.0 - DARKNESS);
} 
#endif
1 Like

That’s perfect! Very easy to use, works exactly as described. Should definitely be added to the repos. Thanks! :smiley:

1 Like

Hi @Nesguy, i know i’m too late but just in case we just released a little software that allow you to add scanlines diectly on windows very simply. Opacity is adjustable and png’s templates are editable with photoshop. No blur effect, only black lines. We did it initially for Pixel art Pc Games. Here it is if you’re still interested.
Website : https://scanline-for-windows-21.webselfsite.net/ Website Mirror 1 : https://scanline-for-windows-59.webselfsite.net/
Have a nice day and good game. (Sorry for all this links but i did the website on a free plateform so bandwidth is limited)

2 Likes

Hello !!! 2.0 version is available, you can now save more profiles and it will switch automatically between them + you can choose english/french language

Website : https://scanlines-for-windows-14.webselfsite.net/ (replace 14 by 16 or 98 in the link if this website has reached maximum bandwith limit)

Download link : S4W : https://www.mediafire.com/file/2ftew7fqszycfuo/S4W_2.0.rar/file

Cheers