Files
anatomia/data-pipeline/scripts/build-seed-models.mjs
T

101 lines
2.8 KiB
JavaScript

import { Document, NodeIO } from "@gltf-transform/core";
import { readFileSync, mkdirSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { buildGeometry } from "./geometry.mjs";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const manifestPath = path.resolve(
__dirname,
process.argv[2] ?? "../seed/manifest-tegumentar.json",
);
const outDir = path.resolve(__dirname, "../seed/models");
mkdirSync(outDir, { recursive: true });
const { structures } = JSON.parse(readFileSync(manifestPath, "utf-8"));
function eulerToQuat([x, y, z]) {
const cx = Math.cos(x / 2), sx = Math.sin(x / 2);
const cy = Math.cos(y / 2), sy = Math.sin(y / 2);
const cz = Math.cos(z / 2), sz = Math.sin(z / 2);
return [
sx * cy * cz - cx * sy * sz,
cx * sy * cz + sx * cy * sz,
cx * cy * sz - sx * sy * cz,
cx * cy * cz + sx * sy * sz,
];
}
function hexToRgb(hex) {
const n = parseInt(hex.replace("#", ""), 16);
return [((n >> 16) & 255) / 255, ((n >> 8) & 255) / 255, (n & 255) / 255, 1];
}
const bySystem = new Map();
for (const s of structures) {
if (!bySystem.has(s.system)) bySystem.set(s.system, []);
bySystem.get(s.system).push(s);
}
const systemColors = {
esqueletico: "#e8e2d0",
muscular: "#b5433a",
nervoso: "#f2c14e",
cardiovascular: "#c1121f",
respiratorio: "#4f7cff",
tegumentar: "#e0a96d",
};
for (const [systemSlug, items] of bySystem) {
const doc = new Document();
const buffer = doc.createBuffer();
const scene = doc.createScene(systemSlug);
doc.getRoot().setDefaultScene(scene);
const material = doc
.createMaterial(systemSlug)
.setBaseColorFactor(hexToRgb(systemColors[systemSlug] ?? "#cccccc"))
.setRoughnessFactor(0.6)
.setMetallicFactor(0.05);
for (const item of items) {
const geo = buildGeometry(item.shape);
const posAccessor = doc
.createAccessor()
.setType("VEC3")
.setArray(geo.positions)
.setBuffer(buffer);
const normAccessor = doc
.createAccessor()
.setType("VEC3")
.setArray(geo.normals)
.setBuffer(buffer);
const idxAccessor = doc
.createAccessor()
.setType("SCALAR")
.setArray(geo.indices)
.setBuffer(buffer);
const prim = doc
.createPrimitive()
.setAttribute("POSITION", posAccessor)
.setAttribute("NORMAL", normAccessor)
.setIndices(idxAccessor)
.setMaterial(material);
const mesh = doc.createMesh(item.meshName).addPrimitive(prim);
const node = doc
.createNode(item.meshName)
.setMesh(mesh)
.setTranslation(item.position)
.setRotation(eulerToQuat(item.rotation ?? [0, 0, 0]));
scene.addChild(node);
}
const io = new NodeIO();
const outFile = path.join(outDir, `${systemSlug}.glb`);
await io.write(outFile, doc);
console.log(`✓ ${outFile} (${items.length} estruturas)`);
}