Woher kommt das Licht in den Backrooms? Du hängst Lampen an die Wand, stellst ein Sofa in die Kammer und holst dir Möbel aus dem Internet. Dann gehst du in den Maschinenraum und siehst zu, wie das Programm das Licht berechnet: Punkt für Punkt, Strahl für Strahl, das Licht, das von den Wänden zurückfällt, und die dunklen Ecken. Zum Schluss veröffentlichst du dein Level, und ein fertiges Level wartet auf dich, die Nachtschicht, deren Räume du jetzt Zeile für Zeile lesen kannst.
Seltsam ist die Decke. Die Leuchten hängen direkt darunter und strahlen nach unten, und trotzdem ist die Decke hell.
Funkspruch, zweiter Teil| Level | 3, »Das Licht« |
|---|---|
| Überlebensschwierigkeit | Klasse 1: hell, warm, sehr ruhig |
| Ausdehnung | so weit das Licht reicht |
| Ausgänge | keine bekannten. Aber eine Tür in ein anderes Level (siehe »Die Nachtschicht«). |
Diese Seite baut auf Level 2 auf: auf deinem Level, so wie es am Ende von Level 2 war, mit dem Bad und dem Becken im Schacht. Öffne den Ordner /workspace/backrooms-starter wieder in VS Code und starte die Vorschau (»Go Live«).
Eine Leuchte hängt knapp unter der Decke, mitten über ihrem Feld, unter einer schrägen Decke so schräg wie sie:
| Eintrag | Bedeutung |
|---|---|
light |
ihre Farbe, zum Beispiel #fff3cf
|
power |
wie hell sie ist, 1.0 ohne Angabe |
size |
Breite und Länge in Metern, eine Zahl für eine quadratische; ohne Angabe 0.85, 85 cm im Quadrat |
flicker |
1: Sie flackert ab und zu |
Farbiges Licht färbt alles, was es trifft, auch über die Tür hinaus in den Nachbarraum: Im Gang siehst du, wie rotes und blaues Licht aus zwei Türen fällt.
In der Kammer steht jetzt ein Sofa. Niemand hat es gebracht. An den Wänden hängen zwei Lampen, und sie brennen, obwohl nirgends ein Kabel ist.
Seite aus einem durchnässten Notizbuch, dritte HandschriftWas hier Leuchte heißt, ist ein helles Feld, das immer unter der Decke hängt. Licht kann aber auch aus einem Modell kommen, einer Lampe: einer Wandlampe, einer Stehlampe, einer Laterne. Die Kammer wird ein Ruheraum. Statt der flackernden Leuchte an der Decke hängen zwei Wandlampen an den Wänden, und an der Südwand steht ein Sofa. Ersetze rooms/kammer.room durch:
# Eine Kammer, die gestern noch nicht da war. Jetzt steht ein Sofa darin. [room] name = Kammer height = 2.2 wallpaper = #9a8a4c [map] ##### 5...6 #W.E# #.S.# ##### [W] model = models/industrial_wall_lamp/industrial_wall_lamp_1k.gltf # Poly Haven, CC0 height = 0.43 rotation = 90 offset = -0.42, 1.4, 0 # an die Westwand, 1,4 m hoch light = #ffd9a0 power = 1.2 [E] model = models/industrial_wall_lamp/industrial_wall_lamp_1k.gltf # Poly Haven, CC0 height = 0.43 rotation = 270 offset = 0.42, 1.4, 0 # an die Ostwand light = #ffd9a0 power = 1.2 [S] model = models/sofa_03/sofa_03_1k.gltf # Poly Haven, CC0 height = 0.93 rotation = 180 offset = 0, 0, -0.07 # an die Südwand [6] door = saal 1 |
light = #ffd9a0 bei einem Modell macht es zu einer Lampe. Ihr Licht kommt aus den Teilen, die im Modell selbst leuchten, bei dieser Lampe aus der Glühbirne hinter dem Glas, und es strahlt nach allen Seiten, nicht nur nach unten wie eine Leuchte unter der Decke. Hat eine Lampe einen Schirm, der nach unten zeigt, wie die Wandlampen im Holzsaal aus Level 0, schreib beam = 75 dazu: Dann fällt ihr Licht nur nach unten, in einen Kegel, der bis 75° von der Senkrechten reicht, und die Decke darüber bekommt kein direktes Licht. beam = up, 60 schickt es nach oben. power und flicker gelten wie bei einer Leuchte. Glas und die leuchtenden Teile halten das Licht nicht auf, aber Arm und Schirm einer Lampe werfen Schatten an die Wand.
offset = x, y, z schiebt ein Modell aus der Mitte seines Felds, in Metern und wie in den anderen 3D-Aktivitäten: x nach Osten (im Grundriss nach rechts), y nach oben, z nach Süden (im Grundriss nach unten), mit einer negativen Zahl in die andere Richtung. Die Lampe im Feld W rückt 42 cm nach Westen an die Wand und hängt 1,4 m hoch. Das Sofa rückt 7 cm nach Süden: Es ist 1,12 m tief, ein Feld nur 1 m, und ragte sonst in die Wand. offset gibt es auch für Blöcke. Welche Seite eines Modells vorn ist, legt fest, wer es gebaut hat; rotation in Schritten von 90 dreht es, bis es stimmt. Die Lampe an der Westwand ist um 90° gedreht, damit ihre Rückseite an der Wand liegt. Mit drei Zahlen, rotation = x, y, z, dreht es sich um alle drei Achsen, dieselben wie bei offset: erst um y, wohin es schaut, dann um x, gekippt, dann um z, zur Seite geneigt.
Dabei kommt es auf die Reihenfolge an. Zuerst dreht das Programm ein Modell, um seine eigene Mitte. Dann stellt es dessen Mitte über die Mitte des Felds und seinen tiefsten Punkt auf den Boden, oder auf den Sockel. Erst danach schiebt offset es weiter, in den Richtungen der Welt, nicht in denen des gedrehten Modells: offset = -0.42, 1.4, 0 heißt immer 42 cm nach Westen und mit der Unterkante 1,4 m über dem Boden, wie auch immer die Lampe gedreht ist.

