fix(props): Straßenlaternen auf glaubwürdige Höhe skaliert, Fuß auf den Boden gehoben
street_lamp_02.glb ist nur 1,657 m hoch (per gltf-transform inspect gemessen:
bboxMax.y 1.26478 - bboxMin.y -0.39258) und ihr Fuß liegt unter dem Ursprung.
#buildLamps setzte das Modell bisher unskaliert auf y=0 — der Fuß steckt im Boden,
und 1,66 m ist ohnehin zu klein neben 10-18 m hohen Palmen und 10-28 m breiten
Straßen dieser Karte. Poly Havens eigene Angabe ("1.7m tall") bestätigt, dass die
Rohgröße korrekt gemessen ist — der Fehler liegt in der Verwendung dieser Rohgröße
in diesem Maßstab, nicht in der Messung selbst.
lampFit(minY, maxY, targetHeight) leitet Skalierung und Fuß-Anhebung aus der
gemessenen bbox her; STREET_LAMP_HEIGHT = 4.0 m als benannte Zielgröße (Mitte des
für dekorative Straßenlaternen üblichen 3-6-m-Bereichs). load() wendet beides auf
die Modellwurzel an, bevor die Teil-Matrizen (Mast, Glas) eingesammelt werden, damit
#buildLamps() unverändert bleiben kann.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b273bb09cc
commit
ad9bf63b36
2 files changed
+82
-5
No files matched your search
+39
-4
@@ -1,4 +1,4 @@
|
||||
import { CylinderGeometry, Group, InstancedMesh, Matrix4, Mesh, MeshStandardMaterial,
|
||||
import { Box3, CylinderGeometry, Group, InstancedMesh, Matrix4, Mesh, MeshStandardMaterial,
|
||||
Object3D, RepeatWrapping, SRGBColorSpace, TextureLoader } from "three";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
||||
import { MeshoptDecoder } from "three/examples/jsm/libs/meshopt_decoder.module.js";
|
||||
@@ -8,6 +8,31 @@ const PALM_MODEL_HEIGHT = 439.74; // Einheiten im OBJ, gemessen
|
||||
const TRUNK_RADIUS = 0.22;
|
||||
const LAMP_VERGE = [6, 8, 10, 12, 14, 16]; // Meter, von innen nach außen (Ruling 60)
|
||||
|
||||
// Befund B (Fix-Runde 3): street_lamp_02.glb ist mit `npx @gltf-transform/cli@4.5.0 inspect`
|
||||
// vermessen nur 1,65736 m hoch (bboxMax.y 1.26478 - bboxMin.y -0.39258) — Poly Haven selbst
|
||||
// nennt das Modell "1.7m tall" (https://polyhaven.com/a/street_lamp_02), die Messung bestätigt
|
||||
// also die Rohgröße des Assets. Zu klein ist sie trotzdem: dekorative Straßen-/Parklaternen
|
||||
// liegen real üblicherweise bei 3-6 m, und neben 10-18 m hohen Palmen (PALM_MODEL_HEIGHT-
|
||||
// Skalierung oben) und 10-28 m breiten Straßen dieser Karte wirkt 1,66 m spielzeughaft klein.
|
||||
// 4 m liegt mittig in diesem Bereich und ist mehr als das Doppelte der Rohgröße — eine
|
||||
// bewusste, keine zufällige Skalierung (anders als bei den Palmen: alle Laternen sind gleich
|
||||
// hoch, wie ein echtes Serienprodukt).
|
||||
export const STREET_LAMP_HEIGHT = 4.0; // Meter, Zielhöhe (benannte Konstante, s. Bericht)
|
||||
|
||||
/**
|
||||
* Skalierung und Y-Anhebung, damit ein Modell mit gemessener lokaler bbox [minY, maxY] genau
|
||||
* targetHeight hoch dasteht und sein tiefster Punkt (der Fuß, minY) nach der Skalierung exakt
|
||||
* auf y = 0 zu stehen kommt — unabhängig davon, ob der Modellursprung selbst am Fuß liegt.
|
||||
* street_lamp_02.glb liegt das nicht: bboxMin.y ist negativ, der Fuß also unter dem Ursprung
|
||||
* (Befund B) — ohne die Anhebung um |bboxMin.y| * scale stünde das skalierte Modell weiterhin
|
||||
* teilweise im Boden.
|
||||
*/
|
||||
export function lampFit(minY, maxY, targetHeight = STREET_LAMP_HEIGHT) {
|
||||
const modelHeight = maxY - minY;
|
||||
const scale = modelHeight > 0 ? targetHeight / modelHeight : 1;
|
||||
return { scale, liftY: -minY * scale };
|
||||
}
|
||||
|
||||
/** Kleiner, wiederholbarer Zufall aus einem Schlüssel. */
|
||||
function hashUnit(seed, key) {
|
||||
let h = 2166136261 ^ seed;
|
||||
@@ -126,6 +151,14 @@ export class PropLayer {
|
||||
// Referenzcode fehlte das.
|
||||
gltfLoader.setMeshoptDecoder(MeshoptDecoder);
|
||||
this.lamp = (await gltfLoader.loadAsync("./models/props/street_lamp_02.glb")).scene;
|
||||
// Befund B: Skalierung und Fuß-Anhebung auf die Modellwurzel anwenden, BEVOR unten die
|
||||
// Teil-Matrizen eingesammelt werden — jedes lampParts[i].matrix ist matrixWorld relativ
|
||||
// zu dieser Wurzel und bekommt scale/liftY dadurch automatisch mit; #buildLamps() selbst
|
||||
// bleibt unverändert (platziert weiterhin nur bei y = 0 auf dem Boden).
|
||||
const bbox = new Box3().setFromObject(this.lamp);
|
||||
const { scale, liftY } = lampFit(bbox.min.y, bbox.max.y);
|
||||
this.lamp.scale.setScalar(scale);
|
||||
this.lamp.position.y = liftY;
|
||||
// Anders als die einteilige Palme hat street_lamp_02.glb zwei Materialien — Metallmast
|
||||
// und durchsichtiges Laternenglas (glTF-Mesh "street_lamp_02_stem_mesh", primitives:
|
||||
// [material 1, material 0], per gltf-transform inspect nachgeprüft) — GLTFLoader baut
|
||||
@@ -187,9 +220,11 @@ export class PropLayer {
|
||||
|
||||
/**
|
||||
* Laternen entlang der Mittellinien (lampPoints), seitlich zur Fahrbahnkante versetzt
|
||||
* (vergeLampPoints, Ruling 60 — Fix-Runde 1; siehe dort für die Begründung). Das Modell
|
||||
* ist bei 1,7 m laut Poly-Haven-Angabe bereits maßstäblich, anders als die Palme also
|
||||
* keine Zufallsskalierung.
|
||||
* (vergeLampPoints, Ruling 60 — Fix-Runde 1; siehe dort für die Begründung). Skalierung
|
||||
* auf STREET_LAMP_HEIGHT und die Fuß-Anhebung stecken bereits in this.lampParts[*].matrix
|
||||
* (s. load(), Befund B / Fix-Runde 3) — hier wird jede Laterne nur noch bei y = 0 auf den
|
||||
* Boden gesetzt. Anders als bei der Palme keine Zufallsskalierung je Instanz: jede Laterne
|
||||
* ist gleich hoch, wie ein echtes Serienprodukt.
|
||||
*/
|
||||
#buildLamps(chunk, visual) {
|
||||
const centerlinePoints = lampPoints(chunk.centerlines ?? []);
|
||||
|
||||
Reference in new issue
Block a user