three-usd-robot 0.2.0 → 0.4.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/dist/core.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { n as UsdaFile, g as MetadataMap, m as UsdValue, P as PrimSpec, k as Specifier, j as RelationshipSpec, S as SdfPath, b as AttributeSpec, V as Variability, M as Mat4, R as RobotDescription, d as JointType, A as Axis } from './buildKinematicTree-2fg6ZN8m.js';
2
- export { a as AssetPath, B as BuildTreeOptions, C as CompositionArc, D as DEG2RAD, J as JointDescription, c as JointDriveDescription, K as KinematicNode, e as KinematicTree, L as LinkDescription, f as ListOp, h as PropertySpec, Q as Quat, i as RAD2DEG, T as TreeEdge, U as UsdDictionary, l as UsdMatrix, o as Vec2, p as Vec3, q as Vec4, r as buildKinematicTree, s as fromUsdMatrix, t as getTranslation, u as identity4, v as invert, w as makeEuler, x as makeRotationFromQuat, y as makeRotationX, z as makeRotationY, E as makeRotationZ, F as makeScale, G as makeTranslation, H as multiply, I as multiplyAll } from './buildKinematicTree-2fg6ZN8m.js';
1
+ import { o as UsdaFile, g as MetadataMap, n as UsdValue, P as PrimSpec, l as Specifier, j as RelationshipSpec, k as SdfPath, c as AttributeSpec, p as Variability, M as Mat4, R as RobotDescription, J as JointType, A as Axis } from './buildKinematicTree-CZjBMA1I.js';
2
+ export { b as AssetPath, B as BuildTreeOptions, C as CompositionArc, D as DEG2RAD, a as JointDescription, d as JointDriveDescription, e as KinematicNode, K as KinematicTree, L as LinkDescription, f as ListOp, h as PropertySpec, Q as Quat, i as RAD2DEG, S as SampleChannel, T as TreeEdge, U as UsdDictionary, m as UsdMatrix, q as Vec2, V as Vec3, r as Vec4, s as buildKinematicTree, t as channelFromSamples, u as fromUsdMatrix, v as getTranslation, w as identity4, x as interpolate, y as invert, z as makeEuler, E as makeRotationFromQuat, F as makeRotationX, G as makeRotationY, H as makeRotationZ, I as makeScale, N as makeTranslation, O as multiply, W as multiplyAll } from './buildKinematicTree-CZjBMA1I.js';
3
3
 
4
4
  /** Package identity. Kept in one place so every entry point can re-export it. */
5
5
  declare const PACKAGE_NAME = "three-usd-robot";
@@ -90,6 +90,12 @@ declare class Stage {
90
90
  GetUpAxis(): UpAxis;
91
91
  /** Stage linear unit (`metersPerUnit` metadata); defaults to {@link DEFAULT_METERS_PER_UNIT}. */
92
92
  GetMetersPerUnit(): number;
93
+ /** Animation start time code, if authored. */
94
+ GetStartTimeCode(): number | undefined;
95
+ /** Animation end time code, if authored. */
96
+ GetEndTimeCode(): number | undefined;
97
+ /** Time codes per second for playback; defaults to 24. */
98
+ GetTimeCodesPerSecond(): number;
93
99
  }
94
100
 
95
101
  /**
@@ -211,19 +217,25 @@ declare class DefaultAssetResolver implements AssetResolver {
211
217
  fetchText(url: string): Promise<string>;
212
218
  fetchBytes(url: string): Promise<Uint8Array>;
213
219
  }
214
- /** Resolver over an in-memory `{ path: contents }` map, with posix-style joins. */
215
- declare function createMemoryResolver(files: Record<string, string>): AssetResolver;
220
+ /**
221
+ * Resolver over an in-memory `{ path: contents }` map (text or bytes), with
222
+ * posix-style joins. Useful for tests and bundled assets.
223
+ */
224
+ declare function createMemoryResolver(files: Record<string, string | Uint8Array>): AssetResolver;
216
225
  /** Resolve `rel` against `baseUrl` using posix semantics, normalizing `.`/`..`. */
217
226
  declare function joinPosix(baseUrl: string, rel: string): string;
218
227
 
219
228
  /**
220
- * Minimal USD composition: flattens references, payloads and sublayers into a
221
- * single {@link UsdaFile} so the rest of the pipeline keeps working on one layer.
229
+ * Minimal USD composition: flattens references, payloads, sublayers, variant
230
+ * selections, and internal (intra-layer) reference/inherit arcs into a single
231
+ * {@link UsdaFile} so the rest of the pipeline keeps working on one layer.
222
232
  *
223
- * Scope (M8): the arcs robots actually use. References and payloads pull a prim
224
- * subtree from another asset (weaker than local opinions); sublayers overlay a
225
- * weaker layer stack. Inherits / variants / specializes are out of scope (M10).
226
- * This is not a full LIVRPS implementation it is a pragmatic flattener.
233
+ * Scope: the arcs robots actually use. References/payloads/inherits pull a prim
234
+ * subtree (weaker than local opinions); a `variants` selection grafts the chosen
235
+ * variant's content; internal arcs (`</Path>` with no asset) resolve within the
236
+ * same layer which is what `instanceable` prims use to pull a prototype.
237
+ * Specializes ordering and live instancing are approximated. Not a full LIVRPS
238
+ * engine — a pragmatic flattener.
227
239
  */
