fix(world): quantisierte Positionen vor dem Kollisionsaufbau in Float32 wandeln

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Sonnet 5 committed 2026-09-14 12:42:25 +02:00
1 parent 9f6570b11d
commit 522101c026
3 files changed
+70 -3

No files matched your search

+24 -2
View File
@@ -1,6 +1,7 @@
// Orte: fest platzierte Modelle aus dem Editor three-d-stage, getrennt vom Chunk-Streaming
// (docs/superpowers/specs/2026-09-14-hood-yard-design.md). Aufbereitet werden sie mit
// tools/assets/places.mjs; hier stehen Lage, Laden und Kollision.
import { BufferAttribute } from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { MeshoptDecoder } from "three/examples/jsm/libs/meshopt_decoder.module.js";
import { worldToThree } from "./coords.js";
@@ -79,6 +80,23 @@ export function wantedPlaces(position, places, { show, hide, active }) {
return { add, remove };
}
// tools/assets/places.mjs komprimiert mit meshopt() (KHR_mesh_quantization): Positionen fester Meshes
// liegen als normalisierte Ganzzahlen vor, erst über die Mesh-Transform auf echte Maße skaliert.
// colliderBuild.ts im three-player-controller klont die Geometrie aber und rechnet matrixWorld per
// applyMatrix4 in die Kopie hinein — dabei würden normalisierte Werte beim Zurückschreiben auf ±1
// geklemmt. Deshalb hier vorher in echte, nicht normalisierte Float32-Koordinaten entquantisieren.
function dequantizePosition(geometry) {
const position = geometry.attributes.position;
if (!position.normalized && position.array instanceof Float32Array) return;
const values = new Float32Array(position.count * 3);
for (let i = 0; i < position.count; i++) {
values[i * 3] = position.getX(i);
values[i * 3 + 1] = position.getY(i);
values[i * 3 + 2] = position.getZ(i);
}
geometry.setAttribute("position", new BufferAttribute(values, 3));
}
/**
* Setzt Lage und Schatten und nimmt nicht feste Meshes aus der Kollision (colliderBuild.ts im
* three-player-controller überspringt userData.excludeFromCollider). Gibt zurück, ob ein Teil fest ist.
@@ -93,8 +111,12 @@ export function prepareModel(root, place) {
object.castShadow = true;
object.receiveShadow = true;
const materials = Array.isArray(object.material) ? object.material : [object.material];
if (materials.some((material) => isSolidMaterial(material?.name))) solid = true;
else object.userData.excludeFromCollider = true;
if (materials.some((material) => isSolidMaterial(material?.name))) {
solid = true;
dequantizePosition(object.geometry);
} else {
object.userData.excludeFromCollider = true;
}
});
root.updateMatrixWorld(true);
return solid;