Voorbij de pixels: De wetenschap van CRT Shaders in de browser
Inhoudsopgave
Als je een klassiek 8-bit- of 16-bit-spel opent op een moderne 4K-monitor of het OLED-scherm van een smartphone met hoge resolutie, voelt er iets “niet helemaal goed”. De kleuren zien er hard uit, de randen zijn gekarteld en de grafische weergave lijkt hoekiger dan je je herinnert. Dit is niet alleen nostalgie die je voor de gek houdt – het is een fundamentele mismatch tussen de hardware.
Op Rec0m88, we willen niet alleen dat de games werken; we willen ook dat ze eruitzien zoals de oorspronkelijke ontwerpers het bedoeld hebben. Om dit te bereiken, hebben we geavanceerde GLSL (OpenGL Shading Language) wordt naar onze “machinekamer” gestuurd om de complexe fysica van een kathodestraalbuis (CRT) te simuleren. Hier volgt een technische uitleg van hoe we GPU-rekenkracht gebruiken om de kloof tussen 1992 en 2026 te overbruggen.
Het LCD-probleem: de misvatting van de “vierkante pixel”
Retrogames waren nooit bedoeld om te worden gezien als een perfect raster van scherpe vierkantjes. Op een ouderwetse CRT-monitor waren de “pixels” helemaal geen vierkantjes; het waren gloeiende fosfordeeltjes die door een elektronenstraal werden geraakt. Dit zorgde voor verschillende natuurlijke visuele effecten:
- Scanlijnen: Donkere openingen tussen de lijnen op de plekken waar de elektronenstraal weer over het scherm terugging.
- Kleurdoorbloeding: De rode, groene en blauwe fosforen zouden elkaar enigszins overlappen, waardoor “nieuwe” kleuren ontstaan die niet in het digitale bestand voorkomen.
- The Glow: Gebieden met een hoge helderheid zouden in de omliggende donkere gebieden “uitlopen”.
Als je diezelfde pixels op een modern LCD-scherm weergeeft, is elke pixel een blok met scherpe randen en een steriele uitstraling. Hierdoor ziet de kunst er “onaf” uit, omdat de oorspronkelijke kunstenaars de natuurlijke onscherpte van de CRT gebruikten om “trucs om de zaken onduidelijk te maken” en kleurmenging.
De oplossing: GLSL-shaders in het HTML5-canvas
Om dit te verhelpen, “rek” onze moderne arcade de afbeelding niet zomaar uit om je scherm te vullen. We leiden de video-uitvoer van het spel door een nabewerkingspijplijn met behulp van WebGL 2.0.
A Shader is een klein programma dat rechtstreeks op je grafische kaart (GPU) draait. In plaats van dat de CPU elke pixel één voor één berekent, berekent de GPU duizenden pixels tegelijk met behulp van coördinatenmeetkunde. Op Rec0m88 maken we gebruik van verschillende lagen shaders:
1. De scanline-overlay
We berekenen de verticale coördinaat van elke pixel. Als de coördinaat op een “even” lijn valt, passen we een lichte verduisteringsfactor toe. Hierdoor worden de horizontale openingen nagebootst die retro-games hun textuur en diepte gaven. Een simpele zwarte lijn is echter te hard. Onze shaders maken gebruik van Gaussiaanse vervaging om ervoor te zorgen dat de scanlijnen er natuurlijk uitzien, en niet als een kooi over het scherm.
2. Simulatie van diafragmarooster en schaduwmasker
Bij hoogwaardige “Trinitron”-monitoren werd gebruikgemaakt van een apertuuroppervlak: fijne verticale draadjes die de fosfordeeltjes van elkaar scheidden. Onze geavanceerde shaders simuleren dit door een subpixelmasker toe te passen. Als je inzoomt op een Rec0m88-game waarop onze “Pro”-shader draait, zie je de microscopisch kleine rode, groene en blauwe verticale streepjes die de fysieke structuur van een hoogwaardige arcademonitor nabootsen.
3. Kromming en afronding van hoeken
Het glas van een oude tv was niet vlak; het was een bolvormige glazen kap. Onze motor kan een coördinaat-ketting waardoor de randen van het spelvenster subtiel worden afgerond. Hoewel dit puur esthetisch lijkt, helpt het in feite bij het “volgen van de blik” tijdens snelle gameplay, omdat het de aandacht gecentreerd houdt op de plek waar de actie het meest intens is.
Een evenwicht vinden tussen betrouwbaarheid en prestaties
De grootste uitdaging bij het uitvoeren van shaders in een browser is prestatie-overhead. Een complexe shader zoals “CRT-Geom” of “CRT-Royale” vereist voor elk afzonderlijk frame een aanzienlijke hoeveelheid rekenwerk door de GPU. Als de shader meer dan 2-3 milliseconden nodig heeft om te berekenen, gaat dit ten koste van het “framebudget” van 16,6 ms dat we nodig hebben voor de WebAssembly-emulatorkern.
Om dit op te lossen, maakt Rec0m88 gebruik van Adaptieve schaduwweergave:
- Geoptimaliseerd voor mobiel: Als onze engine een mobiele browser detecteert, schakelt deze over naar een “light”-versie van de shader die gebruikmaakt van een vooraf berekende opzoektabel (LUT) in plaats van realtime fysica-berekeningen.
- Desktop Ultra: Voor gebruikers met een aparte grafische kaart ondersteunen we multi-pass shading, waardoor bloomeffecten, fosforpersistentie (het “spoor” dat heldere objecten achterlaten) en zelfs glasreflecties mogelijk zijn.




