EmboDi / src /services /sample-actor.mjs
xlt99's picture
Upload 180 files
970fc3e verified
Raw History Blame Contribute Delete
3.91 kB
import * as THREE from "three";
import { createHash } from "node:crypto";
import { mkdir, writeFile, access } from "node:fs/promises";
import { join } from "node:path";
async function installSampleActor(directory) {
const folder = join(directory, "actor-assets", "sample-actor");
try {
await access(join(folder, "asset.json"));
return;
} catch {
}
const joints = [[0, 0.94, 0], [-0.11, 0.91, 0], [0.11, 0.91, 0], [0, 1.06, 0], [-0.11, 0.53, 0], [0.11, 0.53, 0], [0, 1.2, 0], [-0.11, 0.13, 0], [0.11, 0.13, 0], [0, 1.34, 0], [-0.11, 0.07, 0.13], [0.11, 0.07, 0.13], [0, 1.51, 0], [-0.09, 1.4, 0], [0.09, 1.4, 0], [0, 1.66, 0], [-0.21, 1.4, 0], [0.21, 1.4, 0], [-0.49, 1.4, 0], [0.49, 1.4, 0], [-0.72, 1.4, 0], [0.72, 1.4, 0], [-0.8, 1.4, 0], [0.8, 1.4, 0]].map(([x, y, z]) => [-x, y, z]);
const parents = [-1, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 12, 13, 14, 16, 17, 18, 19, 20, 21];
const names = ["pelvis", "left_hip", "right_hip", "spine1", "left_knee", "right_knee", "spine2", "left_ankle", "right_ankle", "spine3", "left_foot", "right_foot", "neck", "left_collar", "right_collar", "head", "left_shoulder", "right_shoulder", "left_elbow", "right_elbow", "left_wrist", "right_wrist", "left_hand", "right_hand"];
const vertices = [], faces = [], skinIndices = [], skinWeights = [];
function add(geometry, bone, position, quaternion = new THREE.Quaternion()) {
const g = geometry.toNonIndexed(), p = g.getAttribute("position"), v = new THREE.Vector3(), offset = vertices.length / 3;
for (let i = 0; i < p.count; i++) {
v.fromBufferAttribute(p, i).applyQuaternion(quaternion).add(position);
vertices.push(...v.toArray());
skinIndices.push(bone, 0, 0, 0);
skinWeights.push(1, 0, 0, 0);
faces.push(offset + i);
}
g.dispose();
geometry.dispose();
}
const point = (i) => new THREE.Vector3(...joints[i]);
const limb = (a, b, width) => {
const p = point(a), q = point(b), d = q.clone().sub(p);
add(new THREE.BoxGeometry(width, d.length(), width), a, p.clone().add(q).multiplyScalar(0.5), new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 1, 0), d.normalize()));
};
add(new THREE.BoxGeometry(0.29, 0.19, 0.19), 0, point(0));
for (const [a, b, w] of [[1, 4, 0.13], [2, 5, 0.13], [4, 7, 0.105], [5, 8, 0.105], [3, 6, 0.24], [6, 9, 0.27], [9, 12, 0.3], [12, 15, 0.09], [13, 16, 0.09], [14, 17, 0.09], [16, 18, 0.09], [17, 19, 0.09], [18, 20, 0.075], [19, 21, 0.075]]) limb(a, b, w);
for (const i of [10, 11]) add(new THREE.BoxGeometry(0.13, 0.14, 0.26), i, point(i));
for (const i of [22, 23]) add(new THREE.BoxGeometry(0.13, 0.075, 0.1), i, point(i));
add(new THREE.SphereGeometry(0.14, 10, 8), 15, point(15));
const template = { format: "vrbuild-humanoid24-template/1", coordinateSystem: "right-handed-y-up", vertices, faces, joints: joints.flat(), parents, jointNames: names, skinIndices, skinWeights };
const motion = { format: "vrbuild-humanoid24/1", coordinateSystem: "right-handed-y-up", jointCount: 24, frames: 1, fps: 30, quaternions: Array.from({ length: 24 }, () => [0, 0, 0, 1]).flat(), translations: [0, 0, 0], normalization: { origin: [0, 0, 0], yaw: 0 } };
const t = Buffer.from(JSON.stringify(template)), m = Buffer.from(JSON.stringify(motion)), hash = (b) => createHash("sha256").update(b).digest("hex");
const asset = { id: "sample-actor", name: "Mannequin", kind: "vrbuild-humanoid24", displayModel: "Procedural mannequin", defaultActor: true, preferred: true, bodyOnly: true, frames: 1, fps: 30, duration: 0, lastSample: 0, templateHash: hash(t), motionHash: hash(m), sourceFormat: "Original primitive geometry" };
await mkdir(folder, { recursive: true });
await writeFile(join(folder, "template.json"), t);
await writeFile(join(folder, "motion.json"), m);
await writeFile(join(folder, "asset.json"), JSON.stringify(asset));
}
export {
installSampleActor
};