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

+57 -3
View File
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { applyPolygonOffsets, MATERIAL_KEYS, POLYGON_OFFSETS, POLYGON_OFFSET_ORDER, SURFACE_COLORS, TEXTURES,
waterNormalData } from "../src/world/materials.js";
import { afterEach, describe, expect, it, vi } from "vitest";
import { applyPolygonOffsets, loadSet, MATERIAL_KEYS, POLYGON_OFFSETS, POLYGON_OFFSET_ORDER, SURFACE_COLORS,
TEXTURES, waterNormalData } from "../src/world/materials.js";
import { buildChunkGeometry } from "../src/world/geometry.js";
describe("materials", () => {
@@ -127,3 +127,57 @@ describe("Schichten aus Teil 2", () => {
expect(POLYGON_OFFSETS.curb).toBeUndefined();
});
});
// Befund der Gesamtprüfung: loadSet() lud Diffuse-, Normal- und ARM-Karte in einem einzigen
// Promise.all und fiel auf den einfarbigen Ersatz zurück, sobald eine davon fehlte. Für den Gehweg
// liefert modular_sidewalk_curb_kit nur `sidewalk_Diffuse.jpg` (der Entwurf sagt das selbst,
// Abschnitt "Die beiden Kits") — 0,298 km² rendern deshalb einfarbig, und die committete Kachel
// lag ungenutzt im Repository. Die Tests laufen ohne echte Dateien: loadSet() bekommt seinen Loader
// von außen, hier ein Attrappenloader, der je nach Dateiname auflöst oder abweist.
describe("Texturen laden: Diffuse ist Pflicht, Normal und ARM sind freiwillig", () => {
/** Loader-Attrappe: löst für jede Kachel auf, deren Kürzel in `vorhanden` steht. */
const fakeLoader = (vorhanden) => ({
loadAsync: (url) => {
// Über die Endung vergleichen, nicht über den letzten Unterstrich: "nor_gl" trägt selbst einen.
const teil = vorhanden.find((t) => url.endsWith(`_${t}.jpg`));
return teil ? Promise.resolve({ name: teil }) : Promise.reject(new Error(`404 ${url}`));
},
});
afterEach(() => { vi.restoreAllMocks(); });
it("nimmt eine Diffuse-Karte ohne Normal- und ARM-Karte an, statt einfarbig zu werden", async () => {
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
const material = await loadSet(fakeLoader(["Diffuse"]), "sidewalk", 0xd8d2c4);
expect(material.map).toMatchObject({ name: "Diffuse" });
expect(material.normalMap).toBeNull();
expect(material.aoMap).toBeNull();
expect(material.roughnessMap).toBeNull();
// Ohne ARM-Karte kommt die Rauheit aus dem Material selbst, nicht aus der Textur.
expect(material.roughness).toBe(0.9);
expect(warn).not.toHaveBeenCalled();
});
it("nimmt auch eine fehlende ARM-Karte allein hin, ohne die Normal-Map mitzureißen", async () => {
const material = await loadSet(fakeLoader(["Diffuse", "nor_gl"]), "sidewalk", 0xd8d2c4);
expect(material.normalMap).toMatchObject({ name: "nor_gl" });
expect(material.roughnessMap).toBeNull();
});
it("hängt den vollen Satz weiterhin vollständig ein", async () => {
const material = await loadSet(fakeLoader(["Diffuse", "nor_gl", "arm"]), "asphalt_02", 0x505050,
{ maxAnisotropy: 8 });
expect(material.map).toMatchObject({ name: "Diffuse", anisotropy: 8 });
expect(material.normalMap).toMatchObject({ name: "nor_gl", anisotropy: 8 });
expect(material.aoMap).toMatchObject({ name: "arm" });
expect(material.roughnessMap).toBe(material.aoMap);
});
it("fällt nur dann auf den einfarbigen Ersatz zurück, wenn die Diffuse-Karte fehlt", async () => {
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
const material = await loadSet(fakeLoader(["nor_gl", "arm"]), "fehlt", 0x123456);
expect(material.map).toBeNull();
expect(material.color.getHex()).toBe(0x123456);
expect(warn).toHaveBeenCalledTimes(1);
});
});