From ff80b3cc0fd5a235f088868ddd8fc2e1119af85a Mon Sep 17 00:00:00 2001 From: irrlicht Date: Fri, 12 Jun 2026 22:36:03 +0200 Subject: [PATCH] =?UTF-8?q?Plan=20f=C3=BCr=20sp=C3=A4tere=20Renderer-Imple?= =?UTF-8?q?mentierung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notes/renderer-plan.md | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 notes/renderer-plan.md diff --git a/notes/renderer-plan.md b/notes/renderer-plan.md new file mode 100644 index 0000000..b946b91 --- /dev/null +++ b/notes/renderer-plan.md @@ -0,0 +1,110 @@ +# wds — Renderer-Plan + +Stand: 2026-06-12. Entscheidungen aus der irl3d-Analyse, festgehalten bevor +der Projekt-Einstieg über die Kern-Systeme (Signals/KV, CLI-Phase) läuft. + +## Ziel + +PS1-artiger Look, von vornherein nativ und simpel implementiert statt +emuliert: affines Texture-Mapping, Integer-Vertex-Koordinaten, 16-Bit-Farbe. +Niedrige interne Auflösung (320×240), hochskaliert aufs Fenster. + +Referenz ist `../irl3d`: gleiche Engine-Idee (datengetrieben, eine +OBJ-Szene, Signals/KV/Ink), aber dort als 8-Bit-Palette-CPU-Softwarerenderer +in Q16.16. wds ersetzt den Grafikpfad durch echtes GPU-Rastern. + +## Hardware-Target + +Mittelklasse-Laptop von 2015 (Klasse: i5-5200U + Intel HD 5500). +Konsequenzen: + +- Zwei schwache CPU-Kerne → Transformation gehört auf die GPU, die CPU + bleibt für Physik und Spiellogik frei. +- Per-Frame-Vertex-Streaming (CPU-Transform, GTE-Stil) wäre auf alten + iGPU-Treibern der riskante Pfad (Buffer-Upload-Stalls) → statische + Vertex-Buffer, einmal hochgeladen. +- wgpu-Backend: Vulkan primär (ANV unterstützt Gen8+), GL als Fallback + einplanen. Keine Features jenseits von Baseline-WebGPU benutzen. + +## Entscheidungen + +1. **wgpu direkt, kein pbio.** pbio ist eine Abstraktion für + Software-Renderer (8-Bit-Framebuffer + Palette-Blit) — für echtes + GPU-Rastern Verschwendung. winit + wgpu direkt im Projekt. + +2. **Vertex-Shader-Transform mit Pixel-Snapping.** Model→View→Projektion im + Vertex-Shader. Danach `xy/w` auf das Pixelraster der internen Auflösung + runden und wieder mit `w` multiplizieren → Vertex-Jitter wie auf der PS1, + authentisch gerechnet, nicht nachgestellt. + +3. **Affines Texture-Mapping via `@interpolate(linear)`.** WGSL kann die + perspektivische Korrektur pro Varying abschalten. UVs (und ggf. + Vertex-Colors) linear interpolieren → das Textur-Wobbeln kommt gratis. + Gegenmittel bleibt wie auf der PS1 das Unterteilen großer Flächen im + Asset, nicht Shader-Tricks. + +4. **RGB555 + Ordered Dithering im Fragment-Shader.** wgpu hat kein + 555-Render-Target-Format; Render-Target bleibt RGBA8 bei 320×240, aber + der Fragment-Shader quantisiert auf 5 Bit pro Kanal mit 4×4-Bayer-Dither. + Die Farbreduktion ist echt, nur das Speicherformat ist modern. + Das 16. Bit entspricht dem PS1-Maskbit → bei uns **1-Bit-Alpha** + (Alpha-Test, kein Blending) — Fortführung der Index-0-Transparenz + aus irl3d. + +5. **Z-Buffer: ja.** Ordering-Tables wären nur eine technische Hürde, kein + ästhetischer Gewinn. Standard-Depth-Buffer auf dem internen Target. + +6. **UVs aus dem OBJ (`vt`).** irl3d ignoriert `vt` und mappt planar über + Welt-Koordinaten; wds liest echte UVs. PS1-Spiele hatten handgemachte + UVs — das gehört zum Look. + +7. **Licht: gebacken zuerst.** Nur Gouraud-Shading wäre zu einseitig. + Plan: Lichteffekte in die Szene backen (Blender → Vertex-Colors), + im Shader mit der Textur multiplizieren und mitquantisieren. Dynamische + per-Vertex-Punktlichter (im Vertex-Shader, additiv auf die gebackene + Farbe) als spätere Stufe. Kein Per-Pixel-Lighting. + +## Pipeline-Skizze + +``` +statische VBOs (Pos i16/f32, UV, Vertex-Color) + → Vertex-Shader: Model·View·Proj, dann Snap auf 320×240-Raster + → Raster (Hardware), UV/Color @interpolate(linear) + → Fragment: Texel-Fetch (nearest), × Vertex-Color, + Alpha-Test (1 Bit), RGB555-Quantisierung + 4×4-Bayer + → RGBA8-Offscreen 320×240 + Depth + → Blit-Pass: Nearest-Upscale mit Letterbox (4:3) aufs Fenster +``` + +Draw-Granularität wie irl3d: pro Instance ein Draw (Uniform: Pos + Yaw), +Material-Batching später, wenn es weh tut. + +## Offene Punkte + +- **Asset-Pipeline:** Texture-Painting in Blender ist mühsam. Kandidaten + für Textur-pro-Fläche-Workflows: TrenchBroom (Map-Format-Import nötig), + Crocotile 3D, Blockbench. Entscheidung wenn der Szenen-Loader ansteht. +- **Texturformat:** 8-Bit-CLUT-TGA weiterverwenden (PS1-authentisch, + Paletten-Swaps bleiben möglich) vs. direkte 16/24-Bit-Texturen. +- **Fog / Distance-Fade:** irl3d hat hartes Pop-In bei `CULL_DIST` — + in wds von Anfang an als Fade Richtung Sky-Farbe einplanen (im Shader + trivial, passt zur PS1). +- **Skybox:** Cubemap wie irl3d oder schlicht Far-Plane-Farbe + Fog. +- Interne Auflösung umschaltbar lassen (QVGA/VGA wie irl3d). + +## Aus irl3d portierbar (renderer-unabhängig) + +signals, kv, ink, story_ctrl, game (ActionCtx-Idee), physics, pick, +camera, obj-Loader (um `vt` erweitern), tga, wav, audio, assets, +fix/math (Q16.16 bleibt für Spiellogik/Physik sinnvoll; der Renderer +selbst rechnet f32 — die GPU kennt ohnehin nur Floats). + +## Projektphasen + +1. **CLI-Phase (läuft):** KV-Store, Signal/Action-Dispatcher, + Ink-Integration, Konsolen-REPL als erstes Frontend. Effects als Daten + (`hide_object`, `play_sound`, `load_palette`), damit spätere Subsysteme + sie konsumieren, ohne dass der Kern sie kennt. +2. Datenmodell (Mesh/Instance/Material/Scene + TOML-Formate) headless. +3. Renderer nach diesem Plan, gegen das stehende Datenmodell. +4. Physik, Audio, Panel-UI andocken (Ports aus irl3d).