56 lines
1.6 KiB
JavaScript
56 lines
1.6 KiB
JavaScript
// CRTPipeline – PostFX pipeline that simulates a classic CRT monitor:
|
||
// - Barrel distortion (curved screen edges)
|
||
// - Scanlines (every other row darkened)
|
||
// - Vignette (edge darkening)
|
||
|
||
const fragShader = `
|
||
precision mediump float;
|
||
|
||
uniform sampler2D uMainSampler;
|
||
uniform vec2 uResolution;
|
||
|
||
varying vec2 outTexCoord;
|
||
|
||
void main (void) {
|
||
// --- Screen curvature (barrel distortion) ---
|
||
// Remap UV from [0,1] to centred [-0.5,0.5], distort, remap back
|
||
vec2 uv = outTexCoord;
|
||
vec2 dc = uv - 0.5;
|
||
float strength = 0.18;
|
||
uv = uv + dc * dot(dc, dc) * strength;
|
||
|
||
// Pixels pushed outside [0,1] become black (the CRT bezel)
|
||
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
|
||
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||
return;
|
||
}
|
||
|
||
// --- Base colour ---
|
||
vec4 color = texture2D(uMainSampler, uv);
|
||
|
||
// --- Scanlines ---
|
||
// Every other screen-pixel row is darkened by ~28%
|
||
float lineY = uv.y * uResolution.y;
|
||
float scanline = mod(floor(lineY), 2.0);
|
||
color.rgb *= mix(1.0, 0.72, scanline);
|
||
|
||
// --- Vignette ---
|
||
float vig = 1.4 - dot(dc * 1.8, dc * 1.8);
|
||
vig = clamp(vig, 0.0, 1.0);
|
||
vig = pow(vig, 0.45);
|
||
color.rgb *= vig;
|
||
|
||
gl_FragColor = color;
|
||
}
|
||
`;
|
||
|
||
export default class CRTPipeline extends Phaser.Renderer.WebGL.Pipelines.PostFXPipeline {
|
||
constructor(game) {
|
||
super({ game, name: 'CRTPipeline', fragShader });
|
||
}
|
||
|
||
onPreRender() {
|
||
this.set2f('uResolution', this.game.scale.width, this.game.scale.height);
|
||
}
|
||
}
|