File size: 2,931 Bytes
0dfa89f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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));});