Retro CRT Shader — A post processing effect study

Think back to those halcyon days when video games came on cartridges, controllers were square, and televisions were big, rounded, and weighed nearly as much as a fully loaded pickup truck. The days when computational speed was measured in megahertz, and when television was fuzzy pixels dancing across curved screens illuminated by cathode rays that may or may not have permanently damaged our eyes. Ahhh the memories…

https://atariage.com/forums/topic/271350-crt-tv-vs-modern-tv-for-retro-games/?do=findComment&comment=3876282
Don’t mind the banding, that’s just the aliasing of our scan lines when compressed. Though you sometimes see this effect when real photographs of CRTs are manipulated as well! — https://drigax.github.io/RooftopRampage/
https://thumbs.dreamstime.com/b/closeup-led-lights-bulb-diode-led-tv-led-monitor-screen-display-panel-closeup-led-lights-bulb-diode-led-tv-led-111461955.jpg
image borrowed from https://computer.howstuffworks.com/monitor7.htm
outUV = inUV(abs(inUV * 2 — 1) / curvature)² + inUV
1 dimensional view of remapped UVs after applying screen curvature filter.
#ifdef GL_ES
precision highp float;
#endif
// Samplers
varying vec2 vUV;
uniform sampler2D textureSampler;
// Parameters
uniform vec2 curvature;

vec2 curveRemapUV(vec2 uv)
{
// as we near the edge of our screen apply greater distortion using a cubic function
uv = uv * 2.0–1.0;
vec2 offset = abs(uv.yx) / vec2(curvature.x, curvature.y);
uv = uv + uv * offset * offset;
uv = uv * 0.5 + 0.5;
return uv;
}
void main(void)
{
vec2 remappedUV = curveRemapUV(vec2(vUV.x, vUV.y));
vec4 baseColor = texture2D(textureSampler, remappedUV);
if (remappedUV.x < 0.0 || remappedUV.y < 0.0 || remappedUV.x > 1.0 || remappedUV.y > 1.0){
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
} else {
gl_FragColor = baseColor;
}
}
BABYLON.Effect.ShadersStore["crtFragmentShader"] = `{shader code}`var postProcess = new BABYLON.PostProcess(“CRTShaderPostProcess”, “crt”, [“curvature”], null, 1, camera);postProcess.onApply = function (effect) {    effect.setFloat2(“curvature”, 3.0, 3.0);
}
var postProcess = new BABYLON.PostProcess(“CRTShaderPostProcess”, “crt”, [“curvature”], null, 0.25, camera);
dem pixels. https://dirkdigduggler.files.wordpress.com/2013/04/img_04301.jpg
(0.5 * sin(UV.x * screenSize.x * PI * 2) + 0.5) * 0.9 + 0.1
1-dimensional view of scan line filter over pixel intensity for a 15 pixel wide display.
```
vec4 scanLineIntensity(float uv, float resolution, float opacity)
{
float intensity = sin(uv * resolution * PI * 2.0);
intensity = ((0.5 * intensity) + 0.5) * 0.9 + 0.1;
return vec4(vec3(pow(intensity, opacity)), 1.0);
}



void main(void)
{


baseColor *= scanLineIntensity(remappedUV.x, screenResolution.y, scanLineOpacity.x);
baseColor *= scanLineIntensity(remappedUV.y, screenResolution.x, scanLineOpacity.y);

}
Brightened for clarity. https://playground.babylonjs.com/frame.html#PPPXW0#12
an oldie, but a goodie. http://www.retroaudiolab.com/tvphoto.htm
clamp((inUV * 1-inUV) * screenResolution/roundness)^vignetteOpacity, 0.0, 1.0)
Note the steep drop in pixel intensity as we reach the edges and corners.
Brightened for clarity — https://playground.babylonjs.com/frame.html#PPPXW0#13
 void main(void) 
{


baseColor *= vec4(vec3(brightness), 1.0);


}
NOT brightened for clarity :) — https://playground.babylonjs.com/frame.html#PPPXW0#14
That’s the good stuff. — https://drigax.github.io/RooftopRampage/

Babylon.js: Powerful, Beautiful, Simple, Open — Web-Based 3D At Its Best. https://www.babylonjs.com/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store