4.6 KiB
Texturoptimierung für den Web-Avatar: Codec- und Algorithmus-Vorüberlegungen
Stand: 08.09.2026 · Vorbereitung, noch ohne Dateien
Anschluss an: uebergabe-animationspipeline.md
Kontext
Die Animationspipeline ist abgeschlossen (88 KB pro Clip, kein Engpass mehr). Der Fokus liegt jetzt auf den Texturen des Avatars. Die Dateien liegen noch nicht vor — dieses Dokument hält nur die Vorüberlegungen zu Codec und Verfahren fest, damit sie nicht verloren gehen.
Packing und Scaling sind bereits auf dem Schirm und hier bewusst nur gestreift.
Virtual Textures: nicht praktikabel
Frage war, ob sich etwas wie Unreals Virtual Textures in three.js abbilden lässt.
Kurz: nein — und für einen Avatar auch nicht das passende Werkzeug.
- Unreals VT setzt auf Sparse/Tiled Resources auf GPU-Ebene. WebGL2 kennt das nicht, WebGPU exponiert es derzeit ebenfalls nicht.
- Ein Nachbau wäre möglich (Atlas + Indirection-Textur + Feedback-Pass), aber der Feedback-Readback ist im Browser latenzbehaftet. Aufwand und Nutzen stehen in keinem Verhältnis.
- VT lohnt sich, wenn unique Texturdaten das VRAM um ein Vielfaches übersteigen — Open-World-Terrain, große Umgebungen. Ein Avatar hat 5–15 Maps. Das Problem existiert hier nicht.
Was den eigentlichen Zweck erfüllt
Progressives Nachladen. Erst eine 512er-Fassung zeigen, dann auf volle Auflösung tauschen. Umsetzbar entweder über zwei separate Dateien oder, bei KTX2, durch gezieltes Laden nur der oberen Mip-Level.
Mipmaps: nicht verzichtbar
Verzicht wäre kontraproduktiv.
- Mips kosten +33 % Speicher, machen das Sampling aber schneller, weil der Texture-Cache trifft.
- Ohne Mips shimmert das Bild sichtbar, sobald die Textur verkleinert dargestellt wird.
- Bei KTX2 sind die Mips mitkomprimiert — der Download-Aufschlag beträgt 33 % auf die komprimierte Größe, nicht auf die Rohgröße.
Falle
three.js kann für GPU-komprimierte Texturen keine Mips zur Laufzeit
generieren. Sie müssen beim Encoding in die Datei geschrieben werden.
gltfpack und toktx tun das per Default, aber wer sich auf
generateMipmaps verlässt, bekommt bei KTX2 stillschweigend keine.
Wo Verzicht vertretbar ist
Nur bei Maps, die nie verkleinert dargestellt werden: LUTs, UI-Elemente, Screen-Space-Texturen.
Ergänzend statt Verzicht
anisotropy auf 4–8 setzen. Kostet wenig und bringt bei streifenden
Blickwinkeln deutlich mehr als jede Mip-Diskussion.
Codec-Optionen
Der entscheidende Unterschied ist nicht die Dateigröße, sondern was im VRAM landet.
| Format (4K, RGBA) | Download | VRAM inkl. Mips |
|---|---|---|
| PNG | groß | ~85 MB |
| WebP / AVIF | klein | ~85 MB (dekodiert zu RGBA8) |
| KTX2 UASTC → BC7/ASTC | mittel | ~21 MB |
| KTX2 ETC1S → BC1/ETC | sehr klein | ~11 MB |
WebP spart ausschließlich Bandbreite. KTX2 spart Bandbreite, Speicher und Sampling-Bandbreite. Für einen Avatar mit mehreren Maps der klare Gewinner.
Die zwei Basis-Modi
ETC1S — starke Kompression, sichtbare Artefakte an harten Kanten. Geeignet für AO, Roughness, Metallic, Masken, oft auch Albedo.
UASTC — deutlich höhere Qualität, größere Datei (mit RDO + Zstd aber vertretbar). Pflicht für Normal Maps. ETC1S auf einer Normal Map erzeugt Banding im Shading, das auf Haut sofort auffällt.
Zusätzlich: Normal Maps als Zwei-Kanal speichern und Z im Shader rekonstruieren. Entfernt einen kompletten Kanal als Fehlerquelle.
Werkzeuge
gltfpack wendet Textureinstellungen global an (-tc, -tu, -tw).
Sobald Normal Map und ORM unterschiedlich behandelt werden sollen, reicht das
nicht mehr.
glTF-Transform ist dann das bessere Werkzeug: kennt --slots und erlaubt
Codec, Qualität und Auflösung getrennt pro Map-Typ.
Alternativ: toktx / basisu direkt auf die Einzeldateien anwenden und
das Ergebnis anschließend im glTF referenzieren.
three.js-Seite
KTX2Loader mit setTranscoderPath() und detectSupport(renderer). Ohne
detectSupport weiß der Loader nicht, ob nach BC7 oder ASTC transcodiert
werden soll.
Erster Schritt, sobald die Dateien da sind
Vor allen Codec-Feinheiten: wie viele Maps werden überhaupt gebraucht?
- Roughness ggf. als konstanter Faktor statt als Textur
- Metallic bei Haut ohnehin 0
- AO teilweise verzichtbar
Jede eingesparte Map schlägt jede Codec-Entscheidung.
Danach dasselbe Vorgehen wie bei den Animationen: erst messen, dann optimieren. Ein Inventar mit Auflösung, Kanalbelegung und tatsächlichem Informationsgehalt pro Map. Erfahrungsgemäß sind halbleere Kanäle und überdimensionierte Masken der häufigste Fund.