@openusd-wasm/three-loader 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 KeJun <https://github.com/kejunmao>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # @openusd-wasm/three-loader
2
+
3
+ Three.js loader for OpenUSD `.usd`, `.usda`, `.usdc`, and `.usdz` assets.
4
+ Parsing runs through `@openusd-wasm/pxr`; this package converts the opened USD
5
+ stage into a Three.js object tree and keeps OpenUSD metadata available in
6
+ `Object3D.userData`.
7
+
8
+ ```ts
9
+ import createOpenUsdPxrWasm from '@openusd-wasm/core'
10
+ import { wasmURL, workerURL } from '@openusd-wasm/core/urls'
11
+ import { USDLoader } from '@openusd-wasm/three-loader'
12
+
13
+ const loader = new USDLoader({
14
+ pxrOptions: {
15
+ core: createOpenUsdPxrWasm,
16
+ wasmURL,
17
+ workerURL,
18
+ },
19
+ })
20
+
21
+ const { scene, metadata } = await loader.loadAsync('/models/robot.usda')
22
+ threeScene.add(scene)
23
+
24
+ console.log(metadata.joints)
25
+ ```
26
+
27
+ ## Returned Data
28
+
29
+ `USDLoader` returns:
30
+
31
+ - `scene`: a `THREE.Group` containing mesh/group objects that mirror the USD prim hierarchy.
32
+ - `metadata`: stage info, view prims, mesh geometry summaries, material/shader inputs, and physics joint info.
33
+ - `sourcePath` and `rootLayerIdentifier`: useful for diagnostics and texture resolution.
34
+
35
+ The same metadata is attached to the scene:
36
+
37
+ ```ts
38
+ scene.userData.usdMetadata
39
+ scene.userData.usdJoints
40
+ scene.userData.usdObjectsByPath
41
+ ```
42
+
43
+ Each generated object gets `userData.usdPath` and `userData.usdTypeName`.
44
+ Joint prim objects get `userData.usdJoint`; body objects referenced by joints
45
+ get a `userData.usdJoints` array. This mirrors the URDFLoader pattern where
46
+ clients can restore articulation controls from exported joint metadata.
47
+
48
+ ## USDZ
49
+
50
+ For USDZ packages, OpenUSD can often open the package path directly. If the
51
+ package requires an explicit root layer, pass it when constructing or parsing:
52
+
53
+ ```ts
54
+ const loader = new USDLoader({
55
+ pxr,
56
+ usdzLayer: 'robot.usda',
57
+ })
58
+ ```
59
+
60
+ The loader will open `file.usdz[robot.usda]` before falling back to `file.usdz`.
61
+
62
+ ## References
63
+
64
+ For URL-based loads, the loader resolves same-origin relative USD references
65
+ automatically before opening the stage. It scans the entry asset for referenced
66
+ USD, image, and material paths, fetches those files recursively, and mirrors
67
+ them into the same virtual filesystem directory that OpenUSD opens from.
68
+
69
+ This handles common exported asset layouts where files reference extensionless
70
+ assets like `./resource/material` while the server stores `material.usd`.
71
+ When the entry layer references a known asset root, such as `resource/` or
72
+ `textures/`, sibling references are also searched under that root. Use
73
+ `assetSearchRoots` to configure additional pipeline-specific root folders,
74
+ pass `files` to `parseAsync` for explicit virtual filesystem entries, or set
75
+ `autoResolveAssets: false` to disable this behavior.
76
+
77
+ ## Textures
78
+
79
+ USD asset paths do not always map directly to browser URLs. The loader creates
80
+ object URLs for image files it auto-resolves and for image entries inside stored
81
+ USDZ packages. Pass `textureResolver` to override or extend that mapping for
82
+ custom asset systems.
83
+
84
+ ```ts
85
+ const loader = new USDLoader({
86
+ pxr,
87
+ textureResolver(asset, context) {
88
+ if (asset.path) return new URL(asset.path, context.sourcePath).href
89
+ return null
90
+ },
91
+ })
92
+ ```
@@ -0,0 +1,243 @@
1
+ import { Pxr } from "@openusd-wasm/pxr";
2
+ import * as THREE from "three";
3
+ import { Loader, LoadingManager } from "three";
4
+
5
+ //#region src/types.d.ts
6
+ type USDSourceInput = string | ArrayBuffer | ArrayBufferView | Blob;
7
+ type USDFileExtension = 'usd' | 'usda' | 'usdc' | 'usdz';
8
+ type USDVector2 = [number, number];
9
+ type USDVector3 = [number, number, number];
10
+ type USDVector4 = [number, number, number, number];
11
+ interface USDStageInfo {
12
+ sourcePath: string;
13
+ rootLayerIdentifier: string;
14
+ defaultPrim: string | null;
15
+ upAxis: string;
16
+ startTimeCode?: number | null;
17
+ endTimeCode?: number | null;
18
+ timeCodesPerSecond?: number;
19
+ }
20
+ interface USDViewPrim {
21
+ path: string;
22
+ parentPath: string | null;
23
+ name: string;
24
+ typeName: string;
25
+ visibility: string;
26
+ localMatrix: number[] | null;
27
+ resetsXformStack: boolean;
28
+ }
29
+ interface USDMeshGeometryData {
30
+ positions: number[];
31
+ normals: number[];
32
+ uvs: number[];
33
+ displayColor: USDVector3 | null;
34
+ displayOpacity: number | null;
35
+ }
36
+ interface USDMeshElement {
37
+ path: string;
38
+ doubleSided: boolean;
39
+ material: string | null;
40
+ geometry: USDMeshGeometryData;
41
+ }
42
+ interface USDShaderInfo {
43
+ path: string;
44
+ id: string | null;
45
+ inputs: Record<string, unknown>;
46
+ }
47
+ interface USDMaterialInfo {
48
+ path: string;
49
+ inputs: Record<string, unknown>;
50
+ shaders: USDShaderInfo[];
51
+ }
52
+ interface USDJointDriveInfo {
53
+ targetPosition: number | null;
54
+ targetVelocity: number | null;
55
+ stiffness: number | null;
56
+ damping: number | null;
57
+ maxForce: number | null;
58
+ }
59
+ interface USDJointInfo {
60
+ path: string;
61
+ name: string;
62
+ typeName: string;
63
+ jointType: string;
64
+ body0: string | null;
65
+ body1: string | null;
66
+ axis: string | null;
67
+ localPos0: USDVector3;
68
+ localPos1: USDVector3;
69
+ localRot0: USDVector4 | null;
70
+ localRot1: USDVector4 | null;
71
+ lowerLimit: number | null;
72
+ upperLimit: number | null;
73
+ enabled: boolean;
74
+ drive: USDJointDriveInfo | null;
75
+ drives: Record<string, USDJointDriveInfo>;
76
+ }
77
+ interface USDTransformAnimationSample {
78
+ time: number;
79
+ localMatrix: number[];
80
+ }
81
+ interface USDTransformAnimation {
82
+ primPath: string;
83
+ samples: USDTransformAnimationSample[];
84
+ }
85
+ interface USDAnimationInfo {
86
+ startTimeCode: number;
87
+ endTimeCode: number;
88
+ timeCodesPerSecond: number;
89
+ transforms: USDTransformAnimation[];
90
+ }
91
+ interface USDModelData {
92
+ stage: USDStageInfo;
93
+ view: {
94
+ prims: USDViewPrim[];
95
+ };
96
+ elements: USDMeshElement[];
97
+ materials: USDMaterialInfo[];
98
+ joints: USDJointInfo[];
99
+ animations: USDAnimationInfo[];
100
+ }
101
+ interface USDLoadedModel {
102
+ scene: THREE.Group;
103
+ metadata: USDModelData;
104
+ stage?: unknown;
105
+ pxr: Pxr;
106
+ sourcePath: string;
107
+ rootLayerIdentifier: string;
108
+ }
109
+ interface ExtractUSDModelDataOptions {
110
+ sourcePath?: string;
111
+ rootLayerIdentifier?: string;
112
+ }
113
+ interface USDTextureResolverContext {
114
+ sourcePath: string;
115
+ material?: USDMaterialInfo;
116
+ shader?: USDShaderInfo;
117
+ }
118
+ interface USDAssetValue {
119
+ path?: string;
120
+ resolvedPath?: string;
121
+ url?: string;
122
+ }
123
+ type USDTextureResolver = (asset: USDAssetValue, context: USDTextureResolverContext) => string | null | undefined;
124
+ interface BuildUSDObjectOptions {
125
+ sourcePath?: string;
126
+ convertZUp?: boolean;
127
+ loadTextures?: boolean;
128
+ textureResolver?: USDTextureResolver;
129
+ textureLoader?: THREE.TextureLoader;
130
+ textureCache?: Map<string, THREE.Texture>;
131
+ }
132
+ interface USDLoaderParseOptions extends BuildUSDObjectOptions {
133
+ sourcePath?: string;
134
+ fileName?: string;
135
+ files?: Record<string, USDSourceInput>;
136
+ autoResolveAssets?: boolean;
137
+ assetSearchExtensions?: string[];
138
+ assetSearchRoots?: string[];
139
+ maxAssetReferences?: number;
140
+ maxAssetReferenceDepth?: number;
141
+ workingDirectory?: string;
142
+ usdzLayer?: string;
143
+ preserveStage?: boolean;
144
+ cleanupAfterParse?: boolean;
145
+ }
146
+ interface USDLoaderOptions extends BuildUSDObjectOptions {
147
+ pxr?: Pxr | Promise<Pxr>;
148
+ pxrOptions?: Parameters<typeof import('@openusd-wasm/pxr').createPxr>[0];
149
+ workingDirectory?: string;
150
+ assetSearchRoots?: string[];
151
+ usdzLayer?: string;
152
+ preserveStage?: boolean;
153
+ cleanupAfterParse?: boolean;
154
+ }
155
+ type PxrObject = Record<string, any> & {
156
+ delete?: () => void;
157
+ };
158
+ //#endregion
159
+ //#region src/loader.d.ts
160
+ declare class USDLoader extends Loader<USDLoadedModel, string> {
161
+ private options;
162
+ private pxrPromise;
163
+ constructor(manager?: LoadingManager);
164
+ constructor(options?: USDLoaderOptions, manager?: LoadingManager);
165
+ setPxr(pxr: Pxr | Promise<Pxr>): this;
166
+ setUSDZLayer(layer: string): this;
167
+ setWorkingDirectory(path: string): this;
168
+ load(url: string, onLoad: (data: USDLoadedModel) => void, onProgress?: (event: ProgressEvent) => void, onError?: (err: unknown) => void): void;
169
+ parse(input: USDSourceInput, onLoad: (data: USDLoadedModel) => void, onError?: (err: unknown) => void, options?: USDLoaderParseOptions): void;
170
+ parseAsync(input: USDSourceInput, options?: USDLoaderParseOptions): Promise<USDLoadedModel>;
171
+ private getPxr;
172
+ }
173
+ //#endregion
174
+ //#region src/manipulation-controls.d.ts
175
+ interface USDManipulationControlsOptions {
176
+ scene: THREE.Scene;
177
+ camera: THREE.Camera;
178
+ domElement: HTMLElement;
179
+ controls?: {
180
+ enabled: boolean;
181
+ } | null;
182
+ highlightColor?: THREE.ColorRepresentation;
183
+ enabled?: boolean;
184
+ onChange?: (event: USDManipulationChangeEvent) => void;
185
+ onHoverChange?: (event: USDManipulationHoverEvent) => void;
186
+ }
187
+ interface USDManipulationChangeEvent {
188
+ joint: USDJointInfo;
189
+ object: THREE.Object3D;
190
+ body0: THREE.Object3D | null;
191
+ value: number;
192
+ previousValue: number;
193
+ }
194
+ interface USDManipulationHoverEvent {
195
+ joint: USDJointInfo | null;
196
+ object: THREE.Object3D | null;
197
+ }
198
+ declare class USDManipulationControls {
199
+ private readonly raycaster;
200
+ private readonly pointer;
201
+ private readonly jointValues;
202
+ private readonly highlighted;
203
+ private activeDrag;
204
+ private hovered;
205
+ private modelStateSignature;
206
+ private _enabled;
207
+ private disposed;
208
+ scene: THREE.Scene;
209
+ camera: THREE.Camera;
210
+ domElement: HTMLElement;
211
+ controls: {
212
+ enabled: boolean;
213
+ } | null;
214
+ highlightColor: THREE.Color;
215
+ onChange?: (event: USDManipulationChangeEvent) => void;
216
+ onHoverChange?: (event: USDManipulationHoverEvent) => void;
217
+ constructor(options: USDManipulationControlsOptions);
218
+ get enabled(): boolean;
219
+ set enabled(value: boolean);
220
+ dispose(): void;
221
+ update(): void;
222
+ clearSelection(): void;
223
+ getJointValue(joint: USDJointInfo, root?: THREE.Object3D): number | undefined;
224
+ setJointValue(joint: USDJointInfo, value: number, root?: THREE.Object3D): boolean;
225
+ private readonly onPointerMove;
226
+ private readonly onPointerDown;
227
+ private readonly onPointerUp;
228
+ private pickJoint;
229
+ private updatePointer;
230
+ private syncModelState;
231
+ private endDrag;
232
+ private applyHighlight;
233
+ private restoreHighlight;
234
+ }
235
+ //#endregion
236
+ //#region src/metadata.d.ts
237
+ declare function extractUSDModelData(pxr: Pxr, stage: PxrObject, options?: ExtractUSDModelDataOptions): USDModelData;
238
+ //#endregion
239
+ //#region src/three.d.ts
240
+ declare function buildUSDObject(data: USDModelData, options?: BuildUSDObjectOptions): THREE.Group;
241
+ declare function createUSDLoadedModel(data: USDModelData, pxr: USDLoadedModel['pxr'], rootLayerIdentifier: string, options?: BuildUSDObjectOptions, stage?: unknown): USDLoadedModel;
242
+ //#endregion
243
+ export { type BuildUSDObjectOptions, type ExtractUSDModelDataOptions, type PxrObject, type USDAnimationInfo, type USDAssetValue, type USDFileExtension, type USDJointDriveInfo, type USDJointInfo, type USDLoadedModel, USDLoader, type USDLoaderOptions, type USDLoaderParseOptions, type USDManipulationChangeEvent, USDManipulationControls, type USDManipulationControlsOptions, type USDManipulationHoverEvent, type USDMaterialInfo, type USDMeshElement, type USDMeshGeometryData, type USDModelData, type USDShaderInfo, type USDSourceInput, type USDStageInfo, type USDTextureResolver, type USDTextureResolverContext, type USDTransformAnimation, type USDTransformAnimationSample, type USDVector2, type USDVector3, type USDVector4, type USDViewPrim, buildUSDObject, createUSDLoadedModel, extractUSDModelData };