Sofa und Wandlampe liegen schon in models/, dazu die Wandlampe mit Schirm und der Kerzenleuchter aus dem Holz- und dem Samtsaal und Möbel: ein Schreibtisch aus Metall, Stühle, eine Kommode, ein Regal, ein altes Bettgestell, ein Schaukelstuhl und ein kleiner Tisch. Alle sind von Poly Haven. Dort steht jedes Modell unter CC0: Du darfst es verwenden, wofür du willst, ohne zu fragen. So holst du dir weitere:
.gltf, einer .bin und Bildern im Ordner textures. Sie gehören zusammen in einen eigenen Ordner in models, etwa models/sessel/, so wie sie ankommen.model = models/sessel/DATEINAME.gltf. Wie groß das Modell ist, steht auf seiner Seite bei den Maßen; die Höhe davon gehört in height.Kommt beim Herunterladen eine ZIP-Datei an, zieh sie in VS Code in den Ordner models und pack sie im Terminal in einen eigenen Ordner aus:
cd /workspace/backrooms-starter/models unzip DATEINAME.zip -d sessel
Weitere Modelle unter CC0 findest du bei den 3D-Scans der Smithsonian Institution und bei Sketchfab, die Suche dort schon auf CC0 und herunterladbare Modelle eingestellt; beide als GLB herunterladen. Nimm nur Modelle, deren Lizenz das erlaubt, und schreib in einem Kommentar neben model = dazu, woher sie kommen.
Viele Spiele rechnen das Licht für jedes Bild neu, 60-mal in der Sekunde, weil sich dort Figuren, Türen und Lampen bewegen, und müssen dafür stark vereinfachen. Hier bewegst nur du dich, die Leuchten bleiben, wo sie sind. Darum rechnet das Programm das Licht einmal aus, wenn das Level lädt, und klebt es dann wie eine zweite Tapete auf jede Fläche. Diese Tapete aus Licht heißt Lightmap, und das Ausrechnen nennt man Backen. Es läuft auf der Grafikkarte, in Shadern: kleinen Programmen in GLSL, die für Tausende Punkte zugleich laufen. Schritt für Schritt, im Saal mit seinen Säulen:
Die Punkte. Die Lightmap hat auf jedem Meter Wand, Boden und Decke 16 Punkte in jeder Richtung, alle 6,25 cm einen. Nur für diese Punkte rechnet die Grafikkarte aus, wie hell es dort ist; dazwischen mischt sie beim Zeichnen die vier nächsten. Mit G siehst du die Punkte, mit T ohne Tapete und Teppich deutlicher:

