fretina 🔼

reinhard@finalmedia.de cafeface
Wed Jul 29 11:57:04 PM CEST 2026
Public Domain

fretina liest steuerungsbefehle (kameraposition und worldloader) von stdin und gibt rgba frames auf stdout aus.


WORK IN PROGRESS

Sourcecode

  • fretina.c v0.27 - Filesystem Retina Gaussian Splat RGBA Renderer mit Fixpoint Arithmetik
  • gen_cyber.c erzeugt auf stdout einen tarball mit einer prozedural generierten cyber welt.
  • gen_helix.c erzeugt auf stdout einen tarball mit einer prozedural generierten helix welt.
  • gen_world.c erzeugt auf stdout einen tarball mit einer prozedural generierten welt.
  • Makefile

    Binaries

  • fretina 22kb 23e4eed0fec17bedda670a296a1eade0 fretina.x86-64: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), static-pie linked, stripped
  • gen_helix

    Beschreibung

    fretina ist ein filesystembasierter highspeed Software 3D-Renderer fĂŒr Hyper Gaussian Splats in (Fixpoint Arithmetik) inkl. Spherical Harmonics.. (BlickwinkelabhĂ€ngig Änderungen bei der Farbgebung von Pixeln fĂŒr hohen Realismus bei Spiegelungen, Transparenzen, irisierenden Farben).

    Ziel der Implementierung ist ein leicht portierbarer, minimalistischer, hoch optimierter, speichereffizienter und echtzeitfÀhiger 3D-Grafik-Renderer ohne externe AbhÀngigkeiten.

    fretina wurde fĂŒr eingebettete Systeme oder minimalistische Umgebungen im puristischen djb-Programmierstil entwickelt.

    Das Tool liest kontinuierlich Kamerabefehle ĂŒber die Standardingabe (stdin) ein und streamed eine in sich selbst animierte Gaussian Splat Welt aus einer lokalen wohldefinierten Verzeichnisstruktur aus Ordnern, Dateien und Symlinks. Es rendert diese abhĂ€ngig von der ĂŒbergebenen Kameraposition (x y z pan tilt brennweite) und gibt die fertig gerenderten Videobilder (als RGBA-Frames) ĂŒber die Standardausgabe (stdout) aus.

    Die Gesamte Welt ist dabei durchwanderbar und Daten werden dabei erst on demand geladen. So muss nie die gesamte Welt in den Arbeitsspeicher geladen werden. Pro Block sind dabei >24h Gaussian Splat Animation möglich, die jeweils beginnt, wenn der Block betreten wird. Da die Weltblöcke als viele tausende kleine Dateien fester GrĂ¶ĂŸer (4MB) existieren sind sie parallel von anderen Tools zur Laufzeit verĂ€nderbar. Die Weltblöcke (Sektoren) beinhalten dabei jeweils maximal 262.144 Splats. Die DateigrĂ¶ĂŸe wurde fĂŒr ein optimales Streaming von ext4 Dateisystemen gewĂ€hlt. Durch Symlinks sind 0-Byte Belegungen möglich, wenn sich einzelne Blöcke nicht Ă€ndern.

    Toolchain

    Neben den bereitgestellten Proof-Of-Concept Weltgeneratoren empfiehlt sich zur raschen Sichtung im Terminal die Verwendung von

    rgba2fdraw s 33333 | fdrawterm
    aus dem fdraw Paket, um z.B. auch die Ausgabe via ssh auf einem Terminal auszugeben. Alternativ kann das bekannte ffmpeg verwendet werden, um die rgba Ausgabe live darzustellen oder in Videos zu rendern.

    Steuer-Befehle

    P x y z pan tilt zoom brennweite	Kamera positionieren
    W d					wechselt in das angegebene Welten Verzeichnis d, bestehend aus 4 Dezimalstellen
    

    Beispiel fĂŒr einen Wechsel in das Welten-Verzeichnis W0001 ist der Befehl "W 0001" und das Programm verwendet dann adhoc die Struktur W0001/0000/0000/0000/000000.p - W0001/9999/9999/9999/99999.p

    Assets

  • epicfly.txt
  • kamera.txt
  • rundflug.txt
  • play.sh
  • render.sh
  • controller.sh
  • interactive.sh

    Wie wird der Quellcode gebaut und getestet?

    make
    make myhelix
    make activate
    make fly
    

    Was ist das hier?

    1. Ein- und Ausgabe (I/O) & Steuerung

  • Kamera-Eingabe (stdin): Das Programm wartet auf menschenlesbare Steuerbefehle im ASCII Format, die mit dem Buchstaben P beginnen (z. B. P x y z pan tilt zoom b_shift \n). Es parst die Parameter (Kameraposition, Blickwinkel, Zoom und Bit-Verschiebung) direkt zeichenweise aus einem internen Puffer (in_buf).
  • Dynamische Auflösung: Die Standardauflösung betrĂ€gt 640×480 Pixel. Sie kann vor dem Start ĂŒber die Umgebungsvariablen SCREEN_WIDTH und SCREEN_HEIGHT auf bis zu Ultra-HD (3840×2160) angehoben werden.

    2. Das Splat-Filesystem (RĂ€umliches Daten-Streaming)

    Um nicht die gesamte 3D-Welt im Arbeitsspeicher halten zu mĂŒssen, nutzt das Programm ein cleveres, dateibasiertes Streaming-Verfahren:

  • Sektorierung: Die Kameraposition wird in Sektoren der GrĂ¶ĂŸe 500×500×500 Einheiten unterteilt (SEC_SZ).
  • Pfadgenerierung (gen_path): Aus den aktuellen Sektorkoordinaten und der globalen Zeit (gt) wird ein exakter Dateipfad generiert (z. B. world/5000/5000/5000/00000.p). Um printf zu vermeiden, geschieht dies ĂŒber eine blitzschnelle Look-Up-Table (LUT).
  • Cache & Key-Hashing: Über einen Hash-Key (key) wird geprĂŒft, ob sich die Kamera noch im selben Sektor und Zeitfenster befindet. Nur bei einem Wechsel werden die neuen Geometriedaten (.p-Datei) und Metadaten (.m-Datei) geladen.
  • Kernel-Optimierung: Mittels posix_fadvise wird dem Betriebssystem signalisiert, dass die Dateien sequentiell und sofort benötigt werden, was die Festplatten-I/O drastisch beschleunigt.

    3. Effiziente Festkomma-Mathematik (Kein Float)

    Der Code verzichtet komplett auf Fließkommazahlen (float/double), was ihn auf Systemen ohne mathematischen Koprozessor oder im Kernel-Space extrem schnell macht:

  • Trigonometrie per LUT: Sinus- und Kosinuswerte werden aus einem vorab berechneten Array (INT_SIN) mit 64 Schritten ausgelesen.
  • Eigener atan2: Eine schnelle, ganzzahlige AnnĂ€herung zur Berechnung von Winkeln (Arkustangens 2).

    4. Animation & Rendering-Vorbereitung (Auszug am Ende)

  • Lebenszyklus von Splats: Jeder Bildpunkt besitzt einen Startzeitpunkt (t0) und eine Lebensdauer (dt). Das Programm filtert Splats heraus, die im aktuellen Frame (Zeitpunkt relative_zeit) nicht sichtbar sind.
  • Dynamische Partikel: FĂŒr langlebige Splats (dt >= 100) berechnet der Code am Ende relative AbstĂ€nde, um Animationen (wie Rotationen oder Bewegungen innerhalb des Sektors) zu simulieren.
  • Z-Buffer & Compositing: Vor dem Zeichnen werden die FarbkanĂ€le und der Tiefenpuffer (ret_z) zurĂŒckgesetzt, um eine korrekte Verdeckung von Objekten im 3D-Raum (Verdeckung weiter entfernter Punkte durch nĂ€here) zu gewĂ€hrleisten.

    Funktionen im Detail

    1. Konfiguration und Puffer-Definitionen

  • Maximale Dimensionen: Der Speicher fĂŒr die Bildpuffer ist statisch auf bis zu Ultra-HD (3840 × 2160 Pixel) ausgelegt.
  • Separater Farb- und Tiefenspeicher: FĂŒr eine effiziente Bildberechnung existieren getrennte FlĂ€chen fĂŒr Transparenz (ret_o), Rot (ret_r), GrĂŒn (ret_g), Blau (ret_b) und Tiefe (ret_z).
  • Splat-Datenstruktur: Ein einzelner Splat belegt exakt 16 Bytes im Speicher (SPL_SZ). Er speichert relative 3D-Koordinaten (x, y, z), Animations-Zeitfenster (t0, dt), OpazitĂ€t (op) und Farbinformationen (r, g, b). Der p_pool fasst ĂŒber diese Struktur exakt 262.144 Splats gleichzeitig im Speicher.

    2. Ganzzahl-Mathematik (Keine Fließkommazahlen)

  • get_sin / get_cos: Nutzt eine Look-Up-Table (INT_SIN) mit einer Auflösung von 64 Schritten fĂŒr einen vollstĂ€ndigen Kreis (360° entsprechen dem Wert 64). Ein logisches Und (& 63) verhindert PufferĂŒberlĂ€ufe und realisiert die PeriodizitĂ€t. Die Werte sind mit dem Faktor 251 skaliert (Wertbereich von -251 bis +251).
  • get_atan2: Berechnet den mathematischen Winkel zwischen zwei Punkten rein ĂŒber Festkomma-Arithmetik und Bit-Verschiebungen, angepasst an das 64-Schritte-Rastersystem.

    3. Das Dateipfad-System (gen_path)

  • Sektor-Mapping: Konvertiert 3D-Welt-Koordinaten und Zeitstempel in standardisierte Pfade (Format: world/ZZZZ/YYYY/XXXX/TTTTT.sfx).
  • Optimierung: Um die Formatierung ohne die langsame Standardfunktion sprintf umzusetzen, zerlegt die Funktion die Zahlen mathematisch in Hunderter- und Einer-Blöcke und schreibt die ASCII-Zeichen direkt paarweise aus der LUT-Matrix in den String-Puffer.

    4. Befehls-Parser & Stream-Initialisierung

  • Umgebungsvariablen: Zu Beginn liest das Programm SCREEN_WIDTH und SCREEN_HEIGHT aus. Fehlen diese, bleibt es bei 640×480. Der Framebuffer (fb) wird exakt auf diese Pixelanzahl skaliert.
  • Zeichenweiser Parser: Über eine Endlosschleife wird stdin blockweise in in_buf gelesen. Sobald ein P erkannt wird, schaltet der Parser auf ein internes Zustands-Flag (in_cmd = 1) um. Er liest zeichenweise Ziffern und Minuszeichen ein, baut daraus Ganzzahlen und fĂŒllt das Array p mit den 7 Kameraparametern.

    5. Sektoren-Streaming & Caching (I/O-Verwaltung)

    Sobald ein Befehl vollstÀndig ist (entweder durch ein Newline \n oder nach dem 7. Parameter), erhöht das Programm den globalen ZeitzÀhler (gt++).

  • Positions-Hashing: Die Kameraposition wird in Sektoren (SEC_SZ = 500) geteilt. Aus den Sektor-IDs und der aktuellen Zeitepoche (req_t) wird ein eindeutiger Hash-SchlĂŒssel (key) erzeugt.
  • Bedarfsgesteuertes Laden: Nur wenn sich der key gegenĂŒber dem Vorframe geĂ€ndert hat (key != active_t), generiert das Programm neue Pfade fĂŒr Geometrie (.p) und Metadaten (.m) und lĂ€dt sie via Linux-Systemaufruf read() direkt in p_pool und m_pool.

    6. Splat-Selektion & Animations-Engine

    Bevor gezeichnet wird, setzt das Programm alle Bildpuffer zurĂŒck: Die Farb- und Alpha-KanĂ€le werden auf 0 gesetzt, der Tiefenpuffer (ret_z) auf den maximalen Integer-Wert 32767.

    Danach lĂ€uft eine Schleife ĂŒber alle 262.144 möglichen Splats (TOT_SPL):

    7. Sichtbarkeits- & Zeitfenster: Splats mit einer OpazitĂ€t von 0 werden ĂŒbersprungen. Besitzt ein Splat eine Lebensdauer dt < 100, wird geprĂŒft, ob die aktuelle Sektor-Zeit (relative_zeit) in sein Sichtbarkeitsfenster (t0 bis t0 + dt) fĂ€llt. Wenn nicht, wird er verworfen.

    Ganzzahl-3D-Animation (Wellen-Effekt): Hat ein Splat eine hohe Lebensdauer (dt >= 100), wird er pro Frame animiert. Das Programm berechnet mittels get_atan2 den Polarwinkel der XZ-Ebene und moduliert den Radius ĂŒber eine Multiplikation von Sinus- und Kosinuswellen (s_wave * c_wave). Dies erzeugt ohne jegliche Fließkommazahlen rotierende oder pulsierende Wellenbewegungen der Punkte im Raum.

    8. 3D-zu-2D Projektion (Die Kamera)

  • Kamera-Transformation: Die relativen Koordinaten zum Kamerasystem werden ermittelt (rx, ry, rz). Liegt ein Punkt hinter oder zu nah an der Kamera (rz <= 10), wird er abgeschnitten (Clipping).
  • Blickrichtung (Pan & Tilt): pan (Drehung) und tilt (Neigung) werden ĂŒber Bit-Shifts (>> 9) linear mit der Tiefe rz verrechnet. Das simuliert eine schnelle, extrem schlanke Kameradrehung.
  • Perspektivische Projektion: Unter Einbeziehung des Zooms wird die Brennweite fl ermittelt. Die 3D-Bildpunkte werden ĂŒber (rx * fl) / rz perspektivisch korrekt auf die 2D-Bildschirmkoordinaten (sx, sy) projiziert, wobei die Y-Achse fĂŒr den Screen gespiegelt wird.

    9. Elliptische Rasterisierung (Der Gaussian-Splat-Kern)

    Ein Gaussian Splat ist kein eckiges Pixel, sondern ein weicher, meist elliptischer Punkt. Das Programm berechnet die Radien (emaj fĂŒr die Hauptachse, emin fĂŒr die Nebenachse) sowie eine Scherung (sch) basierend auf der Entfernung rz.

  • Bounding Box: Um Rechenzeit zu sparen, wird um die berechnete Ellipse ein quadratisches Gehege (x0, y0 bis x1, y1) gelegt und mit den BildschirmrĂ€ndern verschnitten.
  • Dynamische Shading-Metadaten: Über die Zusatzdatei (m_pool) wird ein Helligkeitswert (sh) ausgelesen, der die RGB-Grundfarben des Splats basierend auf der Sektorentiefe aufhellt oder abdunkelt.
  • Mathematische Ellipsen-PrĂŒfung: In den verschachtelten Pixel-Schleifen (y und x) wird fĂŒr jeden Pixel im Quadrat ĂŒber eine quadratische Form (ed) geprĂŒft, ob er innerhalb der Gauß-Ellipse liegt (cur_d > 1024 bricht ab).

    10. Alpha-Blending & Tiefenpuffer (Z-Buffer)

    Befindet sich der Pixel innerhalb der Gauß-Kurve, greifen die finalen Grafik-Regeln:

  • Z-Test: Wenn die Tiefe des aktuellen Splats (rz) weiter hinten liegt als ein bereits gezeichneter Punkt an diesem Pixel (ret_z[idx]), wird er verworfen (Verdeckung).
  • Transparenz-Akkumulation: Das Programm berechnet die OpazitĂ€t des Pixels (bo), welche zum Rand der Ellipse hin abfĂ€llt. Über klassisches Front-to-Back Alpha-Blending (ba = (bo * (255 - ao)) >> 8) wird die Farbe des Splats auf die bereits existierenden Pixelfarben addiert.
  • Z-Buffer Write: Nur wenn der Punkt an dieser Stelle sehr deckend ist (bo >= 230), schreibt er seine Tiefe in den Z-Buffer, um dahinterliegende Punkte in Folgeschritten zu blockieren.

    11. Ausgabe (Der Videosignal-Stream)

    Nachdem alle 262.144 Splats verarbeitet wurden, kopiert eine ultraschnelle Schleife die separaten FarbkanÀle (ret_r, ret_g, ret_b, ret_o) sequentiell in den finalen, linearen Ausgabe-Puffer fb.

    Mittels eines ununterbrochenen Systemaufrufs write(1, fb, fb_sz) wird dieser Rohdaten-Frame (RGBA) direkt auf die Standardausgabe (stdout) geschoben, bereit fĂŒr die Weiterverarbeitung.

    Wie groß können die Welten sein?

    Die maximale GrĂ¶ĂŸe der darstellbaren Welt wird durch zwei Faktoren limitiert: das Sektor-Koordinatensystem in der Funktion gen_path und die Auflösung der Festkomma-Mathematik. Die theoretischen und praktischen Grenzen der WeltgrĂ¶ĂŸe teilen sich wie folgt auf:

    Der limitierende Faktor in gen_path() fĂŒr die GesamtgrĂ¶ĂŸe der Welt ist die Art und Weise, wie die Dateipfade fĂŒr die Sektoren generiert werden. In der Funktion gen_path limitiert der Code die Sektorkoordinaten (ax, ay, az) hart auf einen Wertbereich von 0 bis 9999: Da ein Sektor eine SeitenlĂ€nge von 500 Einheiten besitzt (SEC_SZ = 500), ergibt sich daraus folgende Dimension:

  • Sektoren pro Achse: 10.000 Sektoren (von 0000 bis 9999).
  • Verschiebung (Offset): Durch den Welt-Offset von 5.000 Einheiten (W_OFF) reicht das Koordinatensystem der Kamera von -5.000 bis +4.999 Sektoren.

    Das ergibt einen maximalen 3D-Weltraum von 5000 × 5000 × 5000 Einheiten (bzw. 10.000³ = 1 Billion Sektordateien auf der Festplatte).

    Die Festkomma-Arithmetik im Code nutzt int32_t fĂŒr die Transformationen.

  • Wenn die Kamera an den Ă€ußersten Rand der Welt wandert, arbeitet die Projektion mit relativen AbstĂ€nden zum Splat (rx = px - cam_x).
  • Da die relative Distanz zur Kamera innerhalb des aktiven Sektors selten grĂ¶ĂŸer als ein paar Hundert Einheiten ist, laufen die Register bei der Multiplikation mit der Brennweite (rx * fl) nicht ĂŒber. Die mathematische PrĂ€zision bleibt also ĂŒber den gesamten Bereich von 5 Millionen Einheiten konstant exakt.

    Wenn man eine Einheit als 1 Zentimeter definiert (was fĂŒr detaillierte Gaussian Splats ĂŒblich ist), kann dieses Programm eine nahtlos gestreamte 4D-Welt von exakt 50 × 50 × 50 Kilometern darstellen.

    Wie groß wĂ€re ein Vollausbau von W0001/0000/0000/0000/00000 bis W0001/9999/9999/9999/99999 in Bezug auf den Speicherplatz?

    Wir belegen pro .p Datei exakt 4 MB Daten. Ein theoretischer Vollausbau dieses Dateisystems von 0000/0000/0000/00000 bis 9999/9999/9999/99999 wĂŒrde unvorstellbare 445,64 Zettabytes (ZB) bzw. rund 386.535 Exabytes (EB) an Speicherplatz belegen.

    Diese astronomische Datenmenge setzt sich aus der Kombination von gigantischem 3D-Raum und der 5-stelligen Zeitschleife zusammen:

  • RĂ€umliche Sektoren: 1 Billion (1.000.000.000.000) Sektor-Ordner.
  • Zeitliche Schritte (00000 bis 99999): 100.000 Dateien pro Sektor.
  • Gesamtanzahl der Dateien: 100 Billiarden (100.000.000.000.000.000) Dateipaare.
  • DateigrĂ¶ĂŸen pro Schritt: Eine .p-Datei (P_SZ) belegt exakt 4.194.304 Bytes (4 MiB). Dazu kommt im Programm noch die .m-Metadatendatei (M_SZ) mit exakt 262.144 Bytes (256 KiB). Zusammen sind das 4,25 MiB pro Zeitstempel.

    Multipliziert man alle Faktoren, landet man bei exakt 445.644.800.000.000.000.000.000 Bytes. Das entspricht:

        ~ 395.812.094 Petabytes (PB)
        ~ 386.535 Exabytes (EB)
    

    Da das Programm ein "Sparse-Filesystem" nutzt (es öffnet Dateien nur bei Bedarf und ĂŒberspringt fehlende via fd >= 0), mĂŒssen auf der Festplatte nur die Sektoren tatsĂ€chlich existieren, in denen sich Geometrie befindet. Leere Bereiche im Universum belegen 0 Bytes.

    Und welcher Auflösung entspricht das, wenn man reale Szenendaten der echten Welt ablegt, z.B. die LIDAR gescanned oder als Gaussian Splat Video gerechnet und zusammengesetzt?

    Um die Auflösung bei realen Szenendaten (LiDAR-Scans oder 4D-Gaussian-Splat-Videos) zu bestimmen, mĂŒssen wir die rĂ€umliche Punktdichte (Auflösung im Raum) und die zeitliche Bildwiederholrate (Auflösung in der Zeit) betrachten.

    Bei einem Vollausbau bietet dieses System eine Sub-Millimeter-PrĂ€zision im Raum und eine extrem flĂŒssige Kino-Zeitauflösung.

    1. RÀumliche Auflösung (Punktdichte)

    Jeder Sektor besitzt eine KantenlĂ€nge von 500 Einheiten und lĂ€dt eine .p-Datei mit exakt 262.144 Splats/Punkten (TOT_SPL). Wenn wir 1 Einheit als 1 Zentimeter definieren (womit die Gesamtwelt 50 × 50 × 50 km groß ist), ergibt sich fĂŒr einen einzelnen Sektor (5 × 5 × 5 Meter):

  • Volumen pro Sektor: 125 mÂł
  • Punktdichte: ≈ 2.097 Punkte pro Kubikmeter
  • Mittlerer Punktabstand: ≈ 7,8 cm zwischen den Splats.

    Skalierung auf Sub-Millimeter-Niveau: Gaussian Splats nutzen im Gegensatz zu harten LiDAR-Punkten weiche Ellipsen mit Transparenz. Setzt man 1 Einheit = 1 Millimeter (Gesamtwelt 5 × 5 × 5 km), schrumpft der Sektor auf ein handliches Volumen von 50 × 50 × 50 cm (0,125 m³).

  • Mittlerer Punktabstand: ≈ 7,8 mm.

    Da jeder Splat eine Ausdehnung hat, entspricht dies einer fotorealistischen, lĂŒckenlosen OberflĂ€chenauflösung im Millimeterbereich, ideal fĂŒr die Archivierung von hochprĂ€zisen Drohnenscans oder volumetrischen Video-Aufnahmen von Menschen.

    2. Zeitliche Auflösung (Framerate & Dauer)

    Die zeitliche Auflösung wird ĂŒber das Makro TPF 100 (Ticks Per Frame/File) und die 5-stellige Dateinummerierung definiert:

  • Sektor-Lebensdauer: 100.000 Dateien pro Sektor. Da alle 100 Ticks (TPF) eine neue Datei geladen wird, deckt ein Vollausbau exakt ab.
  • Framerate: Der Renderer erhöht den ZeitzĂ€hler bei jedem gĂŒltigen Kamerabefehl (gt++). Bei einer ĂŒblichen Frequenz von 60 Hz (60 Bildern pro Sekunde) entspricht eine Datei mit 100 Ticks genau 1,66 Sekunden Echtzeit.
  • Gesamtdauer: Die 100.000 Dateien bieten Platz fĂŒr 166.666 Sekunden, was exakt 46,3 Stunden ununterbrochenem 4D-Videostream pro Sektor entspricht.

    Realer Vergleichmaßstab

    In der Praxis entsprechen 262.144 Splats pro 50 cm-WĂŒrfel der Detailstufe von modernen 4D-Gaussian-Splat-Verfahren (wie Deformable 3D Gaussians). Die Datenmenge pro Sekunde ist mit rund 2,5 MiB/s pro aktivem Sektor sogar extrem effizient kompiliert – sie liegt auf dem Niveau eines stark komprimierten 4K-Netflix-Videostreams, liefert dem Nutzer aber eine voll begehbare, volumetrische 3D-Umgebung.

    Wie hoch wÀre die Streaming-Datenrate (in MB/s) bei einer Kamerageschwindigkeit von z.B. 50 km/h durch die Sektoren?

    Bei einer Kamerageschwindigkeit von 50 km/h betrĂ€gt die reine rĂ€umliche Streaming-Datenrate ca. 11,81 MiB/s. Wenn das Video gleichzeitig in Echtzeit (bei 60 Hz) weiterspielt, steigt die kombinierte Gesamtrate im Worst Case auf ca. 14,36 MiB/s. Die Berechnung basiert auf der logischen Annahme, dass 1 Einheit = 1 Zentimeter entspricht (SektorgrĂ¶ĂŸe = 5 Meter):

    1. Reine rÀumliche Datenrate (Bewegung durch die Welt)

  • Geschwindigkeit: 50 km/h entsprechen 13,89 Metern pro Sekunde.
  • Sektorwechsel: Da ein Sektor 5 Meter lang ist, durchquert die Kamera 2,78 Sektoren pro Sekunde.
  • Daten pro Sektor: Ein Dateipaar (.p + .m) ist exakt 4.456.448 Bytes (4,25 MiB) groß.
  • Ergebnis: 2,78 × 4,25 MiB = 11,81 MiB/s. 2. Zeitliche Datenrate (Fortlaufen der Animation)

    Selbst wenn die Kamera stillsteht, lÀdt das System im Zeitverlauf (4D-Video) Daten nach:

  • Intervall: Alle 100 Ticks (TPF) wird eine neue Datei geladen. Bei einer Steuerungsfrequenz von 60 Hz entspricht das einem Wechsel alle 1,67 Sekunden.
  • Ergebnis: 4,25 MiB / 1,67 s = 2,55 MiB/s.

    Technische Einordnung

    Die maximale Gesamtlast von ~14,36 MiB/s (ca. 115 Mbit/s) ist fĂŒr moderne Speichermedien extrem leicht zu bewĂ€ltigen. Selbst eine herkömmliche SATA-SSD (ca. 500 MB/s) oder eine langsame SD-Karte in einem Embedded System langweilt sich bei dieser Datenrate. Das Betriebssystem puffert die Daten dank des im Code genutzten POSIX_FADV_WILLNEED zudem perfekt im RAM vor.

    Welche ZeitrÀume kann ich maximal darstellen?

    Die maximale darstellbare Zeitdauer im System hĂ€ngt davon ab, mit welcher Frequenz (Bilder pro Sekunde) die Kamera-Steuerbefehle an den Renderer gesendet werden. Da der Code die Zeitepochen ĂŒber eine 5-stellige Zeichenkette im Pfad abbildet (von 00000 bis 99999), stehen exakt 100.000 diskrete Zeitschritte (Dateien) pro Sektor zur VerfĂŒgung. Hier sind die maximalen ZeitrĂ€ume fĂŒr die typischen Bildwiederholraten:

    1. Bei flĂŒssigen 60 Hz (Standard-Echtzeit)

    Wenn ein in der Pipe auf stdin exakt 60 Befehle pro Sekunde auflaufen:

  • Jede der 100.000 Dateien deckt exakt 100 Ticks (TPF) ab, also 1,67 Sekunden.
  • Maximaler Zeitraum: 100.000 × 1,67 Sekunden = 166.666 Sekunden.
  • Das entspricht exakt 46 Stunden, 17 Minuten und 46 Sekunden ununterbrochenem 4D-Videostream.

    2. Bei Kino-Framerate (24 fps)

    Wenn der Datenstrom auf die klassische Film-Framerate reduziert wird:
  • Jede Datei deckt 4,17 Sekunden ab.
  • Maximaler Zeitraum: 416.666 Sekunden.
  • Das entspricht exakt 115 Stunden und 44 Minuten (knapp 5 Tage Daueranimation).

    3. Bei Zeitraffer / Überwachungskamera (1 Hz)

    Wenn das System als Langzeit-Archiv genutzt wird (z. B. ein Bild pro Sekunde fĂŒr LiDAR-VerĂ€nderungen im GelĂ€nde):

  • Jede Datei deckt 100 Sekunden ab.
  • Maximaler Zeitraum: Das entspricht exakt 115,7 Tagen kontinuierlicher Zeitraffer-Aufzeichnung.

    Die mathematische Systemgrenze im Speicher

    Im RAM wird der ZeitzÀhler als vorzeichenloser 16-Bit-Integer deklariert: uint16_t gt = 0;.

    Ein uint16_t lĂ€uft bei 65.535 ĂŒber und springt zurĂŒck auf 0. Das bedeutet, nach exakt 655 Dateien (65.535 / 100) fĂ€ngt die Animation im Speicher wieder von vorne an (Loop-Effekt), obwohl auf der Festplatte Platz fĂŒr 100.000 Dateien wĂ€re.

    Ich kann also mit W Befehle manuell oder procedural in ein neues world verzeichnis springen und hÀtte erneut diese Zeit?

    Ja, exakt so funktioniert das System. Sobald du die rĂ€umliche Grenze eines Sektors ĂŒberschreitest, wechselt das Programm in ein komplett neues Verzeichnis auf der Festplatte (z. B. von W0001/5000/5000/5000/ nach W0001/5000/5000/5001/). In diesem neuen Sektor-Verzeichnis beginnt die Zeitrechnung fĂŒr die Dateien wieder komplett bei 00000.p, da der Pfad fĂŒr jeden Sektor individuell generiert wird. Hier sind die technischen Konsequenzen dieser Architektur:

    Da jeder der 1 Billion Sektoren (10000^3) seine eigenen 100.000 Zeitdateien besitzt, ist die theoretische Gesamtlaufzeit der gesamten Welt gigantisch. Bewegt sich die Kamera kontinuierlich von Sektor zu Sektor vorwĂ€rts, könntest du das System ĂŒber Jahrhunderte laufen lassen, ohne jemals an das Ende der Zeitstempel zu stoßen.

    Zwei Szenarien, wie man das nutzen kann:

  • Szenario A: Lokale Zeitschleifen (Looping): Jeder Sektor beinhaltet eine in sich geschlossene Animation (z. B. ein rotierendes Objekt, wehendes Gras oder eine lokale Maschinensimulation). Wenn die Kamera den Sektor betritt, lĂ€uft das dortige 46-Stunden-Video ab.
  • Szenario B: Globale Synchronisation: Wenn du eine zusammenhĂ€ngende, riesige Welt aufnimmst (z. B. eine ganze Stadt im Zeitverlauf), sorgt das System dafĂŒr, dass beim Sektorwechsel immer das zur globalen Zeit gt passende File geladen wird. VerlĂ€sst du Sektor A bei Minute 10, lĂ€dt Sektor B direkt die Datei, die der Minute 10 entspricht.

    Das World-Verzeichnis darf sich mittels anderer Programme zur Laufzeit Àndern, durch mounts, overlays, symlinks?

    Exakt. Das ist der große Vorteil des minimalistischen Datei-basierten Designs. Da der Renderer die 3D-Welt ausschließlich ĂŒber das Dateisystem konsumiert und keine interne Datenbank fĂŒhrt, merkt er gar nicht, was unter der Haube auf Betriebssystemebene passiert.

    Durch Standard-Linux-Mechanismen lÀsst sich das Basisverzeichnis W0000 nahtlos und unendlich im laufenden Betrieb austauschen, erweitern oder manipulieren. Da die Streaming-Datenrate bei 50 km/h mit rund 12 bis 14 MiB/s sehr moderat ist, lÀsst sich dieses System hervorragend mit Cloud-Speichern oder Netzwerk-Dateisystemen (wie rclone mount, NFS oder Ceph) koppeln.

    Das Betriebssystem lĂ€dt ĂŒber den Mount-Point immer nur genau die 4-MB-Sektoren aus dem Internet oder dem Netzwerk nach, die die Kamera in diesem Moment anfordert. Dank posix_fadvise weiß der Linux-Kernel zudem vorab, welche Daten als NĂ€chstes blockweise geladen werden mĂŒssen.

    Dazu muss man den Steuerbefehl W fĂŒr World nutzen, um zwischen Welten zu springen. "W 0023" wĂŒrde das basis verzeichnis w0023/ nutzen.

    Nutzung-Beispiele

    export SCREEN_WIDTH=320
    export SCREEN_HEIGHT=240
    fretina < epicfly.txt | gzip -9 > output.rgba.gz
    
    export SCREEN_WIDTH=120
    export SCREEN_HEIGHT=150
    fretina < epicfly.txt | rgba2fdraw | fdrawterm 
    
    export SCREEN_WIDTH=120
    export SCREEN_HEIGHT=150
    cat kamera.txt | fretina | rgba2fdraw s 33333 | fdrawterm > demo.anim.gz
    zcat demo.anim.gz
    
    export SCREEN_WIDTH=1920
    export SCREEN_HEIGHT=1080
    cat rundflug.txt | fretina | ffmpeg -y -f rawvideo -pix_fmt rgba -s ${SCREEN_WIDTH}x${SCREEN_HEIGHT} -r 60 -i - -c:v libx264 -an animation.mp4
    
    export SCREEN_WIDTH=320
    export SCREEN_HEIGHT=240
    cat rundflug.txt | fretina | ffplay -f rawvideo -pixel_format rgba -video_size ${SCREEN_WIDTH}x${SCREEN_HEIGHT} -i -
    
    mkdir config
    echo 150 > config/SCREEN_WIDTH
    echo 80 > config/SCREEN_HEIGHT
    cat rundflug.txt | envdir config fretina | envdir config rgba2fdraw | envdir config fdrawterm
    
    yes P 0 0 0 0 0 100 0 | envdir termres ./fretina | envdir termres rgba2fdraw | envdir termres fdrawterm
    

    World Generatoren

    gen_ programme erzeugen auf stdout einen tarball, den du entpacken kannst, um das world verzeichnis zu erstellen. prozeduraler democontent, teils animiert. man entpackt diese dann einfach einmalig

    ./gen_world | tar xvv 2>/dev/null
    ./gen_cyber | tar xvv 2>/dev/null
    ./gen_helix | tar xvv 2>/dev/null
    
    ln -s world W0000
    

    Optimierung

    Die Optimierung liegt in der mathematischen Harmonie zwischen den Hardware-Eigenschaften einer SSD (ext4-Dateisystem) und den Cache-Zeilen der CPU. Es gibt drei entscheidende GrĂŒnde, warum das Trennen in .p (Geometrie) und .m (Material) weitaus performanter ist, als die SH-Daten in eine einzige Datei mit weniger Splats zu quetschen:

    1. Physisches Alignment (ext4 Blocksize & Page Size)

    Die Zahl 4 MiB (4.194.304 Byte) ist fĂŒr das Betriebssystem eine magische Grenze. Sie entspricht exakt den Speicherseiten (Huge Pages) des Kernels. Eine Datei mit genau 4 MiB wird von modernen NVMe-SSDs in einem einzigen, ununterbrochenen Hardware-Zyklus direkt in den RAM gestreamt. Wenn wir die SH-Daten in dieselbe Datei stecken, wĂŒrde sich die GrĂ¶ĂŸe eines einzelnen Splat-Blocks von 16 Byte auf ungerade 20 oder 24 Byte Ă€ndern. Das Problem: 4.194.304 Byte lĂ€sst sich nicht ohne Rest durch 20 oder 24 teilen. Wir hĂ€tten am Ende einer Datei ungenutzte FĂŒllbytes (Padding) oder Splats, die mitten ĂŒber eine harte 4-KiB-Dateisystemblockgrenze zerrissen werden. Das wĂŒrde bei jedem Lese-Vorgang zusĂ€tzliche SSD-Latenzen erzeugen.

    2. CPU-Cache-Effizienz (Cache Line Locality)

    Moderne Prozessoren laden Daten nicht byte-weise, sondern immer in Blöcken von 64 Byte (Cache Lines) in den ultraschnellen L1/L2-Cache. Getrennte Dateien: In unserem aktuellen Code rattert die CPU in der Pipeline-Schleife linear durch das p_pool-Array. Da ein Splat exakt 16 Byte groß ist, passen exakt 4 Splats in eine einzige 64-Byte-Cache-Line. Die CPU weiß im Voraus, was als NĂ€chstes kommt, und berechnet 4 Splats ohne einen einzigen Cache-Miss. Kombinierte Datei (z. B. 20 Byte): Ein Splat wĂŒrde ĂŒber die 64-Byte-Grenze des CPU-Caches hinausragen. Der Prozessor mĂŒsste mitten unter der Berechnung eines einzigen Splats anhalten und neue Daten aus dem langsameren Haupt-RAM anfordern. Das wĂŒrde die Framerate massiv einbrechen lassen.

    3. Biologische SĂ€ttigung filtert Materialdaten

    Dadurch, dass die Materialdaten in der separaten .m-Datei liegen, nutzen wir das SĂ€ttigungsmodell optimal aus: Die CPU liest die Geometrie (.p) und transformiert die Punkte. Wenn die "Retina" an einer Koordinate bereits zu 255 gesĂ€ttigt (undurchsichtig) ist, bricht der Code sofort ab (return). Der Clou: FĂŒr all diese verdeckten Splats greift die CPU niemals auf das m_pool-Array zu. Wir sparen uns das rechenintensive Laden und Berechnen der SH-Blickwinkel aus dem Speicher fĂŒr alles, was ohnehin unsichtbar ist. WĂ€ren die SH-Daten mit der Geometrie verschmolzen, mĂŒssten wir sie gezwungenermaßen immer mit in den Cache laden, selbst wenn der Punkt verdeckt ist.

    Zusammenfassung

    Mit der Kombination aus einer 16-Byte-Geometrie (.p) und einem 1-Byte-Materialstrom (.m) bleibt alles perfekt auf Zweierpotenzen ausgerichtet. Das garantiert, dass weder auf dem SSD-Bus noch im CPU-Cache auch nur ein einziges Bit Speicherbandbreite verschwendet wird.

    Die Struktur

    			W0000/XXXX/YYYY/ZZZZ/TTTTT.SUFFIX
    
        Verzeichnis-Layout: W0000/[S_x+5000]/[S_y+5000]/[S_z+5000]/[zeit_basis].p und .m
            Jede Koordinate ist 4-stellig mit fĂŒhrenden Nullen (%04d).
            Die zeit_basis ist 5-stellig mit fĂŒhrenden Nullen (%05d) und schreitet in 100er-Schritten voran (z.B. 00000, 00100).
        .p-Dateien (HyperSplat4D Pool): MĂŒssen exakt 4.194.304 Bytes groß sein. Sie enthalten 262.144 Splats zu je 16 Bytes mit folgendem Packed-Layout:
            int16_t x, y, z (Sektor-relative Koordinaten, 0 bis 499)
            uint16_t t_start (0 bis 99)
            uint8_t t_duration (Lebensdauer)
            uint8_t opacity (Sichtbarkeit, >0 damit es gerendert wird)
            uint8_t color_r, color_g, color_b, pad
        .m-Dateien (Material/Glanz Pool): MĂŒssen exakt 262.144 Bytes groß sein. Sie enthalten 262.144 einzelne int8_t-Werte (Metadaten fĂŒr den Shading-Glanz), die eins-zu-eins den Splats zugeordnet sind.
    

    Wir starten immer in W0000, wenn fretina aufgerufen wird.

    Aufbau des P‑Befehls (Kamera‑/Render‑Steuerung)

    Ein P‑Eintrag wird als Text‑Zeile auf stdin geschrieben. Die Zeile besteht aus dem Buchstaben P gefolgt von sieben ganzzahligen Feldern, die durch Leerzeichen getrennt sind und optional ein Vorzeichen - besitzen.

     P       \n
    
        cam_x, cam_y, cam_z – absolute Kameraposition im Welt‑Koordinatensystem.
        Intern wird ein Offset von +250 zu cam_x und cam_y addiert, weil die Daten‑Chunks jeweils einen Sektor‑Mittelpunkt bei (250, 250, 250) haben.
        pan – horizontale Schwenk‑Komponente (in Bild‑pixeln‑Àhnlichen Einheiten).
        WĂ€hrend der Projektionsrechnung wird pan * rz >> 9 zu x‑Koordinate addiert, also ein Bild‑verschiebungs‑Effekt, der stĂ€rker wirkt, je weiter das Objekt vom Beobachter entfernt ist.
        tilt – vertikale Schwenk‑Komponente (analog zu pan, wirkt auf die y‑Koordinate).
        zoom – additive Änderung der effektiven Brennweite.
        Die Formel fl = 300 + zoom bestimmt, wie stark das Bild „herangezoomt“ wird; ein grĂ¶ĂŸerer Wert vergrĂ¶ĂŸert die projizierten Splats, ein kleinerer Wert verkleinert sie.
        b_shift – „brightness‑shift“ (im Quellcode nur als b_shift gespeichert, aber nicht weiter verwendet).
        Der Wert wird derzeit nicht in den Render‑Berechnungen ausgewertet, er ist also reserviert fĂŒr mögliche spĂ€tere Helligkeits‑ oder Farb‑Modulationen.
    
    Das Programm liest die Zeile zeichenweise; erst nach dem abschließenden Zeilen‑Break (\n) oder nach dem siebten Zahlen‑Token wird die Zeile verarbeitet.
    
    
    

    Was passiert bei Änderung einzelner P Werte?

    Parameter Erhöhter Wert → Was Ă€ndert sich im Bild cam_x / cam_y Die Kamera verschiebt sich entlang der jeweiligen Achse. Das verschiebt das gesamte Bild horizontal/vertikal – Objekte erscheinen nach links/rechts bzw. oben/unten, weil die relative Lage zu cam_x / cam_y Ă€ndert. cam_z Ändert die Entfernung zum Beobachter. Ein grĂ¶ĂŸerer cam_z (weiter weg) reduziert die projizierte GrĂ¶ĂŸe (fl / rz) und lĂ€sst die Szene „zusammenziehen“. Ein kleinerer cam_z (nach vorne) vergrĂ¶ĂŸert die Objekte und verkĂŒrzt die Tiefen­perspektive. pan Positive Werte drĂŒcken das Bild nach rechts (Objekte wandern nach links) – es wirkt wie ein Schwenk um die vertikale Achse. Negative Werte schwenken nach links. Der Effekt steigt linear mit der Tiefe rz (weiter entfernte Splats bewegen sich stĂ€rker). tilt Analog zu pan, aber vertikal. Positive Werte kippen das Bild nach unten (Objekte bewegen sich nach oben), negative Werte nach oben. Auch hier gilt: Je grĂ¶ĂŸer rz, desto stĂ€rker die Verschiebung. zoom Erhöht die Basis‑Brennweite (fl = 300 + zoom). Mehr Zoom → grĂ¶ĂŸere projizierte Splat‑GrĂ¶ĂŸen → Bild wirkt „gezoomt“. Reduziertes Zoom (oder negative Werte) verkleinert das Bild, erweitert das Sichtfeld. b_shift Momentan hat der Wert keine Auswirkung auf das Rendering; er bleibt im Code ungenutzt und kann spĂ€ter fĂŒr Helligkeits‑ oder Farb‑Offset‑Modulationen reserviert werden. Beispiel‑Sequenz P 0 0 0 0 0 0 0 // Kamera im Ursprung, keine Schwenks, Standard‑Zoom P 100 0 0 0 0 0 0 // Kamera 100 px nach rechts → Szene wandert nach links P 0 0 0 50 0 0 0 // Pan‑Wert +50 → alle weiter entfernten Objekte verschieben sich nach rechts P 0 0 0 0 0 100 0 // Zoom +100 → Bild „herangezoomt“, Splats grĂ¶ĂŸer