Update Healer Man server
This commit is contained in:
1 parent
6114a2295f
commit
69809f7228
593 files changed
+903643
-40774
No files matched your search
@@ -0,0 +1,60 @@
|
||||
import { Document, NodeIO } from "@gltf-transform/core";
|
||||
import { Matrix4, Vector3 } from "three";
|
||||
import path from "node:path";
|
||||
import { mkdir } from "node:fs/promises";
|
||||
|
||||
/** Preserve world-space source triangles while bounding each physical GLB. */
|
||||
export async function writeBoundedCollisionGlbs(sourceFile, outputDirectory, slug, {
|
||||
maximumTriangles = 90_000,
|
||||
sourceSha256,
|
||||
} = {}) {
|
||||
if (!Number.isSafeInteger(maximumTriangles) || maximumTriangles < 1) {
|
||||
throw new Error("Collision chunk limit must be a positive integer.");
|
||||
}
|
||||
const io = new NodeIO();
|
||||
const source = await io.read(sourceFile);
|
||||
const scene = source.getRoot().getDefaultScene() ?? source.getRoot().listScenes()[0];
|
||||
if (!scene) throw new Error("Native collision source has no scene.");
|
||||
const positions = [];
|
||||
scene.traverse((node) => {
|
||||
const mesh = node.getMesh();
|
||||
if (!mesh) return;
|
||||
const matrix = new Matrix4().fromArray(node.getWorldMatrix());
|
||||
const reverse = matrix.determinant() < 0;
|
||||
for (const primitive of mesh.listPrimitives()) {
|
||||
if (primitive.getMode() !== 4) throw new Error("Collision must contain triangle primitives.");
|
||||
const position = primitive.getAttribute("POSITION");
|
||||
const index = primitive.getIndices();
|
||||
const count = index?.getCount() ?? position?.getCount() ?? 0;
|
||||
if (!position || count % 3) throw new Error("Invalid collision triangle positions.");
|
||||
for (let triangle = 0; triangle < count; triangle += 3) {
|
||||
for (const corner of reverse ? [0, 2, 1] : [0, 1, 2]) {
|
||||
const vertex = index ? index.getScalar(triangle + corner) : triangle + corner;
|
||||
const point = new Vector3(...position.getElement(vertex, [])).applyMatrix4(matrix);
|
||||
if (!point.toArray().every(Number.isFinite)) throw new Error("Non-finite collision coordinate.");
|
||||
positions.push(...point.toArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!positions.length) throw new Error("Native collision source is empty.");
|
||||
await mkdir(outputDirectory, { recursive: true });
|
||||
const records = [];
|
||||
for (let begin = 0; begin < positions.length; begin += maximumTriangles * 9) {
|
||||
const document = new Document();
|
||||
const buffer = document.createBuffer();
|
||||
const targetScene = document.createScene("native-options-and-source-supports");
|
||||
document.getRoot().setDefaultScene(targetScene);
|
||||
const array = new Float32Array(positions.slice(begin, begin + maximumTriangles * 9));
|
||||
const primitive = document.createPrimitive().setAttribute("POSITION", document.createAccessor("collision-positions", buffer).setType("VEC3").setArray(array));
|
||||
targetScene.addChild(document.createNode("collision").setMesh(document.createMesh().addPrimitive(primitive)));
|
||||
document.getRoot().setExtras({
|
||||
collisionMode: "respect-options", sourceCandidateSha256: sourceSha256 ?? null,
|
||||
triangleRange: [begin / 9, begin / 9 + array.length / 9],
|
||||
});
|
||||
const file = `${slug}-collision-${String(records.length).padStart(3, "0")}.glb`;
|
||||
await io.write(path.join(outputDirectory, file), document);
|
||||
records.push({ file, triangles: array.length / 9, nativeSerializedCollision: true, derivedSourceAnchorSupport: true });
|
||||
}
|
||||
return records;
|
||||
}
|
||||
Reference in new issue
Block a user