Eine Wand ist 10 m lang und 3 m hoch. Wie viele Punkte hat die Lightmap auf dieser Wand?
Wo ein Modell oder ein Block nah an einer Wand, auf dem Boden oder unter der Decke steht, wirft er Schatten, für die 6,25 cm zu grob sind: Eine Säule unter der Decke wirft dort einen scharfen Keil. Dort bekommt die Fläche ein zweites, feineres Stück Lightmap, das zu seinem Rand hin weich in das grobe übergeht. Es reicht 60 cm über den Umriss hinaus, so weit reichen die weichen Schatten; um ein Modell liegen bis zu viermal so viele Punkte in jeder Richtung, um einen Block dreimal so viele, denn seine Kanten sind gerade. Auch eine Lampe an der Wand bekommt eins, für die Schatten ihres Arms. Weit weg sind die feinen Punkte so klein, dass G sie ausblendet; dort sieht die Fläche glatt aus.
Ein Bild für alle Flächen. Alle Punkte aller Flächen liegen in einem einzigen Bild, der Lightmap. Jede Fläche ist darin ein Rechteck aus ihren Punkten: so viele breit und hoch, wie sie Meter breit und hoch ist, mal 16. Nur Boden und Decke eines Raums teilen sich je ein Rechteck, so wie der Grundriss sie von oben zeigt: Wo zwei ihrer Stücke aneinanderstoßen, liegen dieselben Punkte, und das Licht hat dort keine Naht. Das Programm legt die Rechtecke dicht an dicht in das Bild, die großen zuerst, wie Kisten in einen Kofferraum, und macht das Bild nur so groß wie nötig, mit einer Zweierpotenz als Seite, etwa 1024 × 1024 Punkte. Jede Ecke einer Fläche weiß, wo im Bild ihr Rechteck liegt. Beim Zeichnen holt sich die Grafikkarte für jeden Pixel der Fläche die Helligkeit von der passenden Stelle im Rechteck: Das Rechteck wird auf die Fläche geklebt, wie ein Bild auf eine Wand. Shift+G zeigt die ganze Lightmap, hier die deines Levels (zum Vergrößern anklicken):
?show=atlas&face=bad,wall in der Adresse zeigt nur das Rechteck der größten Wand im Bad, Punkt für Punkt. Ein anderer Raum statt bad, floor oder ceiling statt wall; eine Zahl dahinter nimmt die nächstkleinere Fläche (bad,wall,1 die zweitgrößte), fine ihr feineres Stück. In den feinen Stücken sieht man gut, wie ein Schatten an der Kante, die ihn wirft, scharf beginnt und mit dem Abstand weicher wird, warum, kommt gleich. An der Wand hinter der Treppe im Bad und um eine Kiste auf dem Dachboden, die zwei Leuchten sieht und darum zwei Schatten wirft:
bad,wall,3,fine)
dachboden,floor,1,fine)
Bevor es um die Strahlen geht: Geh zurück ins Zimmer (Shift R) und schau nach oben, zur Decke.
Was passiert mit der Decke des Zimmers, wenn du das Bounce-Licht ausschaltest (B)? Überleg zuerst, dann probier es aus.
Direktes Licht. Für jeden Punkt nimmt das Programm einen Punkt auf jeder Leuchte und schickt einen Strahl dorthin. Steht etwas im Weg, eine Wand, eine Säule oder ein Modell, kommt von dieser Leuchte nichts an. Sonst kommt Licht an, umso weniger, je weiter die Leuchte weg ist (doppelt so weit: ein Viertel) und je schräger es auf die Fläche fällt. Das wiederholt es 64-mal, jedes Mal mit einem anderen Punkt auf der Leuchte, und nimmt den Durchschnitt. Ganz zufällig sind diese Punkte nicht: Das Programm teilt die Leuchte in 8 × 8 Felder, und jeder Punkt der Lightmap kommt in den 64 Durchgängen in jedes Feld genau einmal, darin an eine zufällige Stelle. So verteilen sich seine Strahlen gleichmäßig über die ganze Leuchte, und der Halbschatten wird glatter als mit Zufall allein. Ein Punkt, der eine Leuchte nur halb sieht, ist in etwa der Hälfte der Durchgänge beleuchtet: Er liegt im Halbschatten. Darum werfen große Leuchten weiche Schatten und kleine scharfe. Und der Halbschatten ist dort schmal, wo der Schatten an der Kante beginnt, die ihn wirft, und wird breiter, je weiter er von ihr weg fällt: wie an der Wand hinter der Treppe und um die Kiste. Nur mit direktem Licht sieht der Saal so aus:
Hier geht es weiter, sobald du deine Antwort oben abgegeben hast.

