openusd-explorer / tests /engine.test.mjs
ZIP Space Deployer
Deploy ZIP — 2026-10-26 20:15 UTC
0dfa89f
Raw History Blame Contribute Delete
2.93 kB
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import init, {UsdLoader} from '../public/vendor/usd-reader/wasm/usd_wasm.js';
import {composeStage,readGeometries} from '../public/vendor/usd-reader/esm/load-core.js';
import {rootLayerText,physicsResult,ROOT_KEY,ROOT_LAYER,LOCAL} from '../src/vendor/web-usd.js';
import {bodyMatrices,jointProgress,controllableJoints} from '../src/vendor/kinematics.js';
const samples = JSON.parse(await fs.readFile(new URL('../public/samples.json',import.meta.url)));
await init({module_or_path:await fs.readFile(new URL('../public/vendor/usd-reader/wasm/usd_wasm_bg.wasm',import.meta.url))});
const results=[];
for (const sample of samples) {
test(`USD + articulation: ${sample.name}`, async () => {
const base=new URL(`../.cache/samples/${sample.id}/`,import.meta.url);
const source=JSON.parse(await fs.readFile(new URL('articulation.json',base)));
const bytes=new Uint8Array(await fs.readFile(new URL('asset.usdc',base)));
const files = new Map([[LOCAL+ROOT_KEY,new TextEncoder().encode(rootLayerText(1))],[LOCAL+ROOT_LAYER,bytes]]);
const {scene,meta,stats}=await composeStage({UsdLoader,rootUrl:LOCAL+ROOT_KEY,fetchBytes:async url=>files.get(url)??null,physics:['simready']});
let vertices=0,triangles=0;
readGeometries(scene,meta,(_index,_meta,arrays)=>{if(arrays){vertices+=arrays.positions.length/3;triangles+=arrays.indices.length/3;}});
assert(vertices>0,'real geometry is present');
const result=physicsResult(true,meta,[],[],{colliders:'skip'});
assert(result.articulation,JSON.stringify(result.info));
const art=result.articulation;
assert.equal(controllableJoints(art).length,controllableJoints(source).length);
let checks=0,maxError=0;
for(const fixture of source.selftest??[]) {
const joint=art.joints.find(j=>j.id===fixture.joint);
assert(joint);
const matrices=bodyMatrices(art,{[joint.id]:jointProgress(joint,fixture.value)});
for(const [body,expected] of Object.entries(fixture.deltas)) {
assert(matrices[body]);
for(let i=0;i<16;i++){const error=Math.abs(matrices[body][i]-expected[i]);maxError=Math.max(maxError,error);assert(error<2e-5,`${body}[${i}]: error ${error}`);checks++;}
}
}
for(const t of [0,0.25,0.5,0.75,1]) {
const matrices=bodyMatrices(art,Object.fromEntries(controllableJoints(art).map(j=>[j.id,t])));
assert(Object.values(matrices).flat().every(Number.isFinite));
}
scene.free();
results.push({name:sample.name,vertices,triangles,bodies:art.bodies.length,joints:controllableJoints(art).length,referenceMatrixChecks:checks,maxError,warnings:stats.warnings});
});
}
test.after(async()=>{await fs.mkdir(new URL('../reports/',import.meta.url),{recursive:true});await fs.writeFile(new URL('../reports/engine.json',import.meta.url),JSON.stringify(results,null,2));});