CRT screen
Barrel curve, scanlines and chromatic split over a plain 2D scene. The whole look is one fullscreen pass.
The editor above is running this project. Change a line and it reloads.
Godot classes used
ColorRectCanvasLayerPolygon2D
The code
scripts/main.gd
extends Node
var bars: Array[Polygon2D] = []
var elapsed: float = 0.0
func _ready() -> void:
var view: Vector2 = get_viewport().get_visible_rect().size
var background: ColorRect = ColorRect.new()
background.color = Color('#101820')
add_child(background)
background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
for i in 8:
var bar: Polygon2D = Polygon2D.new()
bar.polygon = PackedVector2Array([Vector2.ZERO, Vector2(90, 0), Vector2(90, 260), Vector2(0, 260)])
bar.color = Color.from_hsv(float(i) / 8.0, 0.55, 0.95)
bar.position = Vector2(view.x * 0.5 - 400 + i * 100, view.y * 0.5 - 130)
add_child(bar)
bars.append(bar)
var title: Label = Label.new()
title.text = 'CRT POST PROCESSING'
title.add_theme_font_size_override('font_size', 42)
title.position = Vector2(view.x * 0.5 - 250, view.y * 0.2)
add_child(title)
# the ColorRect sits on a CanvasLayer above everything and reads what was already drawn
var layer: CanvasLayer = CanvasLayer.new()
layer.layer = 10
add_child(layer)
var material: ShaderMaterial = ShaderMaterial.new()
material.shader = Get.shader('crt')
var screen: ColorRect = ColorRect.new()
screen.material = material
layer.add_child(screen)
screen.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
print('the scene below is plain 2D, the whole look is one fullscreen shader')
func _process(delta: float) -> void:
elapsed += delta
for i in bars.size():
bars[i].scale.y = 0.4 + 0.6 * abs(sin(elapsed * 1.5 + i * 0.6))shaders/crt.gdshader
shader_type canvas_item;
uniform sampler2D screen_texture: hint_screen_texture, filter_linear;
uniform float curvature = 0.18;
uniform float scanline_strength = 0.35;
uniform float scanline_count = 320.0;
uniform float chromatic = 0.0018;
void fragment() {
vec2 centered = SCREEN_UV * 2.0 - 1.0;
centered *= 1.0 + curvature * dot(centered, centered) * 0.35;
vec2 uv = centered * 0.5 + 0.5;
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
COLOR = vec4(0.0, 0.0, 0.0, 1.0);
} else {
float r = texture(screen_texture, uv + vec2(chromatic, 0.0)).r;
float g = texture(screen_texture, uv).g;
float b = texture(screen_texture, uv - vec2(chromatic, 0.0)).b;
float line = 1.0 - scanline_strength * step(0.5, fract(uv.y * scanline_count));
float edge = 1.0 - 0.6 * dot(centered, centered) * 0.25;
COLOR = vec4(vec3(r, g, b) * line * edge, 1.0);
}
}