228
240
 
229
241
  type ComposeOptions = {
@@ -231,12 +243,10 @@ type ComposeOptions = {
231
243
  /** Guard against pathological recursion (default 64). */
232
244
  maxDepth?: number;
233
245
  };
234
- /**
235
- * Parse and fully compose a layer: resolve its sublayers and every prim's
236
- * references/payloads (recursively), returning a flattened layer. Unresolvable
237
- * arcs are reported via `onWarn` and skipped.
238
- */
246
+ /** Parse USDA text and fully compose it. */
239
247
  declare function composeLayer(text: string, baseUrl: string, resolver: AssetResolver, options?: ComposeOptions, stack?: ReadonlySet<string>): Promise<UsdaFile>;
248
+ /** Compose an already-parsed layer (used by the binary-crate path too). */
249
+ declare function composeFile(file: UsdaFile, baseUrl: string, resolver: AssetResolver, options?: ComposeOptions, stack?: ReadonlySet<string>): Promise<UsdaFile>;
240
250
 
241
251
  /**
242
252
  * USDZ (zipped USD package) support.
@@ -333,6 +343,12 @@ declare class CrateReader {
333
343
  private readIndexVector;
334
344
  /** Read an SdfListOp; returns the effective (explicit ∪ prepended ∪ added ∪ appended) items. */
335
345
  private readListOp;
346
+ /**
347
+ * Read a Reference/Payload list-op into composition arcs. Each item is
348
+ * `[assetPath: string-index][primPath: path-index][layerOffset: 2 doubles]`,
349
+ * and a Reference additionally carries a (usually empty) customData dict.
350
+ */
351
+ private readArcListOp;
336
352
  }
337
353
 
338
354
  /**
@@ -461,4 +477,4 @@ declare function getJointDrive(prim: Prim, kind: "angular" | "linear"): {
461
477
  /** Read `PhysicsJointStateAPI` position for the given instance, as authored. */
462
478
  declare function getJointStatePosition(prim: Prim, kind: "angular" | "linear"): number | undefined;
463
479
 
464
- export { ARTICULATION_ROOT_API, type AssetResolver, Attribute, AttributeSpec, Axis, COLLISION_API, type ComposeOptions, CrateReader, DEFAULT_METERS_PER_UNIT, DefaultAssetResolver, type ExtractOptions, JointType, Layer, Mat4, MetadataMap, PACKAGE_NAME, ParseError, Prim, PrimSpec, RIGID_BODY_API, Relationship, RelationshipSpec, type ResolvedXform, RobotDescription, SdfPath, Specifier, Stage, TokenizeError, type UpAxis, UsdValue, UsdaFile, type UsdzPackage, VERSION, Variability, composeLayer, computeLocalTransform, crateToUsdaFile, createMemoryResolver, driveKindFor, extractRobotDescription, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, isMesh, isScope, isXform, iterDescendants, joinPosix, jointValueToSI, normalizeJointLimits, openUsdz, parseOpType, parseUsda, refineJointType, tokenize };
480
+ export { ARTICULATION_ROOT_API, type AssetResolver, Attribute, AttributeSpec, Axis, COLLISION_API, type ComposeOptions, CrateReader, DEFAULT_METERS_PER_UNIT, DefaultAssetResolver, type ExtractOptions, JointType, Layer, Mat4, MetadataMap, PACKAGE_NAME, ParseError, Prim, PrimSpec, RIGID_BODY_API, Relationship, RelationshipSpec, type ResolvedXform, RobotDescription, SdfPath, Specifier, Stage, TokenizeError, type UpAxis, UsdValue, UsdaFile, type UsdzPackage, VERSION, Variability, composeFile, composeLayer, computeLocalTransform, crateToUsdaFile, createMemoryResolver, driveKindFor, extractRobotDescription, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, isMesh, isScope, isXform, iterDescendants, joinPosix, jointValueToSI, normalizeJointLimits, openUsdz, parseOpType, parseUsda, refineJointType, tokenize };
package/dist/core.js CHANGED
@@ -1,3 +1,3 @@
1
- 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 } from './chunk-XCP5GZPY.js';
1
+ 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, channelFromSamples, composeFile, composeLayer, computeLocalTransform, crateToUsdaFile, createMemoryResolver, driveKindFor, extractRobotDescription, fromUsdMatrix, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, getTranslation, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, identity4, interpolate, invert, isMesh, isScope, isXform, iterDescendants, joinPosix, jointValueToSI, makeEuler, makeRotationFromQuat, makeRotationX, makeRotationY, makeRotationZ, makeScale, makeTranslation, multiply, multiplyAll, normalizeJointLimits, openUsdz, parseOpType, parseUsda, refineJointType, tokenize } from './chunk-FYVZ7YPW.js';
2
2
  //# sourceMappingURL=core.js.map
