diff --git a/src/world/materials.js b/src/world/materials.js index 43a5600..c937a83 100644 --- a/src/world/materials.js +++ b/src/world/materials.js @@ -17,10 +17,9 @@ export const TEXTURES = { carriageway: "asphalt_02", lots: "asphalt_02", // Parkplätze und Vorplätze: derselbe Asphalt wie die Fahrbahn curb: "curb", // modular_sidewalk_curb_kit (Just8, CC BY 4.0), s. tools/assets/textures.mjs - // Korrektur: sidewalk_Diffuse.jpg aus modular_sidewalk_curb_kit ist keine Betontextur, sondern - // das Platzhalterbild des Kits (roter Schriftzug "Tru-planar Sidewalk texture" auf dunklem - // Grund, im Browser geprüft) - das Kit taugt deshalb nur für den Bordstein. Derselbe Wert wie - // TEXTURES.paths, s. Entwurf Abschnitt "Die beiden Kits". + // Derselbe Wert wie TEXTURES.paths: helle Betonplatten in echter Größe. Die Kit-Textur schied + // aus, weil sidewalk_Diffuse.jpg kein Betonbild war, sondern das Platzhalterbild des Kits + // (roter Schriftzug "Tru-planar Sidewalk texture", im Browser geprüft). sidewalk: "concrete_pavement", // Ruling 56: eine Brücke ist in den Daten dasselbe Straßenstück, nur über Wasser — dieselbe // Textur wie die Fahrbahn, sonst zeigt jeder Straße-Brücke-Übergang eine Farbnaht. @@ -180,14 +179,32 @@ export async function loadSet(loader, slug, fallback, { tint, maxAnisotropy } = export const POLYGON_OFFSET_ORDER = ["ground", "urban", "park", "sand", "field", "court", "pool", "parking", "lots", "sidewalk", "paths"]; +// Nachtrag Teil 2, im Browser gemessen: Der Faktor ist der gefährliche Teil der Formel. Er wird mit +// der Tiefensteigung multipliziert, und die geht beim streifenden Blick über eine Bodenfläche gegen +// unendlich — ein Belag wird dann um ein Vielfaches seines nominellen Versatzes nach vorn gezogen. +// Mit einem Faktor je Rangstufe (Gehweg: -9) deckte der Gehwegbelag den 18 cm hohen Bordstein neben +// sich aus 18 m vollständig zu; von oben und aus zwei Metern war er zu sehen, beim flachen Blick die +// Straße entlang verschwand er. Genau der Fall, vor dem der Kommentar oben gewarnt hat. +// +// Deshalb ist die Stufenhöhe jetzt entkoppelt: Die Rangfolge steckt allein in den Units. Sie zählen +// in der kleinsten auflösbaren Tiefendifferenz, hängen nicht vom Blickwinkel ab und trennen +// koplanare Beläge auf jede Entfernung. Der Faktor ist für alle Beläge derselbe kleine Wert; er hält +// sie über der Bodenplatte (Faktor 0), ohne sie vor Geometrie zu ziehen, die daneben steht. +const DECAL_FACTOR = -1; +const DECAL_UNITS_STEP = 2; // zwei Einheiten je Stufe: Luft gegen Interpolationsrauschen + export const POLYGON_OFFSETS = { ...Object.fromEntries( POLYGON_OFFSET_ORDER.map((key, i) => [ key, - { polygonOffset: true, polygonOffsetFactor: -i, polygonOffsetUnits: -i }, + { + polygonOffset: true, + polygonOffsetFactor: i === 0 ? 0 : DECAL_FACTOR, + polygonOffsetUnits: i === 0 ? 0 : -i * DECAL_UNITS_STEP, + }, ]), ), - markings: { polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: -1 }, + markings: { polygonOffset: true, polygonOffsetFactor: DECAL_FACTOR, polygonOffsetUnits: -DECAL_UNITS_STEP }, }; /** Trägt POLYGON_OFFSETS in die passenden Materialien ein. Nur die benannten Schichten — diff --git a/tests/materials.test.js b/tests/materials.test.js index 2f40bb6..1c3f1e0 100644 --- a/tests/materials.test.js +++ b/tests/materials.test.js @@ -66,16 +66,27 @@ describe("Tiefenpuffer-Versatz je Schicht (gegen Flackern zwischen Boden/Stadt/P expect(new Set(sigs).size).toBe(sigs.length); }); - it("Betrag von Faktor und Units steigt streng von Boden zu Straße (Richtung Kamera)", () => { - const factors = POLYGON_OFFSET_ORDER.map((key) => POLYGON_OFFSETS[key].polygonOffsetFactor); + // Im Browser gemessen (Bordstein-Befund): Der Faktor wird mit der Tiefensteigung multipliziert, + // und die geht beim streifenden Blick über eine Bodenfläche gegen unendlich. Mit einem Faktor je + // Rangstufe zog der Gehwegbelag (-9) den 18 cm hohen Bordstein daneben aus 18 m vollständig zu; + // von oben und aus der Nähe war er da. Deshalb trägt die Rangfolge jetzt allein die Units. + it("trägt die Rangfolge in den Units, nicht im Faktor", () => { const units = POLYGON_OFFSET_ORDER.map((key) => POLYGON_OFFSETS[key].polygonOffsetUnits); - for (let i = 1; i < factors.length; i++) { + for (let i = 1; i < units.length; i++) { // Zunehmend negativ = zunehmend Richtung Kamera gezogen, s. Kommentar in materials.js. - expect(factors[i]).toBeLessThan(factors[i - 1]); - expect(units[i]).toBeLessThan(units[i - 1]); + expect(units[i], POLYGON_OFFSET_ORDER[i]).toBeLessThan(units[i - 1]); } }); + it("gibt allen Belägen denselben kleinen Faktor, nur die Bodenplatte bleibt bei null", () => { + const [boden, ...belaege] = POLYGON_OFFSET_ORDER; + expect(POLYGON_OFFSETS[boden].polygonOffsetFactor).toBe(0); + const faktoren = new Set(belaege.map((key) => POLYGON_OFFSETS[key].polygonOffsetFactor)); + expect([...faktoren]).toEqual([-1]); + // Die Markierung liegt außerhalb der Rangfolge, folgt aber derselben Regel. + expect(POLYGON_OFFSETS.markings.polygonOffsetFactor).toBe(-1); + }); + it("trägt den Versatz nur in Boden/Stadtfläche/Park/Strand/Straße ein — Brücken, Gebäude, " + "Wasser und Meeresboden bleiben unberührt (eigene Materialobjekte, s. Auftrag)", () => { const fake = Object.fromEntries( @@ -105,11 +116,11 @@ describe("Schichten aus Teil 2", () => { expect(MATERIAL_KEYS).not.toContain("roads"); }); - it("nimmt den Bordstein aus dem Kit, den Gehweg aus den Betonplatten von Poly Haven", () => { + it("nimmt Bordstein und Gehweg von Poly Haven, nicht mehr aus dem Kit", () => { // Korrektur: sidewalk_Diffuse.jpg aus dem Kit ist ein Platzhalterbild (roter Schriftzug), // keine Betontextur (im Browser geprüft) - der Gehweg benutzt deshalb denselben Belag wie // die Parkwege, nicht den Kit-Slug. - expect(TEXTURES.curb).toBe("curb"); + expect(TEXTURES.curb).toBe("brushed_concrete_04"); expect(TEXTURES.sidewalk).toBe("concrete_pavement"); expect(TEXTURES.sidewalk).toBe(TEXTURES.paths); expect(TEXTURES.carriageway).toBe("asphalt_02"); @@ -125,7 +136,10 @@ describe("Schichten aus Teil 2", () => { // Ihr einziger Nachbar ist die Fahrbahn 1 cm darunter, und die hat keinen Versatz. Die oberste // Stufe zöge sie beim streifenden Blick am weitesten nach vorn, ohne dass es etwas nützte. expect(POLYGON_OFFSET_ORDER).not.toContain("markings"); - expect(POLYGON_OFFSETS.markings).toEqual({ polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: -1 }); + expect(POLYGON_OFFSETS.markings).toEqual({ polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: -2 }); + // Eine Stufe wie der unterste Belag, nicht die oberste: Ihr Nachbar ist die Fahrbahn ohne Versatz. + expect(POLYGON_OFFSETS.markings.polygonOffsetUnits) + .toBe(POLYGON_OFFSETS[POLYGON_OFFSET_ORDER[1]].polygonOffsetUnits); // Fahrbahn und Bordstein liegen 15 cm tiefer und sind echte Geometrie — kein Versatz nötig. expect(POLYGON_OFFSETS.carriageway).toBeUndefined(); expect(POLYGON_OFFSETS.curb).toBeUndefined();