three-usd-robot 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/{ThreeUsdRobot-lMZHW-it.d.ts → ThreeUsdRobot-C6uqpNZA.d.ts} +1 -1
- package/dist/{buildKinematicTree-2fg6ZN8m.d.ts → buildKinematicTree-BJuC_-5_.d.ts} +14 -1
- package/dist/{chunk-XCP5GZPY.js → chunk-XH3L7XDJ.js} +133 -46
- package/dist/chunk-XH3L7XDJ.js.map +1 -0
- package/dist/core.d.ts +11 -13
- package/dist/core.js +1 -1
- package/dist/extras.d.ts +2 -2
- package/dist/helpers.d.ts +2 -2
- package/dist/index.d.ts +30 -7
- package/dist/index.js +95 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-XCP5GZPY.js.map +0 -1
package/README.md
CHANGED
|
@@ -10,11 +10,13 @@ and drives forward kinematics on a Three.js `Object3D` hierarchy.
|
|
|
10
10
|
|
|
11
11
|
> 🚧 **Status: v0.2 + USDC.** Loads **ASCII `.usda`**, **binary `.usdc` / `.usd`
|
|
12
12
|
> (crate)**, and **`.usdz`** robots — including multi-file assets via
|
|
13
|
-
> references/payloads/sublayers
|
|
14
|
-
>
|
|
13
|
+
> references/payloads/sublayers, **variant selections**, and **instanceable**
|
|
14
|
+
> prims (internal-reference prototypes) — drives forward kinematics with meshes,
|
|
15
|
+
> applies flat **`UsdShade` material colors** (UsdPreviewSurface / OmniPBR
|
|
16
|
+
> constants), normalizes up-axis & units, and seeds the initial pose. The
|
|
15
17
|
> crate reader is a from-scratch TypeScript implementation (no OpenUSD/WASM
|
|
16
|
-
> dependency). Not yet:
|
|
17
|
-
>
|
|
18
|
+
> dependency). Not yet: variant resolution inside binary crate, and time-sampled
|
|
19
|
+
> (animated) values.
|
|
18
20
|
|
|
19
21
|
```ts
|
|
20
22
|
// .usda / .usdc / binary .usd / .usdz are all auto-detected:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
-
import {
|
|
2
|
+
import { J as JointType, A as Axis, a as JointDescription, L as LinkDescription, R as RobotDescription, K as KinematicTree } from './buildKinematicTree-BJuC_-5_.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The articulated "motion" node of a joint, inserted between the joint's two
|
|
@@ -80,9 +80,22 @@ type PrimSpec = {
|
|
|
80
80
|
metadata: MetadataMap;
|
|
81
81
|
properties: PropertySpec[];
|
|
82
82
|
children: PrimSpec[];
|
|
83
|
+
/** Authored variant sets (`variantSet "name" = { ... }`), if any. */
|
|
84
|
+
variantSets?: VariantSetMap;
|
|
83
85
|
/** 1-based source line of the prim declaration (for diagnostics). */
|
|
84
86
|
line: number;
|
|
85
87
|
};
|
|
88
|
+
/** The opinions a single variant contributes when selected. */
|
|
89
|
+
type VariantContent = {
|
|
90
|
+
properties: PropertySpec[];
|
|
91
|
+
children: PrimSpec[];
|
|
92
|
+
};
|
|
93
|
+
/** `variantSetName → variantName → content`. */
|
|
94
|
+
type VariantSetMap = {
|
|
95
|
+
[setName: string]: {
|
|
96
|
+
[variantName: string]: VariantContent;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
86
99
|
type PropertySpec = AttributeSpec | RelationshipSpec;
|
|
87
100
|
type AttributeSpec = {
|
|
88
101
|
kind: "attribute";
|
|
@@ -280,4 +293,4 @@ type BuildTreeOptions = {
|
|
|
280
293
|
};
|
|
281
294
|
declare function buildKinematicTree(robot: RobotDescription, options?: BuildTreeOptions): KinematicTree;
|
|
282
295
|
|
|
283
|
-
export { type Axis as A, type BuildTreeOptions as B, type CompositionArc as C, DEG2RAD as D, makeRotationZ as E, makeScale as F, makeTranslation as G, multiply as H, multiplyAll as I, type
|
|
296
|
+
export { type Axis as A, type BuildTreeOptions as B, type CompositionArc as C, DEG2RAD as D, makeRotationZ as E, makeScale as F, makeTranslation as G, multiply as H, multiplyAll as I, type JointType as J, type KinematicTree as K, type LinkDescription as L, type Mat4 as M, type PrimSpec as P, Quat as Q, type RobotDescription as R, type SdfPath as S, type TreeEdge as T, type UsdDictionary as U, type Vec3 as V, type JointDescription as a, AssetPath as b, type AttributeSpec as c, type JointDriveDescription as d, type KinematicNode as e, type ListOp as f, type MetadataMap as g, type PropertySpec as h, RAD2DEG as i, type RelationshipSpec as j, type Specifier as k, UsdMatrix as l, type UsdValue as m, type UsdaFile as n, type Variability as o, type Vec2 as p, type Vec4 as q, buildKinematicTree as r, fromUsdMatrix as s, getTranslation as t, identity4 as u, invert as v, makeEuler as w, makeRotationFromQuat as x, makeRotationX as y, makeRotationY as z };
|
|
@@ -507,26 +507,54 @@ function parsePrim(r) {
|
|
|
507
507
|
if (r.is("ident")) typeName = r.expectIdent();
|
|
508
508
|
const name = r.expect("string").value;
|
|
509
509
|
const metadata = r.is("lparen") ? parseMetadataBlock(r) : {};
|
|
510
|
+
r.expect("lbrace");
|
|
511
|
+
const body = parseBody(r);
|
|
512
|
+
r.expect("rbrace");
|
|
513
|
+
const prim = {
|
|
514
|
+
specifier,
|
|
515
|
+
typeName,
|
|
516
|
+
name,
|
|
517
|
+
metadata,
|
|
518
|
+
properties: body.properties,
|
|
519
|
+
children: body.children,
|
|
520
|
+
line: head.line
|
|
521
|
+
};
|
|
522
|
+
if (body.variantSets) prim.variantSets = body.variantSets;
|
|
523
|
+
return prim;
|
|
524
|
+
}
|
|
525
|
+
function parseBody(r) {
|
|
510
526
|
const properties = [];
|
|
511
527
|
const children = [];
|
|
512
|
-
|
|
528
|
+
let variantSets;
|
|
513
529
|
while (!r.is("rbrace") && !r.atEnd()) {
|
|
514
530
|
if (r.is("ident") && SPECIFIERS.has(r.peek().value)) {
|
|
515
531
|
children.push(parsePrim(r));
|
|
532
|
+
} else if (r.isIdent("variantSet")) {
|
|
533
|
+
const { setName, variants } = parseVariantSet(r);
|
|
534
|
+
variantSets ??= {};
|
|
535
|
+
variantSets[setName] = variants;
|
|
516
536
|
} else {
|
|
517
537
|
properties.push(parseProperty(r));
|
|
518
538
|
}
|
|
519
539
|
}
|
|
540
|
+
return variantSets ? { properties, children, variantSets } : { properties, children };
|
|
541
|
+
}
|
|
542
|
+
function parseVariantSet(r) {
|
|
543
|
+
r.expectIdent();
|
|
544
|
+
const setName = r.expect("string").value;
|
|
545
|
+
r.expect("equals");
|
|
546
|
+
r.expect("lbrace");
|
|
547
|
+
const variants = {};
|
|
548
|
+
while (!r.is("rbrace") && !r.atEnd()) {
|
|
549
|
+
const variantName = r.expect("string").value;
|
|
550
|
+
if (r.is("lparen")) parseMetadataBlock(r);
|
|
551
|
+
r.expect("lbrace");
|
|
552
|
+
const body = parseBody(r);
|
|
553
|
+
r.expect("rbrace");
|
|
554
|
+
variants[variantName] = { properties: body.properties, children: body.children };
|
|
555
|
+
}
|
|
520
556
|
r.expect("rbrace");
|
|
521
|
-
return {
|
|
522
|
-
specifier,
|
|
523
|
-
typeName,
|
|
524
|
-
name,
|
|
525
|
-
metadata,
|
|
526
|
-
properties,
|
|
527
|
-
children,
|
|
528
|
-
line: head.line
|
|
529
|
-
};
|
|
557
|
+
return { setName, variants };
|
|
530
558
|
}
|
|
531
559
|
function parseProperty(r) {
|
|
532
560
|
const line = r.peek().line;
|
|
@@ -652,6 +680,10 @@ function parseMetadataValue(r) {
|
|
|
652
680
|
if (raw.t === "asset") {
|
|
653
681
|
return raw.v;
|
|
654
682
|
}
|
|
683
|
+
if (raw.t === "path") {
|
|
684
|
+
const arc = { primPath: raw.v };
|
|
685
|
+
return arc;
|
|
686
|
+
}
|
|
655
687
|
return rawToUsdValue(raw);
|
|
656
688
|
}
|
|
657
689
|
function parseMetadataList(r) {
|
|
@@ -666,6 +698,9 @@ function parseMetadataList(r) {
|
|
|
666
698
|
} else {
|
|
667
699
|
items.push(assetPath);
|
|
668
700
|
}
|
|
701
|
+
} else if (r.is("path")) {
|
|
702
|
+
const arc = { primPath: r.next().value };
|
|
703
|
+
items.push(arc);
|
|
669
704
|
} else {
|
|
670
705
|
items.push(rawToUsdValue(parseLiteral(r)));
|
|
671
706
|
}
|
|
@@ -1056,7 +1091,8 @@ function normalizePosix(path) {
|
|
|
1056
1091
|
}
|
|
1057
1092
|
|
|
1058
1093
|
// src/usd/composition.ts
|
|
1059
|
-
var ARC_KEYS = ["references", "payload", "payloads"];
|
|
1094
|
+
var ARC_KEYS = ["references", "payload", "payloads", "inherits", "specializes"];
|
|
1095
|
+
var STRIP_KEYS = [...ARC_KEYS, "variants", "variantSets"];
|
|
1060
1096
|
async function composeLayer(text, baseUrl, resolver, options = {}, stack = /* @__PURE__ */ new Set()) {
|
|
1061
1097
|
const warn = options.onWarn ?? (() => {
|
|
1062
1098
|
});
|
|
@@ -1064,47 +1100,89 @@ async function composeLayer(text, baseUrl, resolver, options = {}, stack = /* @_
|
|
|
1064
1100
|
let weak = [];
|
|
1065
1101
|
const subLayers = toArcs(file.metadata.subLayers);
|
|
1066
1102
|
for (let i = subLayers.length - 1; i >= 0; i--) {
|
|
1067
|
-
const sub = await
|
|
1103
|
+
const sub = await loadExternalFile(subLayers[i], baseUrl, resolver, options, stack, warn);
|
|
1068
1104
|
if (sub) weak = mergePrimLists(weak, sub.prims);
|
|
1069
1105
|
}
|
|
1106
|
+
const ctx = {
|
|
1107
|
+
baseUrl,
|
|
1108
|
+
resolver,
|
|
1109
|
+
options,
|
|
1110
|
+
warn,
|
|
1111
|
+
stack,
|
|
1112
|
+
index: buildPathIndex(file.prims),
|
|
1113
|
+
resolving: /* @__PURE__ */ new Set()
|
|
1114
|
+
};
|
|
1070
1115
|
const resolved = [];
|
|
1071
|
-
for (const prim of file.prims)
|
|
1072
|
-
resolved.push(await resolvePrimArcs(prim, baseUrl, resolver, options, stack, warn));
|
|
1073
|
-
}
|
|
1116
|
+
for (const prim of file.prims) resolved.push(await resolvePrim(prim, ctx));
|
|
1074
1117
|
const prims = weak.length > 0 ? mergePrimLists(weak, resolved) : resolved;
|
|
1075
|
-
return { version: file.version, metadata: stripKeys(file.metadata,
|
|
1076
|
-
}
|
|
1077
|
-
async function
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1118
|
+
return { version: file.version, metadata: stripKeys(file.metadata, STRIP_KEYS), prims };
|
|
1119
|
+
}
|
|
1120
|
+
async function resolvePrim(spec, ctx) {
|
|
1121
|
+
let properties = spec.properties;
|
|
1122
|
+
let children = spec.children;
|
|
1123
|
+
const selection = spec.metadata.variants;
|
|
1124
|
+
if (spec.variantSets && isDictionary(selection)) {
|
|
1125
|
+
for (const [setName, variantName] of Object.entries(selection)) {
|
|
1126
|
+
const variant = spec.variantSets[setName]?.[String(variantName)];
|
|
1127
|
+
if (!variant) continue;
|
|
1128
|
+
properties = mergeProperties(variant.properties, properties);
|
|
1129
|
+
children = mergePrimLists(variant.children, children);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
const resolvedChildren = [];
|
|
1133
|
+
for (const child of children) resolvedChildren.push(await resolvePrim(child, ctx));
|
|
1134
|
+
const local = {
|
|
1135
|
+
specifier: spec.specifier,
|
|
1136
|
+
typeName: spec.typeName,
|
|
1137
|
+
name: spec.name,
|
|
1138
|
+
metadata: stripKeys(spec.metadata, STRIP_KEYS),
|
|
1139
|
+
properties,
|
|
1140
|
+
children: resolvedChildren,
|
|
1141
|
+
line: spec.line
|
|
1142
|
+
};
|
|
1083
1143
|
const arcs = ARC_KEYS.flatMap((k) => toArcs(spec.metadata[k]));
|
|
1084
|
-
if (arcs.length === 0) return local;
|
|
1085
1144
|
let base = null;
|
|
1086
1145
|
for (const arc of arcs) {
|
|
1087
|
-
const target = await loadReferencedPrim(arc,
|
|
1088
|
-
if (
|
|
1089
|
-
base = base ? mergePrim(target, base) : target;
|
|
1146
|
+
const target = await loadReferencedPrim(arc, ctx);
|
|
1147
|
+
if (target) base = base ? mergePrim(target, base) : target;
|
|
1090
1148
|
}
|
|
1091
1149
|
return base ? mergePrim(base, local) : local;
|
|
1092
1150
|
}
|
|
1093
|
-
async function loadReferencedPrim(arc,
|
|
1094
|
-
if (
|
|
1095
|
-
|
|
1096
|
-
|
|
1151
|
+
async function loadReferencedPrim(arc, ctx) {
|
|
1152
|
+
if (arc.assetPath) {
|
|
1153
|
+
const composed = await loadExternalFile(
|
|
1154
|
+
arc,
|
|
1155
|
+
ctx.baseUrl,
|
|
1156
|
+
ctx.resolver,
|
|
1157
|
+
ctx.options,
|
|
1158
|
+
ctx.stack,
|
|
1159
|
+
ctx.warn
|
|
1160
|
+
);
|
|
1161
|
+
if (!composed) return null;
|
|
1162
|
+
const target = arc.primPath ? findPrimByPath(composed, arc.primPath) : defaultPrim(composed, ctx.warn);
|
|
1163
|
+
if (!target) {
|
|
1164
|
+
ctx.warn(
|
|
1165
|
+
`reference target ${arc.primPath ?? "(defaultPrim)"} not found in ${arc.assetPath.path}`
|
|
1166
|
+
);
|
|
1167
|
+
return null;
|
|
1168
|
+
}
|
|
1169
|
+
return target;
|
|
1097
1170
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1171
|
+
if (arc.primPath) {
|
|
1172
|
+
if (ctx.resolving.has(arc.primPath)) {
|
|
1173
|
+
ctx.warn(`internal composition cycle at ${arc.primPath}; skipping`);
|
|
1174
|
+
return null;
|
|
1175
|
+
}
|
|
1176
|
+
const target = ctx.index.get(arc.primPath);
|
|
1177
|
+
if (!target) {
|
|
1178
|
+
ctx.warn(`internal reference target ${arc.primPath} not found`);
|
|
1179
|
+
return null;
|
|
1180
|
+
}
|
|
1181
|
+
return resolvePrim(target, { ...ctx, resolving: /* @__PURE__ */ new Set([...ctx.resolving, arc.primPath]) });
|
|
1104
1182
|
}
|
|
1105
|
-
return
|
|
1183
|
+
return null;
|
|
1106
1184
|
}
|
|
1107
|
-
async function
|
|
1185
|
+
async function loadExternalFile(arc, baseUrl, resolver, options, stack, warn) {
|
|
1108
1186
|
if (!arc.assetPath) return null;
|
|
1109
1187
|
const url = resolver.resolve(arc.assetPath.path, baseUrl);
|
|
1110
1188
|
if (stack.has(url)) {
|
|
@@ -1126,7 +1204,6 @@ async function loadComposedFile(arc, baseUrl, resolver, options, stack, warn) {
|
|
|
1126
1204
|
}
|
|
1127
1205
|
function mergePrim(base, over) {
|
|
1128
1206
|
return {
|
|
1129
|
-
// `over` (def) wins; a pure `over` opinion keeps the base's specifier.
|
|
1130
1207
|
specifier: over.specifier === "over" ? base.specifier : over.specifier,
|
|
1131
1208
|
typeName: over.typeName || base.typeName,
|
|
1132
1209
|
name: over.name,
|
|
@@ -1196,6 +1273,14 @@ function mergeMetadata(base, over) {
|
|
|
1196
1273
|
}
|
|
1197
1274
|
return merged;
|
|
1198
1275
|
}
|
|
1276
|
+
function buildPathIndex(prims, parent = "/", map = /* @__PURE__ */ new Map()) {
|
|
1277
|
+
for (const p of prims) {
|
|
1278
|
+
const path = parent === "/" ? `/${p.name}` : `${parent}/${p.name}`;
|
|
1279
|
+
map.set(path, p);
|
|
1280
|
+
buildPathIndex(p.children, path, map);
|
|
1281
|
+
}
|
|
1282
|
+
return map;
|
|
1283
|
+
}
|
|
1199
1284
|
function findPrimByPath(file, path) {
|
|
1200
1285
|
const segments = path.split("/").filter(Boolean);
|
|
1201
1286
|
let level = file.prims;
|
|
@@ -1209,9 +1294,7 @@ function findPrimByPath(file, path) {
|
|
|
1209
1294
|
}
|
|
1210
1295
|
function defaultPrim(file, warn) {
|
|
1211
1296
|
const name = file.metadata.defaultPrim;
|
|
1212
|
-
if (typeof name === "string")
|
|
1213
|
-
return file.prims.find((p) => p.name === name) ?? null;
|
|
1214
|
-
}
|
|
1297
|
+
if (typeof name === "string") return file.prims.find((p) => p.name === name) ?? null;
|
|
1215
1298
|
const first = file.prims[0];
|
|
1216
1299
|
if (first) warn(`referenced layer has no defaultPrim; using first root prim "${first.name}"`);
|
|
1217
1300
|
return first ?? null;
|
|
@@ -1222,10 +1305,14 @@ function toArcs(value) {
|
|
|
1222
1305
|
const arcs = [];
|
|
1223
1306
|
for (const v of list) {
|
|
1224
1307
|
if (v instanceof AssetPath) arcs.push({ assetPath: v });
|
|
1225
|
-
else if (v && typeof v === "object" && "assetPath" in v
|
|
1308
|
+
else if (v && typeof v === "object" && ("assetPath" in v || "primPath" in v))
|
|
1309
|
+
arcs.push(v);
|
|
1226
1310
|
}
|
|
1227
1311
|
return arcs;
|
|
1228
1312
|
}
|
|
1313
|
+
function isDictionary(v) {
|
|
1314
|
+
return typeof v === "object" && v !== null && !Array.isArray(v) && !(v instanceof Quat) && !(v instanceof UsdMatrix) && !(v instanceof AssetPath);
|
|
1315
|
+
}
|
|
1229
1316
|
function stripKeys(meta, keys) {
|
|
1230
1317
|
const out = {};
|
|
1231
1318
|
for (const [k, v] of Object.entries(meta)) {
|
|
@@ -2681,5 +2768,5 @@ function leafName(path) {
|
|
|
2681
2768
|
}
|
|
2682
2769
|
|
|
2683
2770
|
export { ARTICULATION_ROOT_API, AssetPath, Attribute, COLLISION_API, CrateReader, DEFAULT_METERS_PER_UNIT, DEG2RAD, DefaultAssetResolver, Layer, PACKAGE_NAME, ParseError, Prim, Quat, RAD2DEG, RIGID_BODY_API, Relationship, Stage, TokenizeError, UsdMatrix, VERSION, buildKinematicTree, composeLayer, computeLocalTransform, crateToUsdaFile, createMemoryResolver, driveKindFor, extractRobotDescription, fromUsdMatrix, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, getTranslation, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, identity4, invert, isMesh, isScope, isXform, iterDescendants, joinPosix, jointValueToSI, makeEuler, makeRotationFromQuat, makeRotationX, makeRotationY, makeRotationZ, makeScale, makeTranslation, multiply, multiplyAll, normalizeJointLimits, openUsdz, parseOpType, parseUsda, refineJointType, tokenize };
|
|
2684
|
-
//# sourceMappingURL=chunk-
|
|
2685
|
-
//# sourceMappingURL=chunk-
|
|
2771
|
+
//# sourceMappingURL=chunk-XH3L7XDJ.js.map
|
|
2772
|
+
//# sourceMappingURL=chunk-XH3L7XDJ.js.map
|