3
3
  //# sourceMappingURL=core.js.map
package/dist/extras.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { T as ThreeUsdRobot } from './ThreeUsdRobot-lMZHW-it.js';
1
+ import { T as ThreeUsdRobot } from './ThreeUsdRobot-Deoh7zam.js';
2
2
  import 'three';
3
- import './buildKinematicTree-2fg6ZN8m.js';
3
+ import './buildKinematicTree-CZjBMA1I.js';
4
4
 
5
5
  /**
6
6
  * `three-usd-robot/extras`
package/dist/helpers.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as THREE from 'three';
2
- import { J as JointObject, T as ThreeUsdRobot } from './ThreeUsdRobot-lMZHW-it.js';
3
- import './buildKinematicTree-2fg6ZN8m.js';
2
+ import { J as JointObject, T as ThreeUsdRobot } from './ThreeUsdRobot-Deoh7zam.js';
3
+ import './buildKinematicTree-CZjBMA1I.js';
4
4
 
5
5
  /**
6
6
  * An arrow drawn along a joint's motion axis (the rotation axis for
package/dist/index.d.ts CHANGED
@@ -1,14 +1,32 @@
1
- import { Stage, Prim, AssetResolver } from './core.js';
2
- export { ARTICULATION_ROOT_API, Attribute, COLLISION_API, ComposeOptions, CrateReader, DEFAULT_METERS_PER_UNIT, DefaultAssetResolver, ExtractOptions, Layer, PACKAGE_NAME, ParseError, RIGID_BODY_API, Relationship, ResolvedXform, TokenizeError, UpAxis, UsdzPackage, VERSION, composeLayer, computeLocalTransform, crateToUsdaFile, createMemoryResolver, driveKindFor, extractRobotDescription, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, isMesh, isScope, isXform, iterDescendants, joinPosix, jointValueToSI, normalizeJointLimits, openUsdz, parseOpType, parseUsda, refineJointType, tokenize } from './core.js';
1
+ import { AssetResolver, Stage, Prim } from './core.js';
2
+ export { ARTICULATION_ROOT_API, Attribute, COLLISION_API, ComposeOptions, CrateReader, DEFAULT_METERS_PER_UNIT, DefaultAssetResolver, ExtractOptions, Layer, PACKAGE_NAME, ParseError, RIGID_BODY_API, Relationship, ResolvedXform, TokenizeError, UpAxis, UsdzPackage, VERSION, composeFile, composeLayer, computeLocalTransform, crateToUsdaFile, createMemoryResolver, driveKindFor, extractRobotDescription, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, isMesh, isScope, isXform, iterDescendants, joinPosix, jointValueToSI, normalizeJointLimits, openUsdz, parseOpType, parseUsda, refineJointType, tokenize } from './core.js';
3
3
  import * as THREE from 'three';
4
- import { A as Axis, R as RobotDescription } from './buildKinematicTree-2fg6ZN8m.js';
5
- export { a as AssetPath, b as AttributeSpec, B as BuildTreeOptions, C as CompositionArc, D as DEG2RAD, J as JointDescription, c as JointDriveDescription, d as JointType, K as KinematicNode, e as KinematicTree, L as LinkDescription, f as ListOp, M as Mat4, g as MetadataMap, P as PrimSpec, h as PropertySpec, Q as Quat, i as RAD2DEG, j as RelationshipSpec, S as SdfPath, k as Specifier, T as TreeEdge, U as UsdDictionary, l as UsdMatrix, m as UsdValue, n as UsdaFile, V as Variability, o as Vec2, p as Vec3, q as Vec4, r as buildKinematicTree, s as fromUsdMatrix, t as getTranslation, u as identity4, v as invert, w as makeEuler, x as makeRotationFromQuat, y as makeRotationX, z as makeRotationY, E as makeRotationZ, F as makeScale, G as makeTranslation, H as multiply, I as multiplyAll } from './buildKinematicTree-2fg6ZN8m.js';
6
- import { T as ThreeUsdRobot } from './ThreeUsdRobot-lMZHW-it.js';
7
- export { J as JointObject, L as LinkObject, a as ThreeUsdRobotOptions } from './ThreeUsdRobot-lMZHW-it.js';
4
+ import { A as Axis, R as RobotDescription, V as Vec3 } from './buildKinematicTree-CZjBMA1I.js';
5
+ export { b as AssetPath, c as AttributeSpec, B as BuildTreeOptions, C as CompositionArc, D as DEG2RAD, a as JointDescription, d as JointDriveDescription, J as JointType, e as KinematicNode, K as KinematicTree, L as LinkDescription, f as ListOp, M as Mat4, g as MetadataMap, P as PrimSpec, h as PropertySpec, Q as Quat, i as RAD2DEG, j as RelationshipSpec, S as SampleChannel, k as SdfPath, l as Specifier, T as TreeEdge, U as UsdDictionary, m as UsdMatrix, n as UsdValue, o as UsdaFile, p as Variability, q as Vec2, r as Vec4, s as buildKinematicTree, t as channelFromSamples, u as fromUsdMatrix, v as getTranslation, w as identity4, x as interpolate, y as invert, z as makeEuler, E as makeRotationFromQuat, F as makeRotationX, G as makeRotationY, H as makeRotationZ, I as makeScale, N as makeTranslation, O as multiply, W as multiplyAll } from './buildKinematicTree-CZjBMA1I.js';
6
+ import { T as ThreeUsdRobot } from './ThreeUsdRobot-Deoh7zam.js';
7
+ export { J as JointObject, L as LinkObject, a as ThreeUsdRobotOptions } from './ThreeUsdRobot-Deoh7zam.js';
8
8
 
9
9
  /** Unit vector for a USD joint axis token. Returns a fresh vector each call. */
