39 lines
2.3 KiB
JavaScript
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`);
|