ecefe61611
- SPIKE_TEXTUR_render3d.md: Auftrag/Uebergabe fuer den kleinsten ehrlichen Durchstich (RenderStyle::Textured real: UVs, prozedurales Schachbrett, Textur-Bind-Group, MESH_TEXTURED_WGSL, spike3d umschaltbar). - PENDENZEN: Spike als konkretes Item unter 'Als Naechstes', verlinkt am bestehenden Textur-/PBR-Backlog-Eintrag als dessen erster Durchstich.
138 lines
6.9 KiB
Markdown
138 lines
6.9 KiB
Markdown
# SPIKE — Bild-Texturen in `render3d` (`RenderStyle::Textured` real machen)
|
||
|
||
Stand: 2026-07-05. **Auftrag/Übergabe für einen Agenten. Kleinster ehrlicher
|
||
Durchstich — kein Produktfeature, keine Integration.**
|
||
|
||
Ziel: Beweisen, dass der bestehende wgpu-3D-Renderer echte **Bild-Texturen** auf
|
||
Wandflächen darstellen kann, sichtbar im `spike3d`-Fenster. Am Ende steht eine
|
||
belastbare Aussage, wie viel Arbeit „richtig gutes texturiertes 3D" wirklich ist —
|
||
statt Spekulation.
|
||
|
||
---
|
||
|
||
## 0. Ausgangslage (verifiziert am 2026-07-05)
|
||
|
||
- `render3d` ist **kein** Three.js-Wrapper, sondern ein eigenständiger wgpu-Renderer
|
||
(~6400 LOC): echte GPU-Pipeline (wgpu 29), Tiefenpuffer, MSAA, WGSL-Shader.
|
||
Läuft nativ (winit-Spike), headless (naga-validiert) und im Browser (WebGPU).
|
||
- **`RenderStyle::Textured` existiert bereits als Stub** (`gpu.rs:34` Enum-Variante,
|
||
`gpu.rs:47` Parse aus `"textured"`) — es gibt aber **kein echtes Texturing**:
|
||
kein Sampler, keine Textur-Bind-Group, keine Bilddaten.
|
||
- Die `cap_pipeline` mit Layout `[pos vec3, uv vec2]` + `CAP_WGSL` ist **nicht** für
|
||
Bildtexturen, sondern für die **Schnittflächen-Kappen** (prozedurale Schraffur);
|
||
die UVs steuern dort den Schraffur-Abstand. **Nicht damit verwechseln.**
|
||
- **Günstig für uns:** Die Muster, die der Spike braucht, existieren schon —
|
||
ein UV-tragendes Vertex-Layout und eine zweite/dritte Pipeline, die sich die
|
||
`Globals`-Bind-Group teilt (`grid`, `cap`). Der texturierte Mesh-Pfad reiht sich
|
||
1:1 in dieses Muster ein.
|
||
|
||
---
|
||
|
||
## 1. Echte Symbole — vor dem Coding lesen
|
||
|
||
| Was | Ort |
|
||
|---|---|
|
||
| Vertex heute interleaved `[pos.xyz, normal.xyz, color.rgb]`, `FLOATS_PER_VERTEX`, `Mesh`-Struct | `src-tauri/render3d/src/types.rs:322` ff. |
|
||
| Quad-Emitter (Normale + Farbe je Vertex, Reihenfolge `(0,1,2)+(0,2,3)`) | `src-tauri/render3d/src/mesh.rs:886` |
|
||
| Wand-Extrusion / Mesh-Bau | `src-tauri/render3d/src/mesh.rs` — `extrude_wall` (`:91`), `build_walls_mesh` (`:911`) |
|
||
| Haupt-Pipeline + `Globals`-Bind-Group (group 0) | `src-tauri/render3d/src/gpu.rs:232`–`:320` |
|
||
| Vorlage „zweite Pipeline teilt sich Globals" — Grid | `src-tauri/render3d/src/gpu.rs:329` |
|
||
| Vorlage „Pipeline mit UV-Layout `[pos vec3, uv vec2]`" — Cap | `src-tauri/render3d/src/gpu.rs:408` |
|
||
| `RenderStyle`-Enum + Stub `Textured` | `src-tauri/render3d/src/gpu.rs:34`, `:47` |
|
||
| Pipeline-Bindung im Render-Pass (Muster für Stil-Umschaltung) | `src-tauri/render3d/src/gpu.rs:847` |
|
||
| Shader als WGSL-Konstanten (`MESH_WGSL`, `CAP_WGSL`) | `src-tauri/render3d/src/shaders.rs` |
|
||
| Beleuchtungsmodell (hemisphärisch + Directional + Fill) — Doku | `src-tauri/render3d/src/shaders.rs:1`–`40` |
|
||
| naga-WGSL-Validierung headless (Test-Vorlage) | `src-tauri/render3d/src/lib.rs:924` (`cap_module`) |
|
||
| Fenster-Spike mit Orbit-Kamera | `src-tauri/render3d/src/bin/spike3d.rs` |
|
||
|
||
---
|
||
|
||
## 2. Umfang — exakt das, nicht mehr
|
||
|
||
### 2.1 UVs auf Wandflächen
|
||
- In der Quad-Emitter-Funktion (`mesh.rs:886`) je Vertex eine **UV** berechnen:
|
||
planare Projektion in **Metern** — `u` = Distanz entlang der Wandachse,
|
||
`v` = Höhe (z). Textur-Raster damit weltmassstäblich (z. B. 1 Kachel = 1 m).
|
||
- Den bestehenden `[pos, normal, color]`-Pfad **bitgleich unangetastet** lassen.
|
||
Zwei zulässige Wege (Agent wählt begründet):
|
||
1. **Separates additives UV-Array** in `Mesh` (Default leer/None), oder
|
||
2. **Paralleler `build_walls_mesh_textured`** → interleaved
|
||
`[pos.xyz, normal.xyz, uv.xy]`.
|
||
- Regressionstests für den Alt-Pfad müssen grün bleiben (siehe §4).
|
||
|
||
### 2.2 Test-Textur prozedural (kein Asset, keine `image`-Crate)
|
||
- Ein **256×256 RGBA-Schachbrett/Grid im Code** generieren (`Vec<u8>`).
|
||
- `device.create_texture` + `queue.write_texture` + `Sampler`
|
||
(`FilterMode::Linear`, `AddressMode::Repeat`). Mipmaps optional (nice-to-have für
|
||
flache Blickwinkel; kein Muss für den Spike).
|
||
- Selbstständig, damit der Spike ohne Dateipfade/Asset-Pipeline läuft.
|
||
|
||
### 2.3 Textur-Bind-Group (group 1)
|
||
- Neue Bind-Group-Layout mit `texture_view` (`TextureSampleType::Float`) +
|
||
`sampler`. **`Globals` bleibt group 0** und unverändert.
|
||
|
||
### 2.4 Textured-Pipeline + WGSL (`MESH_TEXTURED_WGSL`)
|
||
- Vertex-Layout `[pos vec3, normal vec3, uv vec2]`, `TriangleList`.
|
||
- **Dieselbe Beleuchtung wie `MESH_WGSL`** (hemisphärisches Ambient + Directional +
|
||
Fill) — nur **Albedo = `textureSample(tex, samp, uv)`** statt Vertex-Farbe.
|
||
- Depth-Format, MSAA (`SAMPLE_COUNT`) und Color-Target **identisch** zur
|
||
Haupt-Pipeline (sonst inkompatibler Render-Pass).
|
||
- Pipeline-Layout bindet group 0 (Globals) **und** group 1 (Textur).
|
||
|
||
### 2.5 Verdrahten
|
||
- Bei `RenderStyle::Textured` im Render-Pass die neue Pipeline + beide Bind-Groups
|
||
setzen (Muster: `cap_pipeline`-Bindung bei `gpu.rs:847`).
|
||
|
||
### 2.6 Spike sichtbar machen
|
||
- `spike3d.rs` so erweitern, dass der Stil auf `Textured` schaltbar ist
|
||
(Tastendruck, z. B. `T`, **oder** Startkonstante). Die Demo-Wände sollen
|
||
texturiert im Orbit erscheinen.
|
||
|
||
---
|
||
|
||
## 3. Randbedingungen (hart)
|
||
|
||
- **Nur** die `render3d`-Crate. `src/web.rs` und die Tauri-/`native3d`-Oberfläche
|
||
**nicht** anfassen.
|
||
- Feature-gegatet unter dem bestehenden `render`/`window`-Feature.
|
||
**Default-Build und Default-Darstellung bleiben unverändert.**
|
||
- **Keine neuen Dependencies** (insbesondere **kein `image`-Crate**) für den Spike.
|
||
- Term-/Reihenfolge-sensible Geometrie (Parität) wird **nicht** berührt — es kommt
|
||
nur additiv ein UV-Kanal + ein zweiter Render-Pfad dazu.
|
||
- Kommentar-Stil und Sprache (Deutsch, ausführliche Begründungs-Kommentare) wie im
|
||
umgebenden Code beibehalten.
|
||
|
||
---
|
||
|
||
## 4. Akzeptanz / Verifikation
|
||
|
||
1. `cargo test` (im Crate-Verzeichnis `src-tauri/render3d`) **grün**, inklusive:
|
||
- bestehende Mesh-Regression (Alt-Pfad `[pos,normal,color]` unverändert),
|
||
- **neuer naga-Validierungstest** für `MESH_TEXTURED_WGSL` (Vorlage:
|
||
`lib.rs:924`).
|
||
2. `cargo run --features window --bin spike3d` zeigt die Demo-Wände mit
|
||
**erkennbarer, korrekt gemappter** Schachbrett-Textur:
|
||
- Raster weltmassstäblich (in Metern), keine Verzerrung an Gehrungen/Ecken,
|
||
- beleuchtet wie im Shaded-Modus (Volumen bleibt ablesbar).
|
||
3. Umschalten Shaded ↔ Textured zur Laufzeit (oder per Startkonstante) funktioniert
|
||
ohne Re-Meshing-Crash.
|
||
|
||
---
|
||
|
||
## 5. Abschlussbericht (vom Agenten am Ende zu liefern)
|
||
|
||
- Welche Dateien geändert/hinzugefügt wurden und warum.
|
||
- Wie die UVs projiziert werden (Achswahl, Massstab, Verhalten an Gehrungen).
|
||
- Welcher der beiden UV-Wege (§2.1) gewählt wurde und weshalb.
|
||
- **Ehrliche Lückenliste für „richtig gutes" Texturing:** Asset-/Bild-Datei-Laden,
|
||
Material→Textur-Zuordnung (Wandtyp/Layer → Material), Normal-/Roughness-Maps
|
||
(PBR), anisotropes Filtern + Mipmaps, Web-Pfad (`web.rs`/WebGPU), UI zum
|
||
Zuweisen. Grobschätzung Aufwand je Punkt.
|
||
|
||
---
|
||
|
||
## 6. Nicht im Scope
|
||
|
||
Asset-/Bild-Datei-Laden · Material-System · mehrere Texturen gleichzeitig ·
|
||
PBR/Normal-Maps · Web-Pfad (`web.rs`) · jegliche UI · Anbindung unter die Webview.
|