test(world): entquantisierte Positionen auch für interleaved Attribute

GLTFLoader liefert quantisierte Positionen in echt als
InterleavedBufferAttribute (gemeinsamer Puffer mit Normale/UV), nicht
als eigene BufferAttribute wie im bisherigen Test. dequantizePosition
braucht dafür keine Änderung: es liest nur über das gemeinsame
Attribut-Interface (normalized, getX/getY/getZ, count), das three.js
für beide Klassen implementiert. Der Test läuft grün und schreibt das
fest.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Sonnet 5 committed 2026-09-14 13:41:46 +02:00
1 parent 23a0623898
commit fc9e818c79
1 file changed
+32 -2
+32 -2
View File
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import { BoxGeometry, BufferAttribute, BufferGeometry, Group, Mesh, MeshStandardMaterial, Scene,
Vector3 } from "three";
import { BoxGeometry, BufferAttribute, BufferGeometry, Group, InterleavedBuffer,
InterleavedBufferAttribute, Mesh, MeshStandardMaterial, Scene, Vector3 } from "three";
import { PLACES, PlaceLayer, SOLID_MATERIALS, isSolidMaterial, placeTransform, prepareModel,
wantedPlaces } from "../src/world/places.js";
@@ -122,6 +122,36 @@ describe("prepareModel", () => {
expect(worldGeometry.boundingBox.max.z).toBeCloseTo(-1050.5);
});
// Bruch: GLTFLoader liefert quantisierte Positionen in echt als InterleavedBufferAttribute
// (gemeinsamer Puffer mit weiteren Attributen wie Normale und UV), nicht als eigene
// BufferAttribute — eine Entquantisierung, die nur den einfachen Fall abdeckt, ließe die echten
// Modelldaten quantisiert und der Hof kollidierte wie oben nahe dem Weltursprung.
it("entquantisiert feste Positionen auch als interleaved Attribut", () => {
const buffer = new InterleavedBuffer(
new Int16Array([-32767, 0, -32767, 0, 0, 0, 0, 0, 32767, 32767, 32767, 0, 0, 0, 0, 0]), 8);
const geometry = new BufferGeometry();
geometry.setAttribute("position", new InterleavedBufferAttribute(buffer, 3, 0, true));
const mesh = new Mesh(geometry, new MeshStandardMaterial({ name: "cont_a_side" }));
mesh.scale.setScalar(17);
const root = new Group();
root.add(mesh);
prepareModel(root, { at: [1489, 1067.5], rotation: 0, lift: -0.28 });
expect(mesh.geometry.attributes.position.array).toBeInstanceOf(Float32Array);
expect(mesh.geometry.attributes.position.normalized).toBe(false);
// Wie colliderBuild.ts: Geometrie klonen und die Weltmatrix hineinrechnen.
const worldGeometry = mesh.geometry.clone();
worldGeometry.applyMatrix4(mesh.matrixWorld);
worldGeometry.computeBoundingBox();
expect(worldGeometry.boundingBox.min.x).toBeCloseTo(1472);
expect(worldGeometry.boundingBox.max.x).toBeCloseTo(1506);
expect(worldGeometry.boundingBox.min.z).toBeCloseTo(-1084.5);
expect(worldGeometry.boundingBox.max.z).toBeCloseTo(-1050.5);
});
it("lässt eine durchlässige Position quantisiert", () => {
const geometry = new BufferGeometry();
const position = new BufferAttribute(new Int16Array([0, 0, 0, 32767, 32767, 32767]), 3, true);