10
10
  declare function axisVector(axis: Axis): THREE.Vector3;
11
11
 
12
+ /**
13
+ * Loads texture image assets referenced by `UsdShade` materials.
14
+ *
15
+ * A {@link TextureProvider} maps an authored asset path to a `THREE.Texture`.
16
+ * The default provider resolves the path against the layer base URL and loads it
17
+ * with `THREE.TextureLoader` (so it works for textures served alongside the USD
18
+ * on the web). Textures load asynchronously and update the material when ready.
19
+ */
20
+
21
+ /** Resolve an authored texture asset path to a `THREE.Texture` (or `null`). */
22
+ type TextureProvider = (assetPath: string) => THREE.Texture | null;
23
+ /**
24
+ * A {@link TextureProvider} backed by `THREE.TextureLoader`, resolving paths via
25
+ * `resolver` against `baseUrl`. Results are cached per resolved URL and tagged
26
+ * as sRGB color textures.
27
+ */
28
+ declare function createTextureProvider(resolver: AssetResolver, baseUrl: string): TextureProvider;
29
+
12
30
  /**
13
31
  * Binds `UsdGeom.Mesh` prims to Three.js geometry and attaches them under the
14
32
  * robot's link objects.
@@ -23,11 +41,18 @@ type MeshKind = "visual" | "collision";
23
41
  type BindMeshesOptions = {
24
42
  loadVisuals?: boolean;
25
43
  loadCollisions?: boolean;
44
+ /** Resolves diffuse texture asset paths to `THREE.Texture` (M-tex). */
45
+ textureProvider?: TextureProvider;
26
46
  };
27
47
  /** Build a `BufferGeometry` from a Mesh prim, or `null` if it has no points. */
28
48
  declare function buildMeshGeometry(meshPrim: Prim): THREE.BufferGeometry | null;
29
- /** Build a default material for a Mesh prim from `displayColor` / `doubleSided`. */
30
- declare function buildMeshMaterial(meshPrim: Prim): THREE.Material;
49
+ /**
50
+ * Build a material for a Mesh prim. Color priority: bound `UsdShade` material
51
+ * (when `stage` is given) → `primvars:displayColor` → default gray. A diffuse
52
+ * texture (via `textures`) becomes `material.map`; metalness / roughness /
53
+ * opacity come from the bound material when present.
54
+ */
55
+ declare function buildMeshMaterial(meshPrim: Prim, stage?: Stage, textures?: TextureProvider): THREE.Material;
31
56
  /**
32
57
  * Attach visual (and optionally collision) meshes to every link of a built
33
58
  * {@link ThreeUsdRobot}. Each mesh is positioned by its transform relative to
@@ -35,6 +60,28 @@ declare function buildMeshMaterial(meshPrim: Prim): THREE.Material;
35
60
  */
36
61
  declare function bindRobotMeshes(stage: Stage, robot3d: ThreeUsdRobot, desc: RobotDescription, options?: BindMeshesOptions): void;
37
62
 