Ohne Bounce-Licht ist die Decke fast schwarz: Keine Leuchte strahlt nach oben.
Wie weich ein Schatten ist, hängt also davon ab, wie groß die Leuchte ist. Mit size = 0.2 und mit size = 2 (und power so, dass jede gleich viel Licht gibt, denn eine kleinere Leuchte gibt auch weniger):
[L] light = #fff3cf power = 18 size = 0.2
size = 0.2: scharfe Schatten
size = 2: weiche SchattenBounce-Licht. In Wirklichkeit ist eine Decke trotzdem hell, weil jede Fläche einen Teil des Lichts zurückwirft, das auf sie fällt, in ihrer eigenen Farbe: der Teppich bräunliches Licht, eine rote Wand rotes. Ist das direkte Licht fertig, schickt das Programm von jedem Punkt Strahlen in zufällige Richtungen und schaut, wie hell die Flächen sind, die sie treffen. Was dabei herauskommt, ist das Licht, das einmal zurückgeworfen wurde, ein Bounce. Damit das schnell geht, sammelt es das zurückgeworfene Licht vorher in Würfeln von 25 cm, und weil zufällige Strahlen ein körniges Ergebnis geben, glättet es das Bounce-Licht am Ende. Das Ganze dreimal: Beim zweiten Bounce werfen die Flächen auch das Licht des ersten zurück und so weiter, darum steht beim Backen »bounce 1 of 3«. Mit einem, zwei und drei Bounces (in level.ini mit bounces = 1 und so weiter):
Kontaktschatten. Wo zwei Flächen aneinanderstoßen, in Ecken, an einer Sockelleiste oder unter einem Block, kommt von vielen Seiten kein Bounce-Licht, weil die andere Fläche im Weg ist. Zwei kurze Strahlen von 80 cm prüfen bei jedem der 64 Durchgänge, wie viel Platz um einen Punkt herum ist: Trifft einer etwas, dunkelt das Bounce-Licht dort ab, umso mehr, je näher es ist, und sanft auslaufend, damit keine harte Linie entsteht. Auf Englisch heißt das Ambient Occlusion. Nur das Bounce-Licht, ohne und mit Kontaktschatten:
Alles zusammen. Direktes Licht, Bounce-Licht und Kontaktschatten, mal der Farbe von Wänden und Boden:

