Files
2026-09-11 14:26:15 -04:00

39 lines
2.3 KiB
JavaScript

import { NodeIO } from "@gltf-transform/core";
import { ALL_EXTENSIONS } from "@gltf-transform/extensions";
import { MeshoptDecoder } from "meshoptimizer";
import { Matrix4, Vector3 } from "three";
import { writeFileSync, readdirSync } from "node:fs";
import catalog from "../../shared/arena-stages.json" with { type: "json" };
const io = new NodeIO().registerExtensions(ALL_EXTENSIONS).registerDependencies({ "meshopt.decoder": MeshoptDecoder });
const stages = {};
for (const stage of catalog.stages) {
stages[stage.id] = {};
for (const kind of ["navigation", "collision"]) {
const triangles = [];
const files = kind === "collision" ? readdirSync(`public${stage.assetBaseUrl}`).filter((name) => /^collision(?:-\d+)?\.glb$/.test(name)) : ["navigation.glb"];
for (const file of files) {
const document = await io.read(`public${stage.assetBaseUrl}/${file}`);
for (const node of document.getRoot().listNodes()) {
const mesh = node.getMesh();
if (!mesh) continue;
const matrix = new Matrix4().fromArray(node.getWorldMatrix());
for (const primitive of mesh.listPrimitives()) {
const positions = primitive.getAttribute("POSITION");
if (!positions) continue;
const indices = primitive.getIndices()?.getArray() ?? Array.from({ length: positions.getCount() }, (_, index) => index);
for (let offset = 0; offset < indices.length; offset += 3) {
const triangle = Array.from({ length: 3 }, (_, corner) => new Vector3().fromArray(positions.getElement(indices[offset + corner], [])).applyMatrix4(matrix).toArray());
if ([0, 2].some((axis) => triangle.every((point) => point[axis] < stage.bounds.min[axis] - 3) || triangle.every((point) => point[axis] > stage.bounds.max[axis] + 3))) continue;
triangles.push(...triangle.flat().map((value) => Math.round(value * 1000) / 1000));
}
}
}
}
stages[stage.id][kind] = triangles;
}
console.log(`${stage.id}: ${stages[stage.id].navigation.length / 9} navigation, ${stages[stage.id].collision.length / 9} collision triangles`);
}
writeFileSync("server/generated/arena-geometry.json", `${JSON.stringify(stages)}\n`);
writeFileSync("server/generated/arena-navigation.json", `${JSON.stringify(Object.fromEntries(Object.entries(stages).map(([id, stage]) => [id, stage.navigation])))}\n`);