63
+ /**
64
+ * Resolves `UsdShade` material bindings to flat PBR parameters.
65
+ *
66
+ * Follows a prim's (or an ancestor's) `material:binding` to a `Material`, finds
67
+ * its surface `Shader`, and reads constant color/metalness/roughness/opacity
68
+ * inputs plus the diffuse **texture** asset path. Handles both
69
+ * `UsdPreviewSurface` (`inputs:diffuseColor` constant or a `UsdUVTexture`
70
+ * network) and Omniverse `OmniPBR` MDL (`inputs:diffuse_color_constant`,
71
+ * `inputs:diffuse_texture`). Only the diffuse channel and constants are read.
72
+ */
73
+
74
+ type ResolvedMaterial = {
75
+ color?: Vec3;
76
+ opacity?: number;
77
+ metalness?: number;
78
+ roughness?: number;
79
+ /** Authored asset path of the diffuse/albedo texture, if any. */
80
+ colorTexture?: string;
81
+ };
82
+ /** Resolve the bound material's flat parameters for `prim`, or `undefined`. */
83
+ declare function resolveBoundMaterial(stage: Stage, prim: Prim): ResolvedMaterial | undefined;
84
+
38
85
  type ThreeUsdRobotLoaderOptions = {
39
86
  /** Resolver for references / payloads / sublayers (default {@link DefaultAssetResolver}). */
40
87
  assetResolver?: AssetResolver;
@@ -42,6 +89,8 @@ type ThreeUsdRobotLoaderOptions = {
42
89
  loadVisuals?: boolean;
43
90
  /** Render collision meshes (M6). */
44
91
  loadCollisions?: boolean;
92
+ /** Load diffuse textures referenced by materials (default `true`). */
93
+ loadTextures?: boolean;
45
94
  /** Up-axis correction strategy (M9). */
46
95
  upAxisConversion?: "auto" | "Y" | "Z" | "none";
47
96
  /** Extra uniform scale multiplied with `metersPerUnit` (M9). */
@@ -77,7 +126,7 @@ declare class ThreeUsdRobotLoader {
77
126
  /** Build a robot from the bytes of a `.usdz` package. */
78
127
  parseUsdz(bytes: Uint8Array): Promise<ThreeUsdRobot>;
79
128
  /** Build a robot from the bytes of a binary crate (`.usdc` / binary `.usd`). */
80
- parseCrate(bytes: Uint8Array): Promise<ThreeUsdRobot>;
129
+ parseCrate(bytes: Uint8Array, baseUrl?: string): Promise<ThreeUsdRobot>;
81
130
  /** Parse + compose USDA source into the Three.js-independent robot IR. */
82
131
  parseRobotDescription(text: string, baseUrl?: string): Promise<RobotDescription>;
83
132
  private buildFromStage;
@@ -86,4 +135,4 @@ declare class ThreeUsdRobotLoader {
86
135
  private extractOptions;
87
136
  }
88
137
 
89
- export { AssetResolver, Axis, type BindMeshesOptions, type MeshKind, Prim, RobotDescription, Stage, ThreeUsdRobot, ThreeUsdRobotLoader, type ThreeUsdRobotLoaderOptions, axisVector, bindRobotMeshes, buildMeshGeometry, buildMeshMaterial };
138
+ export { AssetResolver, Axis, type BindMeshesOptions, type MeshKind, Prim, type ResolvedMaterial, RobotDescription, Stage, type TextureProvider, ThreeUsdRobot, ThreeUsdRobotLoader, type ThreeUsdRobotLoaderOptions, Vec3, axisVector, bindRobotMeshes, buildMeshGeometry, buildMeshMaterial, createTextureProvider, resolveBoundMaterial };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { identity4, multiply, computeLocalTransform, invert, DefaultAssetResolver, CrateReader, openUsdz, crateToUsdaFile, Stage, extractRobotDescription, buildKinematicTree, composeLayer } from './chunk-XCP5GZPY.js';
2
- 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 } from './chunk-XCP5GZPY.js';
1
+ import { AssetPath, identity4, multiply, computeLocalTransform, invert, interpolate, DefaultAssetResolver, CrateReader, openUsdz, crateToUsdaFile, composeFile, Stage, extractRobotDescription, buildKinematicTree, composeLayer } from './chunk-FYVZ7YPW.js';
2
+ 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, channelFromSamples, composeFile, composeLayer, computeLocalTransform, crateToUsdaFile, createMemoryResolver, driveKindFor, extractRobotDescription, fromUsdMatrix, gatherMeshDescendants, getJointAxis, getJointBodies, getJointDrive, getJointLimits, getJointLocalFrame, getJointStatePosition, getJointType, getTranslation, hasArticulationRootAPI, hasCollisionAPI, hasRigidBodyAPI, identity4, interpolate, invert, isMesh, isScope, isXform, iterDescendants, joinPosix, jointValueToSI, makeEuler, makeRotationFromQuat, makeRotationX, makeRotationY, makeRotationZ, makeScale, makeTranslation, multiply, multiplyAll, normalizeJointLimits, openUsdz, parseOpType, parseUsda, refineJointType, tokenize } from './chunk-FYVZ7YPW.js';
3
3
  import * as THREE4 from 'three';
4
4
 
5
5
  function axisVector(axis) {
@@ -71,6 +71,93 @@ var LinkObject = class extends THREE4.Object3D {
71
71
  this.matrixAutoUpdate = false;
72
72
  }
73
73
  };
74
+
75
+ // src/three/MaterialBinding.ts
76
+ var DIFFUSE_INPUTS = [
77
+ "inputs:diffuseColor",
78
+ // UsdPreviewSurface
79
+ "inputs:diffuse_color_constant",
80
+ // OmniPBR
81
+ "inputs:diffuse_tint",
82
+ "inputs:base_color",
83
+ "inputs:baseColor"
84
+ ];
85
+ var OPACITY_INPUTS = ["inputs:opacity", "inputs:opacity_constant"];
86
+ var METALLIC_INPUTS = ["inputs:metallic", "inputs:metallic_constant"];
87
+ var ROUGHNESS_INPUTS = ["inputs:roughness", "inputs:reflection_roughness_constant"];
88
+ var SURFACE_OUTPUTS = ["outputs:surface", "outputs:mdl:surface"];
89
+ function resolveBoundMaterial(stage, prim) {
90
+ const materialPath = findBinding(prim);
91
+ if (!materialPath) return void 0;
92
+ const material = stage.GetPrimAtPath(materialPath);
93
+ if (!material) return void 0;
94
+ const shader = findSurfaceShader(material);
95
+ if (!shader) return void 0;
96
+ const result = {};
97
+ const color = firstColor(shader, DIFFUSE_INPUTS);
98
+ if (color) result.color = color;
99
+ const opacity = firstNumber(shader, OPACITY_INPUTS);
100
+ if (opacity !== void 0) result.opacity = opacity;
101
+ const metalness = firstNumber(shader, METALLIC_INPUTS);
102
+ if (metalness !== void 0) result.metalness = metalness;
103
+ const roughness = firstNumber(shader, ROUGHNESS_INPUTS);
104
+ if (roughness !== void 0) result.roughness = roughness;
105
+ const texture = findDiffuseTexture(shader);
106
+ if (texture !== void 0) result.colorTexture = texture;
107
+ return result;
108
+ }
109
+ var DIFFUSE_TEXTURE_INPUTS = ["inputs:diffuse_texture", "inputs:diffuse_color_texture"];
110
+ function findDiffuseTexture(shader) {
111
+ for (const name of DIFFUSE_TEXTURE_INPUTS) {
112
+ const v = shader.GetAttribute(name).Get();
113
+ if (v instanceof AssetPath && v.path) return v.path;
114
+ }
115
+ const conn = shader.GetAttribute("inputs:diffuseColor").GetConnections()[0];
116
+ if (conn) {
117
+ const texPrim = shader.GetStage().GetPrimAtPath(conn.split(".")[0]);
118
+ const file = texPrim?.GetAttribute("inputs:file").Get();
119
+ if (file instanceof AssetPath && file.path) return file.path;
120
+ }
121
+ return void 0;
122
+ }
123
+ function findBinding(prim) {
124
+ let p = prim;
125
+ while (p) {
126
+ const targets = p.GetRelationship("material:binding").GetTargets();
127
+ if (targets.length > 0) return targets[0];
128
+ p = p.GetParent();
129
+ }
130
+ return void 0;
131
+ }
132
+ function findSurfaceShader(material) {
133
+ for (const out of SURFACE_OUTPUTS) {
134
+ const conn = material.GetAttribute(out).GetConnections()[0];
135
+ if (conn) {
136
+ const shaderPath = conn.split(".")[0];
137
+ const shader = material.GetStage().GetPrimAtPath(shaderPath);
138
+ if (shader) return shader;
139
+ }
140
+ }
141
+ return material.GetChildren().find((c) => c.GetTypeName() === "Shader") ?? void 0;
142
+ }
143
+ function firstColor(shader, names) {
144
+ for (const name of names) {
145
+ const v = shader.GetAttribute(name).Get();
146
+ if (Array.isArray(v) && v.length >= 3 && v.every((n) => typeof n === "number")) {
147
+ return [v[0], v[1], v[2]];
148
+ }
149
+ }
150
+ return void 0;
151
+ }
152
+ function firstNumber(shader, names) {
153
+ for (const name of names) {
154
+ const v = shader.GetAttribute(name).Get();
155
+ if (typeof v === "number") return v;
156
+ }
157
+ return void 0;
158
+ }
159
+
160
+ // src/three/MeshBinding.ts
74
161
  var DEFAULT_COLOR = 10132122;
75
162
  function buildMeshGeometry(meshPrim) {
76
163
  const points = meshPrim.GetAttribute("points").Get();
@@ -96,24 +183,41 @@ function buildMeshGeometry(meshPrim) {
96
183
  }
97
184
  return geometry;
98
185
  }
99
- function buildMeshMaterial(meshPrim) {
186
+ function buildMeshMaterial(meshPrim, stage, textures) {
100
187
  const color = new THREE4.Color(DEFAULT_COLOR);
101
- const displayColor = meshPrim.GetAttribute("primvars:displayColor").Get();
102
- if (isVec3Array(displayColor) && displayColor[0]) {
103
- const [r, g, b] = displayColor[0];
104
- color.setRGB(r, g, b);
188
+ let metalness = 0.1;
189
+ let roughness = 0.8;
190
+ let opacity = 1;
191
+ const bound = stage ? resolveBoundMaterial(stage, meshPrim) : void 0;
192
+ if (bound?.color) {
193
+ color.setRGB(bound.color[0], bound.color[1], bound.color[2]);
194
+ } else {
195
+ const displayColor = meshPrim.GetAttribute("primvars:displayColor").Get();
196
+ if (isVec3Array(displayColor) && displayColor[0]) {
197
+ const [r, g, b] = displayColor[0];
198
+ color.setRGB(r, g, b);
199
+ }
105
200
  }
201
+ if (bound?.metalness !== void 0) metalness = bound.metalness;
202
+ if (bound?.roughness !== void 0) roughness = bound.roughness;
203
+ if (bound?.opacity !== void 0) opacity = bound.opacity;
204
+ const map = bound?.colorTexture && textures ? textures(bound.colorTexture) : null;
205
+ if (map) color.setRGB(1, 1, 1);
106
206
  const doubleSided = meshPrim.GetAttribute("doubleSided").Get() === true;
107
207
  return new THREE4.MeshStandardMaterial({
108
208
  color,
109
- metalness: 0.1,
110
- roughness: 0.8,
111
- side: doubleSided ? THREE4.DoubleSide : THREE4.FrontSide
209
+ metalness,
210
+ roughness,
211
+ transparent: opacity < 1,
212
+ opacity,
213
+ side: doubleSided ? THREE4.DoubleSide : THREE4.FrontSide,
214
+ ...map ? { map } : {}
112
215
  });
113
216
  }
114
217
  function bindRobotMeshes(stage, robot3d, desc, options = {}) {
115
218
  const loadVisuals = options.loadVisuals ?? true;
116
219
  const loadCollisions = options.loadCollisions ?? false;
220
+ const textures = options.textureProvider;
117
221
  for (const [key, link] of Object.entries(desc.links)) {
118
222
  const linkObj = robot3d.getLinkObject(key);
119
223
  const linkPrim = stage.GetPrimAtPath(link.primPath);
@@ -122,22 +226,22 @@ function bindRobotMeshes(stage, robot3d, desc, options = {}) {
122
226
  if (loadVisuals) {
123
227
  for (const meshPath of link.visualPrims) {
124
228
  if (collisionSet.has(meshPath)) continue;
125
- attachMesh(stage, linkPrim, meshPath, linkObj, "visual");
229
+ attachMesh(stage, linkPrim, meshPath, linkObj, "visual", textures);
126
230
  }
127
231
  }
128
232
  if (loadCollisions) {
129
233
  for (const meshPath of link.collisionPrims ?? []) {
130
- attachMesh(stage, linkPrim, meshPath, linkObj, "collision");
234
+ attachMesh(stage, linkPrim, meshPath, linkObj, "collision", textures);
131
235
  }
132
236
  }
133
237
  }
134
238
  }
135
- function attachMesh(stage, linkPrim, meshPath, parent, kind) {
239
+ function attachMesh(stage, linkPrim, meshPath, parent, kind, textures) {
136
240
  const meshPrim = stage.GetPrimAtPath(meshPath);
137
241
  if (!meshPrim) return;
138
242
  const geometry = buildMeshGeometry(meshPrim);
139
243
  if (!geometry) return;
140
- const mesh = new THREE4.Mesh(geometry, buildMeshMaterial(meshPrim));
244
+ const mesh = new THREE4.Mesh(geometry, buildMeshMaterial(meshPrim, stage, textures));
141
245
  mesh.name = meshPrim.GetName();
142
246
  mesh.userData.kind = kind;
143
247
  mesh.userData.primPath = meshPath;
@@ -203,6 +307,26 @@ function isVec3Array(v) {
203
307
  function isVec2Array(v) {
204
308
  return Array.isArray(v) && v.every((e) => Array.isArray(e) && e.length === 2);
205
309
  }
310
+ function createTextureProvider(resolver, baseUrl) {
311
+ const loader = new THREE4.TextureLoader();
312
+ const cache = /* @__PURE__ */ new Map();
313
+ return (assetPath) => {
314
+ let url;
315
+ try {
316
+ url = resolver.resolve(assetPath, baseUrl);
317
+ } catch {
318
+ return null;
319
+ }
320
+ const cached = cache.get(url);
321
+ if (cached) return cached;
322
+ const texture = loader.load(url);
323
+ texture.colorSpace = THREE4.SRGBColorSpace;
324
+ texture.wrapS = THREE4.RepeatWrapping;
325
+ texture.wrapT = THREE4.RepeatWrapping;
326
+ cache.set(url, texture);
327
+ return texture;
328
+ };
329
+ }
206
330
  var ThreeUsdRobot = class extends THREE4.Object3D {
207
331
  isThreeUsdRobot = true;
208
332
  robot;
@@ -354,6 +478,41 @@ var ThreeUsdRobot = class extends THREE4.Object3D {
354
478
  getKinematicTree() {
355
479
  return this.tree;
356
480
  }
481
+ // -- Animation playback --------------------------------------------------
482
+ /** Playback rate in time codes per second (from the stage; default 24). */
483
+ getTimeCodesPerSecond() {
484
+ return this.robot.timeCodesPerSecond ?? 24;
485
+ }
486
+ /** Whether any joint has a time-sampled trajectory. */
487
+ hasAnimation() {
488
+ return Object.values(this.robot.joints).some((j) => j.valueSamples !== void 0);
489
+ }
490
+ /**
491
+ * Animation range in time codes: the union of authored joint sample ranges,
492
+ * falling back to the stage `startTimeCode`/`endTimeCode`. `null` if neither.
493
+ */
494
+ getTimeRange() {
495
+ let start = Number.POSITIVE_INFINITY;
496
+ let end = Number.NEGATIVE_INFINITY;
497
+ for (const joint of Object.values(this.robot.joints)) {
498
+ const times = joint.valueSamples?.times;
499
+ if (!times || times.length === 0) continue;
500
+ start = Math.min(start, times[0]);
501
+ end = Math.max(end, times[times.length - 1]);
502
+ }
503
+ if (start <= end) return { start, end };
504
+ const { startTimeCode, endTimeCode } = this.robot;
505
+ if (startTimeCode !== void 0 && endTimeCode !== void 0) {
506
+ return { start: startTimeCode, end: endTimeCode };
507
+ }
508
+ return null;
509
+ }
510
+ /** Sample every animated joint at time code `t` and apply the values. */
511
+ setTime(t) {
512
+ for (const [key, joint] of Object.entries(this.robot.joints)) {
513
+ if (joint.valueSamples) this.setJointValue(key, interpolate(joint.valueSamples, t));
514
+ }
515
+ }
357
516
  // -- Display toggles -----------------------------------------------------
358
517
  get showVisual() {
359
518
  return this._showVisual;
@@ -429,7 +588,7 @@ var ThreeUsdRobotLoader = class {
429
588
  return this.parseUsdz(await this.fetchRootBytes(url));
430
589
  }
431
590
  const bytes = await this.fetchRootBytes(url);
432
- if (CrateReader.isCrate(bytes)) return this.parseCrate(bytes);
591
+ if (CrateReader.isCrate(bytes)) return this.parseCrate(bytes, url);
433
592
  return this.parse(new TextDecoder().decode(bytes), url);
434
593
  }
435
594
  async fetchRootBytes(url) {
@@ -439,32 +598,44 @@ var ThreeUsdRobotLoader = class {
439
598
  }
440
599
  /** Build a robot (composed, with meshes) from USDA source text. */
441
600
  async parse(text, baseUrl = "") {
442
- return this.buildFromStage(await this.composeStage(text, baseUrl, this.resolver));
601
+ return this.buildFromStage(
602
+ await this.composeStage(text, baseUrl, this.resolver),
603
+ baseUrl,
604
+ this.resolver
605
+ );
443
606
  }
444
607
  /** Build a robot from the bytes of a `.usdz` package. */
445
608
  async parseUsdz(bytes) {
446
609
  const pkg = openUsdz(bytes);
447
610
  const rootText = await pkg.resolver.fetchText(pkg.rootEntry);
448
- return this.buildFromStage(await this.composeStage(rootText, pkg.rootEntry, pkg.resolver));
611
+ const stage = await this.composeStage(rootText, pkg.rootEntry, pkg.resolver);
612
+ return this.buildFromStage(stage, pkg.rootEntry, pkg.resolver);
449
613
  }
450
614
  /** Build a robot from the bytes of a binary crate (`.usdc` / binary `.usd`). */
451
- parseCrate(bytes) {
615
+ async parseCrate(bytes, baseUrl = "") {
452
616
  const file = crateToUsdaFile(new CrateReader(bytes));
453
- return Promise.resolve(this.buildFromStage(Stage.OpenFromFile(file)));
617
+ const composeOptions = this.options.onWarn ? { onWarn: this.options.onWarn } : {};
618
+ const composed = await composeFile(file, baseUrl, this.resolver, composeOptions);
619
+ return this.buildFromStage(Stage.OpenFromFile(composed), baseUrl, this.resolver);
454
620
  }
455
621
  /** Parse + compose USDA source into the Three.js-independent robot IR. */
456
622
  async parseRobotDescription(text, baseUrl = "") {
457
623
  const stage = await this.composeStage(text, baseUrl, this.resolver);
458
624
  return extractRobotDescription(stage, this.extractOptions());
459
625
  }
460
- buildFromStage(stage) {
626
+ buildFromStage(stage, baseUrl, resolver) {
461
627
  const robot = extractRobotDescription(stage, this.extractOptions());
462
628
  const tree = buildKinematicTree(robot);
463
629
  const robot3d = new ThreeUsdRobot(robot, tree, this.robotOptions());
464
630
  const loadVisuals = this.options.loadVisuals ?? true;
465
631
  const loadCollisions = this.options.loadCollisions ?? false;
466
632
  if (loadVisuals || loadCollisions) {
467
- bindRobotMeshes(stage, robot3d, robot, { loadVisuals, loadCollisions });
633
+ const textureProvider = this.options.loadTextures ?? true ? createTextureProvider(resolver, baseUrl) : void 0;
634
+ bindRobotMeshes(stage, robot3d, robot, {
635
+ loadVisuals,
636
+ loadCollisions,
637
+ ...textureProvider ? { textureProvider } : {}
638
+ });
468
639
  }
469
640
  return robot3d;
470
641
  }
@@ -488,6 +659,6 @@ var ThreeUsdRobotLoader = class {
488
659
  }
489
660
  };
490
661
 
491
- export { JointObject, LinkObject, ThreeUsdRobot, ThreeUsdRobotLoader, axisVector, bindRobotMeshes, buildMeshGeometry, buildMeshMaterial };
662
+ export { JointObject, LinkObject, ThreeUsdRobot, ThreeUsdRobotLoader, axisVector, bindRobotMeshes, buildMeshGeometry, buildMeshMaterial, createTextureProvider, resolveBoundMaterial };
492
663
  //# sourceMappingURL=index.js.map
493
664
  //# sourceMappingURL=index.js.map