Beim Zeichnen: Tone Mapping und Bloom. Die Lightmap enthält das Licht, wie es wirklich ist: Unter einer Leuchte ist es viel heller als in einer Ecke, und die Leuchte selbst ist noch einmal viel heller. Ein Bildschirm kann das nicht zeigen, er kennt nur Helligkeiten von 0 bis 1. Das Tone Mapping drückt große Werte sanft zusammen, wie eine Kamera: Helles bleibt hell, ohne dass alles darüber gleich weiß wird. Davor kommt Bloom (H): Was viel heller ist als Weiß, die Leuchten vor allem, strahlt weich in seine Umgebung, so wie in einer Kamera oder im Auge, wenn man in eine Lampe schaut. Dafür verkleinert das Programm das Bild mehrmals auf die Hälfte, verwischt die hellsten Stellen und legt sie wieder vergrößert darüber. Das kostet bei jedem Bild ein wenig Zeit, darum fehlt Bloom mit der Rot-Cyan-Brille, in VR und in der Automap; dort hat jede Leuchte einen eigenen, einfachen Schein.
Warum es so echt aussieht. Die Räume sind schlicht: gelbe Tapete, Teppich, ein paar Säulen. Dass sie trotzdem wie ein Foto wirken, liegt fast nur am Licht. In Wirklichkeit fällt Licht nicht nur von der Lampe auf den Boden, es prallt von allen Flächen ab, färbt sich dabei, macht Decken hell und Ecken dunkel, und Schatten haben weiche Ränder. Genau das rechnet das Programm aus, mit rund tausend Strahlen für jeden Punkt der Lightmap. Ein Spiel, das 60 Bilder in der Sekunde zeichnen muss, hat dafür keine Zeit und schummelt; das sieht man. Hier geht es, weil sich nichts bewegt: Keine Lampe wandert, keine Tür geht auf, keine Figur läuft durchs Bild. Das Licht wird einmal gebacken und stimmt dann für immer, und es gibt nichts, das sich anders verhielte als das Licht und den Trick verriete. Die Backrooms sind leer, und genau darum sehen sie so echt aus.
Modelle bekommen ihr Licht nicht aus der Lightmap: Das Programm rechnet es für jede Ecke ihres Netzes aus, mit denselben Leuchten und demselben Bounce-Licht.
Oben links steht für jeden Teil ein Schalter mit seiner Taste; grün heißt an. Ein Klick auf den Schalter oder die Taste schaltet ihn um:
| Taste | Schalter | Was er zeigt |
|---|---|---|
| T | Textures | die Oberflächen mit ihren Flecken und ihrem Glanz; aus: alles hellgrau, nur das Licht |
| L | Direct light | das direkte Licht der Leuchten |
| B | Bounce light | das zurückgeworfene Licht |
| O | Occlusion | die Kontaktschatten |
| F | Flicker | das Flackern |
| E | Edges | die Kanten aller Flächen als Drahtgitter |
| G | Light points | die Punkte der Lightmap |
| H | Bloom | der helle Schein um die Leuchten |
| C | VHS | alles wie von einer alten Videokassette, mit Datum und Uhrzeit (aus; mit vhs = on in level.ini an) |
| X | Aberration | farbige Säume zum Rand hin, rot nach außen, blau nach innen, wie durch eine einfache Linse (aus; mit aberration = on in level.ini an) |
| 3 | Anaglyph | das Bild für eine Rot-Cyan-Brille |
| K | Collision | was beim Laufen im Weg ist (siehe Level 1) |
| M | Automap | die Karte |
| Shift L | Rebake light | das Licht noch einmal von vorn backen |
| Save light | das gebackene Licht als Datei herunterladen (siehe unten) |
size = 0.2 und power = 16 und lade neu. Eine kleinere Leuchte gibt auch weniger Licht, darum die größere Zahl. Sieh dir den Lichtfleck an, den sie durch die Tür in den Gang wirft: Seine Ränder werden scharf. Dann size = 2 mit power = 0.16: Sie werden ganz weich. Mit bounces = 0 in level.ini unter [level] backt das Programm gar kein Bounce-Licht; wie sieht der Gang dann aus? Stell beides danach wieder zurück.
Erkläre in eigenen Worten, warum eine große Leuchte weichere Schatten wirft als eine kleine. Benutze dabei, wie das Programm das direkte Licht ausrechnet.
Backen dauert, darum hebt die Vorschau das fertige Licht im Browser auf. Lädst du neu, ohne etwas zu ändern, steht oben links »Light loaded from this browser«, und es wird hell, ohne dass gebacken wird. Änderst du auch nur ein Zeichen in einem Raum, passt das aufgehobene Licht nicht mehr, und es wird neu gebacken. Ob es passt, sagt ein Fingerabdruck (englisch Hash): eine kurze Zahl, ausgerechnet aus allen Dateien des Levels, den Modellen, dem Teil des Programms, der backt, und dem, was das Programm aus deinen Räumen baut: den Flächen und den Leuchten.
Nach dem Backen bekommen noch die Modelle ihr Licht, oben links steht dann »Light for the models« mit einer Zahl in Prozent. Ist auch das fertig, lädt »Save light« das Licht als Datei level.light herunter. Zieh sie aus deinem Download-Ordner in den Explorer von VS Code, neben level.ini. Dann lädt das Level sein Licht aus dieser Datei, auch in einem anderen Browser, und du kannst deine Backrooms als fertige Webseite weitergeben. Nach jeder Änderung am Level musst du sie neu speichern; eine veraltete Datei meldet die Vorschau oben links.
Wer eine Tür findet, soll sie offen lassen. Für die Nächsten.
Mit Kreide an einen Türrahmen geschriebenSolange dein Workspace läuft, kannst du anderen zeigen, was du gebaut hast. Starte die Vorschau, öffne dein Profil und teile unter »Shared Live Apps« die laufende Web-App; die Vorschau mit »Go Live« läuft auf Port 5500. Alle, die im Workspace angemeldet sind, finden sie dann in ihrem Profil unter »Von anderen geteilt«, deine Gruppe ganz oben. Erreichbar ist sie, solange dein Workspace und die Vorschau laufen.
Speichere vorher das Licht (»Save light«, siehe »Licht aufheben«) und leg level.light neben level.ini: Dann ist es bei allen sofort hell, und niemand muss warten, bis gebacken ist.
Dauerhaft und für alle, auch ohne Anmeldung, wird dein Projekt mit einer eigenen Hackschule-Subdomain, zum Beispiel meinprojekt.hackschule.de. Dorthin kopierst du die fertigen Dateien deines Projekts. Das geht mit allem, was ganz im Browser läuft, ohne ein Programm auf dem Server. Wie du die Subdomain bekommst und die Dateien hochlädst, steht in der Anleitung zum eigenen Webspace.
Willst du dein Level woanders hinlegen, auf einen Webserver, der nur Dateien ausliefert: ./export.sh . ../mein-level im Terminal, im Ordner der Vorlage, baut einen Ordner mein-level neben ihr, nur mit dem, was dein Level braucht, dem Licht und den Modellen, die es nennt. Für eine VR-Brille muss die Adresse mit https:// anfangen.
Ein Gebäude, nachts. In jedem Raum brennt Licht, und in jedem ist es ein anderes. Niemand hat Dienst. Trotzdem steht im Büro ein Laptop offen.
Feldhandbuch, eingelegtes BlattJetzt kennst du alles, was in einer Raumdatei stehen kann. Die Nachtschicht ist ein ganzes Level, gebaut aus genau diesen Einträgen. Du kannst sie sofort durchlaufen, ihr Licht ist schon gebacken:
Sie öffnet sich in einem neuen Tab, schon fertig gebacken. Das geht auch auf dem Handy, dem Tablet und mit einer VR-Brille: Öffne dieselbe Adresse im Browser der Brille und tippe auf »ENTER VR«.
Wie sie gebaut ist, kannst du nachlesen: Ihre Räume liegen auf GitHub, eine Datei pro Raum, im Ordner rooms. Lies sie Zeile für Zeile und nimm dir, was du brauchen kannst.
Du kannst sie auch in deine Vorlage holen und dort öffnen. Klone sie im Terminal in den Ordner der Vorlage, als Ordner nachtschicht:
git clone https://github.com/specht/backrooms-nachtschicht nachtschicht
Dann häng an die Adresse der Vorschau ?level=nachtschicht an. Beim ersten Mal backt dein Browser das Licht selbst. Bei siebzehn Räumen und 150 Modellen dauert das an einem Rechner mit einer Grafikkarte von vor ein paar Jahren etwa eine Viertelstunde. Lass so lange den Tab und die Vorschau offen. Danach hebt dein Browser das Licht auf, und beim nächsten Mal ist es sofort hell, solange du an der Nachtschicht nichts änderst.
Wenn du einen Ausgang findest, schreib ihn auf. Wenn du keinen findest, bau einen Raum, in dem es sich zu warten lohnt.
Feldhandbuch, Rückseite