fix(world): Gehweg lädt seine Diffuse-Textur auch ohne Normal- und ARM-Karte

loadSet() lud Diffuse-, Normal- und ARM-Karte in einem gemeinsamen
Promise.all und fiel schon beim Fehlen einer einzigen Datei auf den
einfarbigen Ersatz zurück. modular_sidewalk_curb_kit liefert für den
Gehweg nur sidewalk_Diffuse.jpg (keine Normal-Map, und die
metallicRoughness-Karte ist laut Entwurf eine 605-Byte-Einfarbfläche,
die bewusst nicht übernommen wird) — Folge: 0,298 km² rendern einfarbig
#d8d2c4, bei jedem Laden "Textur sidewalk fehlt", die committete Kachel
blieb ungenutzt.

Nur die Diffuse-Karte ist jetzt Pflicht; Normal- und ARM-Karte werden
einzeln geladen und fallen bei einem Fehler je für sich auf null zurück,
ohne die anderen beiden mitzureißen. Ohne ARM-Karte bleibt roughness auf
0.9 (derselbe Wert wie der bisherige einfarbige Ersatz).

loadSet() ist jetzt exportiert, damit tests/materials.test.js sie mit
einem Attrappenloader ohne echte Dateien prüfen kann: Diffuse allein,
Diffuse+Normal ohne ARM, der volle Satz, und weiterhin der einfarbige
Ersatz, wenn die Diffuse-Karte selbst fehlt.
This commit is contained in:
knso committed 2026-09-18 06:16:12 +02:00
1 parent 736dcbc1ad
commit 3f4fa7f1ed
2 files changed
+85 -9

No files matched your search

+28 -6
View File
@@ -67,17 +67,36 @@ export function waterNormalData(size = 128) {
return data;
}
async function loadSet(loader, slug, fallback, { tint, maxAnisotropy } = {}) {
let map, normalMap, arm;
/**
* Ein Materialsatz aus den Kacheln von `./textures/<slug>_*.jpg`.
*
* Nur die Diffuse-Karte ist Pflicht; Normal- und ARM-Karte sind freiwillig. Grund: Nicht jede
* Quelle liefert alle drei. Der Gehweg aus modular_sidewalk_curb_kit hat nur `sidewalk_Diffuse.jpg`
* — das Kit bringt gar keine Normal-Map dafür, und `sidewalk_metallicRoughness.png` ist eine 605
* Byte große Einfarbfläche, die der Entwurf bewusst nicht übernimmt (Abschnitt "Die beiden Kits").
* Solange alle drei Pflicht waren, fiel der Gehweg deshalb auf den einfarbigen Ersatz zurück: 0,298
* km² in `#d8d2c4`, bei jedem Laden die Warnung "Textur sidewalk fehlt", und die committete
* Diffuse-Kachel lag ungenutzt im Repository.
*
* Ohne ARM-Karte bleibt die Rauheit auf demselben Wert wie beim einfarbigen Ersatz (0,9): matt,
* wie eine Betonfläche. Ohne Normal-Map ist die Fläche flach — das ist der ehrliche Zustand der
* Quelle und immer noch näher an ihr als ein Einfarbton.
*/
export async function loadSet(loader, slug, fallback, { tint, maxAnisotropy } = {}) {
let map;
try {
[map, normalMap, arm] = await Promise.all(
["Diffuse", "nor_gl", "arm"].map((m) => loader.loadAsync(`./textures/${slug}_${m}.jpg`)),
);
map = await loader.loadAsync(`./textures/${slug}_Diffuse.jpg`);
} catch (err) {
console.warn(`Textur ${slug} fehlt, einfarbiger Ersatz:`, err);
return new MeshStandardMaterial({ color: fallback, roughness: 0.9 });
}
// Die beiden Beiwerke einzeln und je für sich: eine fehlende Datei nimmt nur ihre eigene
// Wirkung weg, nicht die der anderen und schon gar nicht die der Diffuse-Karte.
const [normalMap, arm] = await Promise.all(
["nor_gl", "arm"].map((m) => loader.loadAsync(`./textures/${slug}_${m}.jpg`).then((t) => t, () => null)),
);
for (const t of [map, normalMap, arm]) {
if (!t) continue;
t.wrapS = t.wrapT = RepeatWrapping;
// Ruling 58: Straßen laufen flach in die Tiefe — dort flimmert Standard-
// filterung zuerst. createMaterials() kennt den Renderer nicht selbst, daher
@@ -89,7 +108,10 @@ async function loadSet(loader, slug, fallback, { tint, maxAnisotropy } = {}) {
// (Ruling 57): metalness steht fest auf 0, three multipliziert texelMetalness nur
// noch dazu (metalnessmap_fragment.glsl.js) und könnte das Ergebnis nie von 0
// wegbewegen — reine Kosten (Texturbindung, Shader-Permutation) ohne Wirkung.
const material = new MeshStandardMaterial({ map, normalMap, aoMap: arm, roughnessMap: arm, metalness: 0 });
const material = new MeshStandardMaterial({
map, normalMap, aoMap: arm, roughnessMap: arm, metalness: 0,
...(arm ? {} : { roughness: 0.9 }),
});
// Ruling 55/56: nur der geladene Erfolgsfall bekommt die Tönung — der einfarbige
// Ersatz oben hat schon seinen eigenen, passenden Grundton.
if (tint) material.color.set(tint);