three-usd-robot 0.13.0 → 0.14.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.
Files changed (43) hide show
  1. package/README.md +19 -1
  2. package/dist/{MeshBinding-B_8RhuQE.d.ts → MeshBinding-5Dad1EOh.d.ts} +16 -4
  3. package/dist/{ThreeUsdRobot-X1zbpRZo.d.ts → ThreeUsdRobot-CurQqRqu.d.ts} +78 -2
  4. package/dist/{ThreeUsdRobotLoader-u3d1yoLM.d.ts → ThreeUsdRobotLoader-DrYXpMta.d.ts} +28 -4
  5. package/dist/chunk-ALC7RBKC.js +68 -0
  6. package/dist/chunk-ALC7RBKC.js.map +1 -0
  7. package/dist/{chunk-JN2QPDB3.js → chunk-HDZGWL6P.js} +36 -3
  8. package/dist/chunk-HDZGWL6P.js.map +1 -0
  9. package/dist/{chunk-YGJ23CG3.js → chunk-IAOPNN6V.js} +3 -66
  10. package/dist/chunk-IAOPNN6V.js.map +1 -0
  11. package/dist/{chunk-5ZPHZ5ZH.js → chunk-IT5RWB7A.js} +5 -4
  12. package/dist/chunk-IT5RWB7A.js.map +1 -0
  13. package/dist/{chunk-FUVHAORT.js → chunk-KRT4NL3H.js} +190 -126
  14. package/dist/chunk-KRT4NL3H.js.map +1 -0
  15. package/dist/{chunk-GRJGPHLW.js → chunk-WQRP5IDJ.js} +382 -59
  16. package/dist/chunk-WQRP5IDJ.js.map +1 -0
  17. package/dist/chunk-ZQXYVBQI.js +154 -0
  18. package/dist/chunk-ZQXYVBQI.js.map +1 -0
  19. package/dist/core.d.ts +5 -4
  20. package/dist/core.js +5 -3
  21. package/dist/extras.d.ts +2 -2
  22. package/dist/helpers.d.ts +2 -2
  23. package/dist/helpers.js +3 -2
  24. package/dist/helpers.js.map +1 -1
  25. package/dist/index.d.ts +61 -8
  26. package/dist/index.js +10 -8
  27. package/dist/index.js.map +1 -1
  28. package/dist/nodes.d.ts +4 -4
  29. package/dist/{parseMdl-vfzBGoMr.d.ts → parseMdl-M862hSal.d.ts} +1 -29
  30. package/dist/react.d.ts +5 -5
  31. package/dist/react.js +6 -4
  32. package/dist/react.js.map +1 -1
  33. package/dist/rendering.d.ts +114 -0
  34. package/dist/rendering.js +174 -0
  35. package/dist/rendering.js.map +1 -0
  36. package/dist/usdGeomCamera-BEsGuz7m.d.ts +53 -0
  37. package/dist/{buildKinematicTree-Q9JOjAjM.d.ts → usdLux-BqQlSOwG.d.ts} +108 -1
  38. package/package.json +5 -1
  39. package/dist/chunk-5ZPHZ5ZH.js.map +0 -1
  40. package/dist/chunk-FUVHAORT.js.map +0 -1
  41. package/dist/chunk-GRJGPHLW.js.map +0 -1
  42. package/dist/chunk-JN2QPDB3.js.map +0 -1
  43. package/dist/chunk-YGJ23CG3.js.map +0 -1
@@ -1,9 +1,286 @@
1
- import { getMaterialSubsets, isRenderableGprim, COLLISION_API, isNonVisualPurpose, computeLocalTransform, toBytes, extractRobotDescription, isZip, CrateReader, openUsdz, buildKinematicTree, loadMdlModules, isUnsupportedGprim, Stage, composeLayer, composeFile, crateToUsdaFile } from './chunk-FUVHAORT.js';
2
- import { ThreeUsdRobot } from './chunk-JN2QPDB3.js';
3
- import { identity4, multiply } from './chunk-YGJ23CG3.js';
1
+ import { isNonVisualPurpose, isUnsupportedLight, getLightKind, readLightDescription, getMaterialSubsets, isRenderableGprim, COLLISION_API, toBytes, extractRobotDescription, isZip, CrateReader, openUsdz, buildKinematicTree, loadMdlModules, isUnsupportedGprim, Stage, composeLayer, composeFile, crateToUsdaFile } from './chunk-KRT4NL3H.js';
2
+ import { ThreeUsdRobot } from './chunk-HDZGWL6P.js';
4
3
  import { resolveBoundMaterial, DefaultAssetResolver } from './chunk-PPPRB6KE.js';
5
- import * as THREE from 'three';
4
+ import { isCamera, readCameraDescription, computeWorldTransform, computeLocalTransform } from './chunk-ZQXYVBQI.js';
5
+ import { identity4, multiply } from './chunk-IAOPNN6V.js';
6
+ import * as THREE3 from 'three';
6
7
 
8
+ // src/three/stageAnchors.ts
9
+ function collectAnchors(robot3d) {
10
+ const anchors = /* @__PURE__ */ new Map();
11
+ robot3d.traverse((object) => {
12
+ const path = object.userData.primPath;
13
+ if (typeof path === "string" && !anchors.has(path)) anchors.set(path, object);
14
+ });
15
+ for (const [path, link] of robot3d.getLinkObjectsByPath()) anchors.set(path, link);
16
+ return anchors;
17
+ }
18
+ function findAnchor(prim, anchors) {
19
+ for (let p = prim.GetParent(); p && !p.IsPseudoRoot(); p = p.GetParent()) {
20
+ const object = anchors.get(p.GetPath());
21
+ if (object) return { object, prim: p };
22
+ }
23
+ return null;
24
+ }
25
+ function transformFrom(anchorPrim, prim) {
26
+ const stop = anchorPrim?.GetPath();
27
+ const chain = [];
28
+ for (let p = prim; p && !p.IsPseudoRoot() && p.GetPath() !== stop; p = p.GetParent()) {
29
+ chain.push(p);
30
+ }
31
+ chain.reverse();
32
+ let m = identity4();
33
+ for (const link of chain) m = multiply(m, computeLocalTransform(link).matrix);
34
+ return m;
35
+ }
36
+ function worldScaleOf(prim, rootScale) {
37
+ const m = computeWorldTransform(prim);
38
+ const sx = Math.hypot(m[0], m[1], m[2]);
39
+ const sy = Math.hypot(m[4], m[5], m[6]);
40
+ const sz = Math.hypot(m[8], m[9], m[10]);
41
+ return rootScale * ((sx + sy + sz) / 3);
42
+ }
43
+ function attachAtPrim(object, prim, anchors, robot3d) {
44
+ const anchor = findAnchor(prim, anchors);
45
+ object.matrixAutoUpdate = false;
46
+ object.matrix.fromArray(transformFrom(anchor?.prim ?? null, prim));
47
+ object.matrixWorldNeedsUpdate = true;
48
+ (anchor?.object ?? robot3d).add(object);
49
+ }
50
+
51
+ // src/three/CameraBinding.ts
52
+ function bindCameras(stage, robot3d, options = {}) {
53
+ const cameras = [];
54
+ const anchors = collectAnchors(robot3d);
55
+ const rootScale = robot3d.scale.x || 1;
56
+ for (const prim of stage.Traverse()) {
57
+ if (!isCamera(prim)) continue;
58
+ if (prim.GetAttribute("visibility").Get() === "invisible") continue;
59
+ if (isNonVisualPurpose(prim)) continue;
60
+ const desc = readCameraDescription(prim);
61
+ if (!desc) continue;
62
+ const worldScale = worldScaleOf(prim, rootScale);
63
+ const camera = createThreeCamera(desc, worldScale, options.onWarn);
64
+ camera.name = desc.name;
65
+ camera.userData.kind = "camera";
66
+ camera.userData.primPath = desc.primPath;
67
+ camera.userData.usdCamera = desc;
68
+ camera.userData.usdCameraWorldScale = worldScale;
69
+ attachAtPrim(camera, prim, anchors, robot3d);
70
+ cameras.push(camera);
71
+ }
72
+ return cameras;
73
+ }
74
+ function createThreeCamera(desc, worldScale, onWarn) {
75
+ const near = Math.max(desc.clippingRange[0] * worldScale, 1e-5);
76
+ const far = Math.max(desc.clippingRange[1] * worldScale, near + 1e-5);
77
+ if (desc.projection === "orthographic") {
78
+ const halfWidth = desc.horizontalAperture / 10 / 2 * worldScale;
79
+ const halfHeight = desc.verticalAperture / 10 / 2 * worldScale;
80
+ return new THREE3.OrthographicCamera(-halfWidth, halfWidth, halfHeight, -halfHeight, near, far);
81
+ }
82
+ const camera = new THREE3.PerspectiveCamera(
83
+ THREE3.MathUtils.radToDeg(2 * Math.atan(desc.verticalAperture / (2 * desc.focalLength))),
84
+ desc.horizontalAperture / desc.verticalAperture,
85
+ near,
86
+ far
87
+ );
88
+ camera.filmGauge = desc.horizontalAperture;
89
+ camera.filmOffset = desc.horizontalApertureOffset;
90
+ if (desc.verticalApertureOffset !== 0) {
91
+ onWarn?.(
92
+ `Camera ${desc.primPath} authors a verticalApertureOffset; Three.js has no vertical film offset \u2014 ignored`
93
+ );
94
+ }
95
+ if (desc.focusDistance > 0) camera.focus = desc.focusDistance * worldScale;
96
+ camera.updateProjectionMatrix();
97
+ return camera;
98
+ }
99
+ function conformCameraAspect(camera, viewportAspect, policy = "expandAperture") {
100
+ const desc = camera.userData.usdCamera;
101
+ if (camera.isOrthographicCamera) {
102
+ const ortho = camera;
103
+ const worldScale = camera.userData.usdCameraWorldScale ?? 1;
104
+ const halfWidth = desc ? desc.horizontalAperture / 10 / 2 * worldScale : ortho.right;
105
+ const halfHeight = desc ? desc.verticalAperture / 10 / 2 * worldScale : ortho.top;
106
+ if (widthFollows(policy, viewportAspect, halfWidth / halfHeight)) {
107
+ ortho.top = halfHeight;
108
+ ortho.bottom = -halfHeight;
109
+ ortho.right = halfHeight * viewportAspect;
110
+ ortho.left = -ortho.right;
111
+ } else {
112
+ ortho.right = halfWidth;
113
+ ortho.left = -halfWidth;
114
+ ortho.top = halfWidth / viewportAspect;
115
+ ortho.bottom = -ortho.top;
116
+ }
117
+ ortho.updateProjectionMatrix();
118
+ return;
119
+ }
120
+ const persp = camera;
121
+ persp.aspect = viewportAspect;
122
+ if (desc) {
123
+ const vFov = 2 * Math.atan(desc.verticalAperture / (2 * desc.focalLength));
124
+ const hFov = 2 * Math.atan(desc.horizontalAperture / (2 * desc.focalLength));
125
+ const apertureAspect = desc.horizontalAperture / desc.verticalAperture;
126
+ persp.fov = THREE3.MathUtils.radToDeg(
127
+ widthFollows(policy, viewportAspect, apertureAspect) ? vFov : 2 * Math.atan(Math.tan(hFov / 2) / viewportAspect)
128
+ // keep the horizontal view
129
+ );
130
+ }
131
+ persp.updateProjectionMatrix();
132
+ }
133
+ function widthFollows(policy, viewportAspect, apertureAspect) {
134
+ switch (policy) {
135
+ case "adjustApertureWidth":
136
+ return true;
137
+ case "adjustApertureHeight":
138
+ return false;
139
+ case "expandAperture":
140
+ return viewportAspect >= apertureAspect;
141
+ case "cropAperture":
142
+ return viewportAspect < apertureAspect;
143
+ }
144
+ }
145
+ function bindLights(stage, robot3d, options = {}) {
146
+ const intensityScale = options.lightIntensityScale ?? 1;
147
+ const shadows = options.shadows ?? false;
148
+ const lights = [];
149
+ const domes = [];
150
+ const warned = /* @__PURE__ */ new Set();
151
+ const warnOnce = (key, message) => {
152
+ if (warned.has(key)) return;
153
+ warned.add(key);
154
+ options.onWarn?.(message);
155
+ };
156
+ const anchors = collectAnchors(robot3d);
157
+ const rootScale = robot3d.scale.x || 1;
158
+ let metrics = null;
159
+ const sceneMetrics = () => {
160
+ if (!metrics) {
161
+ const box = new THREE3.Box3().setFromObject(robot3d);
162
+ const sphere = new THREE3.Sphere();
163
+ if (!box.isEmpty()) box.getBoundingSphere(sphere);
164
+ metrics = { center: sphere.center.clone(), radius: Math.max(sphere.radius, 0.5) };
165
+ }
166
+ return metrics;
167
+ };
168
+ for (const prim of stage.Traverse()) {
169
+ if (isUnsupportedLight(prim)) {
170
+ warnOnce(
171
+ prim.GetTypeName(),
172
+ `${prim.GetTypeName()} lights are not supported yet; skipping (e.g. ${prim.GetPath()})`
173
+ );
174
+ continue;
175
+ }
176
+ if (!getLightKind(prim)) continue;
177
+ if (prim.GetAttribute("visibility").Get() === "invisible") continue;
178
+ if (isNonVisualPurpose(prim)) continue;
179
+ const desc = readLightDescription(prim);
180
+ if (!desc) continue;
181
+ if (desc.kind === "dome") {
182
+ domes.push(desc);
183
+ warnOnce(
184
+ "DomeLight",
185
+ `DomeLight ${desc.primPath} is surfaced on robot.domeLights \u2014 apply it as the scene environment with applyUsdEnvironment from three-usd-robot/rendering`
186
+ );
187
+ continue;
188
+ }
189
+ const light = createThreeLight(desc, worldScaleOf(prim, rootScale), intensityScale, warnOnce);
190
+ if (!light) continue;
191
+ light.name = desc.name;
192
+ light.userData.kind = "light";
193
+ light.userData.primPath = desc.primPath;
194
+ light.userData.usdLight = desc;
195
+ attachAtPrim(light, prim, anchors, robot3d);
196
+ if (shadows) configureShadow(light, desc, prim, rootScale, robot3d, sceneMetrics);
197
+ lights.push(light);
198
+ }
199
+ return { lights, domes };
200
+ }
201
+ function aimAlongMinusZ(light) {
202
+ const target = new THREE3.Object3D();
203
+ target.name = "target";
204
+ target.position.set(0, 0, -1);
205
+ light.add(target);
206
+ light.target = target;
207
+ }
208
+ function createThreeLight(desc, worldScale, intensityScale, warnOnce) {
209
+ const color = new THREE3.Color(desc.color[0], desc.color[1], desc.color[2]);
210
+ const intensity = desc.intensity * intensityScale;
211
+ switch (desc.kind) {
212
+ case "distant": {
213
+ const light = new THREE3.DirectionalLight(color, intensity);
214
+ aimAlongMinusZ(light);
215
+ return light;
216
+ }
217
+ case "sphere": {
218
+ if (desc.cone) {
219
+ const angle = THREE3.MathUtils.degToRad(Math.min(desc.cone.angleDeg, 89.9));
220
+ const penumbra = Math.min(Math.max(desc.cone.softness, 0), 1);
221
+ const light = new THREE3.SpotLight(color, intensity, 0, angle, penumbra);
222
+ aimAlongMinusZ(light);
223
+ return light;
224
+ }
225
+ return new THREE3.PointLight(color, intensity);
226
+ }
227
+ case "rect": {
228
+ const width = (desc.width ?? 1) * worldScale;
229
+ const height = (desc.height ?? 1) * worldScale;
230
+ return new THREE3.RectAreaLight(color, intensity, width, height);
231
+ }
232
+ case "disk": {
233
+ const side = 2 * (desc.radius ?? 0.5) * worldScale;
234
+ return new THREE3.RectAreaLight(color, intensity * (Math.PI / 4), side, side);
235
+ }
236
+ case "cylinder":
237
+ warnOnce(
238
+ "CylinderLight",
239
+ `CylinderLight has no Three.js equivalent; approximating as a point light (e.g. ${desc.primPath})`
240
+ );
241
+ return new THREE3.PointLight(color, intensity);
242
+ case "dome":
243
+ return null;
244
+ }
245
+ }
246
+ function configureShadow(light, desc, prim, rootScale, robot3d, sceneMetrics) {
247
+ const directionalOrSpot = light.isDirectionalLight || light.isSpotLight;
248
+ const cast = directionalOrSpot ? desc.shadowEnabled : light.isPointLight && desc.shadowAuthored && desc.shadowEnabled;
249
+ if (!cast) return;
250
+ const { center, radius } = sceneMetrics();
251
+ const m = computeWorldTransform(prim);
252
+ const position = new THREE3.Vector3(m[12], m[13], m[14]).multiplyScalar(rootScale).applyQuaternion(robot3d.quaternion);
253
+ const distance = position.distanceTo(center);
254
+ light.castShadow = true;
255
+ if (light.isDirectionalLight) {
256
+ const shadow = light.shadow;
257
+ shadow.normalBias = 0.02 * radius;
258
+ const camera = shadow.camera;
259
+ const extent = radius * 1.5;
260
+ camera.left = -extent;
261
+ camera.right = extent;
262
+ camera.top = extent;
263
+ camera.bottom = -extent;
264
+ camera.near = distance - 2.5 * radius;
265
+ camera.far = distance + 2.5 * radius;
266
+ camera.updateProjectionMatrix();
267
+ shadow.mapSize.set(2048, 2048);
268
+ } else if (light.isSpotLight) {
269
+ const shadow = light.shadow;
270
+ shadow.normalBias = 0.02 * radius;
271
+ shadow.camera.near = radius / 100;
272
+ shadow.camera.far = distance + 2.5 * radius;
273
+ shadow.camera.updateProjectionMatrix();
274
+ shadow.mapSize.set(1024, 1024);
275
+ } else {
276
+ const shadow = light.shadow;
277
+ shadow.normalBias = 0.02 * radius;
278
+ shadow.camera.near = radius / 100;
279
+ shadow.camera.far = Math.max(4 * radius, distance + 2 * radius);
280
+ shadow.camera.updateProjectionMatrix();
281
+ shadow.mapSize.set(512, 512);
282
+ }
283
+ }
7
284
  var DEFAULT_COLOR = 10132122;
8
285
  function readPrimvar(meshPrim, attrName, isTuple, lens) {
9
286
  const attr = meshPrim.GetAttribute(attrName);
@@ -79,8 +356,8 @@ function buildMeshGeometry(meshPrim) {
79
356
  return expand ? buildExpandedGeometry(meshPrim, points, counts, indices, uvSets, normals, color) : buildIndexedGeometry(meshPrim, points, counts, indices, uvSets, normals, color);
80
357
  }
81
358
  function buildIndexedGeometry(meshPrim, points, counts, indices, uvSets, normals, color) {
82
- const geometry = new THREE.BufferGeometry();
83
- geometry.setAttribute("position", new THREE.Float32BufferAttribute(flat3(points), 3));
359
+ const geometry = new THREE3.BufferGeometry();
360
+ geometry.setAttribute("position", new THREE3.Float32BufferAttribute(flat3(points), 3));
84
361
  if (counts && indices) {
85
362
  const subsets = getMaterialSubsets(meshPrim);
86
363
  if (subsets.length > 0) {
@@ -94,7 +371,7 @@ function buildIndexedGeometry(meshPrim, points, counts, indices, uvSets, normals
94
371
  if (normals?.interpolation === "vertex") {
95
372
  geometry.setAttribute(
96
373
  "normal",
97
- new THREE.Float32BufferAttribute(flat3(normals.values.slice(0, points.length)), 3)
374
+ new THREE3.Float32BufferAttribute(flat3(normals.values.slice(0, points.length)), 3)
98
375
  );
99
376
  } else {
100
377
  geometry.computeVertexNormals();
@@ -103,13 +380,13 @@ function buildIndexedGeometry(meshPrim, points, counts, indices, uvSets, normals
103
380
  if (uv?.interpolation !== "vertex") continue;
104
381
  geometry.setAttribute(
105
382
  uvAttrName(i),
106
- new THREE.Float32BufferAttribute(flat2(uv.values.slice(0, points.length)), 2)
383
+ new THREE3.Float32BufferAttribute(flat2(uv.values.slice(0, points.length)), 2)
107
384
  );
108
385
  }
109
386
  if (color?.interpolation === "vertex") {
110
387
  geometry.setAttribute(
111
388
  "color",
112
- new THREE.Float32BufferAttribute(flat3(color.values.slice(0, points.length)), 3)
389
+ new THREE3.Float32BufferAttribute(flat3(color.values.slice(0, points.length)), 3)
113
390
  );
114
391
  }
115
392
  return geometry;
@@ -128,7 +405,7 @@ function buildExpandedGeometry(meshPrim, points, counts, indices, uvSets, normal
128
405
  return p.values[0];
129
406
  }
130
407
  };
131
- const geometry = new THREE.BufferGeometry();
408
+ const geometry = new THREE3.BufferGeometry();
132
409
  const position = new Array(slots.length * 3);
133
410
  for (let c = 0; c < slots.length; c++) {
134
411
  const v = points[indices[slots[c]]] ?? [0, 0, 0];
@@ -136,7 +413,7 @@ function buildExpandedGeometry(meshPrim, points, counts, indices, uvSets, normal
136
413
  position[c * 3 + 1] = v[1];
137
414
  position[c * 3 + 2] = v[2];
138
415
  }
139
- geometry.setAttribute("position", new THREE.Float32BufferAttribute(position, 3));
416
+ geometry.setAttribute("position", new THREE3.Float32BufferAttribute(position, 3));
140
417
  for (const [i, uv] of uvSets.entries()) {
141
418
  if (!uv || uv.interpolation === "constant") continue;
142
419
  const out = new Array(slots.length * 2);
@@ -145,7 +422,7 @@ function buildExpandedGeometry(meshPrim, points, counts, indices, uvSets, normal
145
422
  out[c * 2] = t[0] ?? 0;
146
423
  out[c * 2 + 1] = t[1] ?? 0;
147
424
  }
148
- geometry.setAttribute(uvAttrName(i), new THREE.Float32BufferAttribute(out, 2));
425
+ geometry.setAttribute(uvAttrName(i), new THREE3.Float32BufferAttribute(out, 2));
149
426
  }
150
427
  const emitVec3 = (p, name) => {
151
428
  const out = new Array(slots.length * 3);
@@ -155,7 +432,7 @@ function buildExpandedGeometry(meshPrim, points, counts, indices, uvSets, normal
155
432
  out[c * 3 + 1] = t[1] ?? 0;
156
433
  out[c * 3 + 2] = t[2] ?? 0;
157
434
  }
158
- geometry.setAttribute(name, new THREE.Float32BufferAttribute(out, 3));
435
+ geometry.setAttribute(name, new THREE3.Float32BufferAttribute(out, 3));
159
436
  };
160
437
  if (normals && normals.interpolation !== "constant") emitVec3(normals, "normal");
161
438
  else geometry.computeVertexNormals();
@@ -212,24 +489,24 @@ function buildGprimGeometry(prim) {
212
489
  return buildMeshGeometry(prim);
213
490
  case "Cube": {
214
491
  const size = getNumber(prim, "size") ?? 2;
215
- return new THREE.BoxGeometry(size, size, size);
492
+ return new THREE3.BoxGeometry(size, size, size);
216
493
  }
217
494
  case "Sphere":
218
- return new THREE.SphereGeometry(getNumber(prim, "radius") ?? 1, 32, 16);
495
+ return new THREE3.SphereGeometry(getNumber(prim, "radius") ?? 1, 32, 16);
219
496
  case "Cylinder": {
220
497
  const radius = getNumber(prim, "radius") ?? 1;
221
498
  const height = getNumber(prim, "height") ?? 2;
222
- return orientSpine(new THREE.CylinderGeometry(radius, radius, height, 32), prim);
499
+ return orientSpine(new THREE3.CylinderGeometry(radius, radius, height, 32), prim);
223
500
  }
224
501
  case "Capsule": {
225
502
  const radius = getNumber(prim, "radius") ?? 0.5;
226
503
  const height = getNumber(prim, "height") ?? 1;
227
- return orientSpine(new THREE.CapsuleGeometry(radius, height, 8, 32), prim);
504
+ return orientSpine(new THREE3.CapsuleGeometry(radius, height, 8, 32), prim);
228
505
  }
229
506
  case "Cone": {
230
507
  const radius = getNumber(prim, "radius") ?? 1;
231
508
  const height = getNumber(prim, "height") ?? 2;
232
- return orientSpine(new THREE.ConeGeometry(radius, height, 32), prim);
509
+ return orientSpine(new THREE3.ConeGeometry(radius, height, 32), prim);
233
510
  }
234
511
  default:
235
512
  return null;
@@ -245,15 +522,25 @@ function buildGprimObject(prim, stage, options = {}) {
245
522
  const geometry = buildGprimGeometry(prim);
246
523
  if (!geometry) return null;
247
524
  const custom = stage && options.materialFactory ? options.materialFactory(prim, stage) : null;
248
- return new THREE.Mesh(
525
+ const mesh = new THREE3.Mesh(
249
526
  geometry,
250
527
  custom ?? buildMeshMaterials(prim, stage, options.textureProvider, options.onWarn, options.mdl)
251
528
  );
529
+ if (options.shadows) applyShadowFlags(mesh);
530
+ return mesh;
252
531
  }
253
532
  }
254
533
  }
534
+ function applyShadowFlags(mesh) {
535
+ mesh.receiveShadow = true;
536
+ const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
537
+ mesh.castShadow = materials.some((material) => {
538
+ const transmission = material.transmission ?? 0;
539
+ return !material.transparent && transmission === 0;
540
+ });
541
+ }
255
542
  function resolveFlatColor(prim, stage, mdl) {
256
- const color = new THREE.Color(DEFAULT_COLOR);
543
+ const color = new THREE3.Color(DEFAULT_COLOR);
257
544
  const bound = stage ? resolveBoundMaterial(stage, prim, mdl ? { mdl } : {}) : void 0;
258
545
  if (bound?.color) {
259
546
  color.setRGB(bound.color[0], bound.color[1], bound.color[2]);
@@ -278,10 +565,10 @@ function meanWidth(prim) {
278
565
  function buildPointsObject(prim, stage, mdl) {
279
566
  const points = prim.GetAttribute("points").Get();
280
567
  if (!isVec3Array(points) || points.length === 0) return null;
281
- const geometry = new THREE.BufferGeometry();
282
- geometry.setAttribute("position", new THREE.Float32BufferAttribute(flat3(points), 3));
568
+ const geometry = new THREE3.BufferGeometry();
569
+ geometry.setAttribute("position", new THREE3.Float32BufferAttribute(flat3(points), 3));
283
570
  const flat = resolveFlatColor(prim, stage, mdl);
284
- const material = new THREE.PointsMaterial({ color: flat.color });
571
+ const material = new THREE3.PointsMaterial({ color: flat.color });
285
572
  if (flat.opacity < 1) {
286
573
  material.transparent = true;
287
574
  material.opacity = flat.opacity;
@@ -289,7 +576,7 @@ function buildPointsObject(prim, stage, mdl) {
289
576
  if (flat.name) material.name = flat.name;
290
577
  const displayColor = prim.GetAttribute("primvars:displayColor").Get();
291
578
  if (isVec3Array(displayColor) && displayColor.length === points.length && points.length > 1) {
292
- geometry.setAttribute("color", new THREE.Float32BufferAttribute(flat3(displayColor), 3));
579
+ geometry.setAttribute("color", new THREE3.Float32BufferAttribute(flat3(displayColor), 3));
293
580
  material.vertexColors = true;
294
581
  material.color.set(16777215);
295
582
  }
@@ -301,7 +588,7 @@ function buildPointsObject(prim, stage, mdl) {
301
588
  material.size = 3;
302
589
  material.sizeAttenuation = false;
303
590
  }
304
- return new THREE.Points(geometry, material);
591
+ return new THREE3.Points(geometry, material);
305
592
  }
306
593
  var CURVE_DIVISIONS = 8;
307
594
  var CUBIC_BASES = {
@@ -363,10 +650,10 @@ function sampleCubicCurve(cvs, basisName, periodic) {
363
650
  return out;
364
651
  }
365
652
  function polylinePath(samples, closed) {
366
- const path = new THREE.CurvePath();
367
- const vecs = samples.map(([x, y, z]) => new THREE.Vector3(x, y, z));
368
- for (let i = 0; i < vecs.length - 1; i++) path.add(new THREE.LineCurve3(vecs[i], vecs[i + 1]));
369
- if (closed) path.add(new THREE.LineCurve3(vecs[vecs.length - 1], vecs[0]));
653
+ const path = new THREE3.CurvePath();
654
+ const vecs = samples.map(([x, y, z]) => new THREE3.Vector3(x, y, z));
655
+ for (let i = 0; i < vecs.length - 1; i++) path.add(new THREE3.LineCurve3(vecs[i], vecs[i + 1]));
656
+ if (closed) path.add(new THREE3.LineCurve3(vecs[vecs.length - 1], vecs[0]));
370
657
  return path;
371
658
  }
372
659
  function buildBasisCurvesObject(prim, stage, curveTubes, mdl) {
@@ -379,13 +666,13 @@ function buildBasisCurvesObject(prim, stage, curveTubes, mdl) {
379
666
  const flat = resolveFlatColor(prim, stage, mdl);
380
667
  const width = meanWidth(prim);
381
668
  const asTubes = curveTubes && width !== void 0 && width > 0;
382
- const material = asTubes ? new THREE.MeshStandardMaterial({ color: flat.color, roughness: 0.8, metalness: 0.1 }) : new THREE.LineBasicMaterial({ color: flat.color });
669
+ const material = asTubes ? new THREE3.MeshStandardMaterial({ color: flat.color, roughness: 0.8, metalness: 0.1 }) : new THREE3.LineBasicMaterial({ color: flat.color });
383
670
  if (flat.opacity < 1) {
384
671
  material.transparent = true;
385
672
  material.opacity = flat.opacity;
386
673
  }
387
674
  if (flat.name) material.name = flat.name;
388
- const group = new THREE.Group();
675
+ const group = new THREE3.Group();
389
676
  let offset = 0;
390
677
  for (const count of counts) {
391
678
  const cvs = points.slice(offset, offset + count);
@@ -394,19 +681,19 @@ function buildBasisCurvesObject(prim, stage, curveTubes, mdl) {
394
681
  if (!samples || samples.length < 2) continue;
395
682
  if (asTubes) {
396
683
  const path = polylinePath(samples, periodic);
397
- const geometry = new THREE.TubeGeometry(
684
+ const geometry = new THREE3.TubeGeometry(
398
685
  path,
399
686
  Math.max(samples.length, 2),
400
687
  width / 2,
401
688
  8,
402
689
  periodic
403
690
  );
404
- group.add(new THREE.Mesh(geometry, material));
691
+ group.add(new THREE3.Mesh(geometry, material));
405
692
  } else {
406
- const geometry = new THREE.BufferGeometry();
407
- geometry.setAttribute("position", new THREE.Float32BufferAttribute(flat3(samples), 3));
693
+ const geometry = new THREE3.BufferGeometry();
694
+ geometry.setAttribute("position", new THREE3.Float32BufferAttribute(flat3(samples), 3));
408
695
  group.add(
409
- periodic ? new THREE.LineLoop(geometry, material) : new THREE.Line(geometry, material)
696
+ periodic ? new THREE3.LineLoop(geometry, material) : new THREE3.Line(geometry, material)
410
697
  );
411
698
  }
412
699
  }
@@ -423,7 +710,7 @@ function orientSpine(geometry, prim) {
423
710
  return geometry.rotateX(Math.PI / 2);
424
711
  }
425
712
  function buildMeshMaterial(meshPrim, stage, textures, bindingPrim, onWarn, mdl) {
426
- const color = new THREE.Color(DEFAULT_COLOR);
713
+ const color = new THREE3.Color(DEFAULT_COLOR);
427
714
  let opacity = 1;
428
715
  let vertexColors = false;
429
716
  const resolveOptions = {
@@ -485,7 +772,7 @@ function buildMeshMaterial(meshPrim, stage, textures, bindingPrim, onWarn, mdl)
485
772
  const emissiveMap = tex(bound?.emissiveTexture, "srgb");
486
773
  const metalness = bound?.metalness ?? bound?.metalnessTexture?.scale?.[0] ?? (metalnessMap ? 1 : 0.1);
487
774
  const roughness = bound?.roughness ?? bound?.roughnessTexture?.scale?.[0] ?? (roughnessMap ? 1 : 0.8);
488
- const emissive = new THREE.Color(0);
775
+ const emissive = new THREE3.Color(0);
489
776
  if (bound?.emissiveColor) {
490
777
  emissive.setRGB(bound.emissiveColor[0], bound.emissiveColor[1], bound.emissiveColor[2]);
491
778
  } else if (emissiveMap) {
@@ -508,7 +795,7 @@ function buildMeshMaterial(meshPrim, stage, textures, bindingPrim, onWarn, mdl)
508
795
  opacity,
509
796
  ...vertexColors ? { vertexColors: true } : {},
510
797
  ...alphaTest > 0 ? { alphaTest } : {},
511
- side: doubleSided ? THREE.DoubleSide : THREE.FrontSide,
798
+ side: doubleSided ? THREE3.DoubleSide : THREE3.FrontSide,
512
799
  ...map ? { map } : {},
513
800
  ...alphaMap ? { alphaMap } : {},
514
801
  ...normalMap ? { normalMap } : {},
@@ -518,8 +805,8 @@ function buildMeshMaterial(meshPrim, stage, textures, bindingPrim, onWarn, mdl)
518
805
  ...emissiveMap ? { emissiveMap } : {}
519
806
  };
520
807
  const physical = bound !== void 0 && (bound.ior !== void 0 || bound.clearcoat !== void 0 || bound.clearcoatRoughness !== void 0 || bound.specularColor !== void 0 || bound.transmission !== void 0 || bound.clearcoatNormalTexture !== void 0);
521
- const material = physical ? new THREE.MeshPhysicalMaterial(params) : new THREE.MeshStandardMaterial(params);
522
- if (material instanceof THREE.MeshPhysicalMaterial && bound) {
808
+ const material = physical ? new THREE3.MeshPhysicalMaterial(params) : new THREE3.MeshStandardMaterial(params);
809
+ if (material instanceof THREE3.MeshPhysicalMaterial && bound) {
523
810
  if (bound.ior !== void 0) material.ior = bound.ior;
524
811
  if (bound.clearcoat !== void 0) material.clearcoat = bound.clearcoat;
525
812
  if (bound.clearcoatRoughness !== void 0)
@@ -551,7 +838,8 @@ function bindRobotMeshes(stage, robot3d, desc, options = {}) {
551
838
  ...options.curveTubes ? { curveTubes: true } : {},
552
839
  ...options.onWarn ? { onWarn: options.onWarn } : {},
553
840
  ...options.mdl ? { mdl: options.mdl } : {},
554
- ...options.materialFactory ? { materialFactory: options.materialFactory } : {}
841
+ ...options.materialFactory ? { materialFactory: options.materialFactory } : {},
842
+ ...options.shadows ? { shadows: true } : {}
555
843
  };
556
844
  for (const [key, link] of Object.entries(desc.links)) {
557
845
  const linkObj = robot3d.getLinkObject(key);
@@ -584,7 +872,7 @@ function bindSceneMeshes(stage, robot3d, desc, options = {}) {
584
872
  if (!parent || parent.IsPseudoRoot()) return robot3d;
585
873
  let node = nodes.get(parent.GetPath());
586
874
  if (!node) {
587
- node = new THREE.Group();
875
+ node = new THREE3.Group();
588
876
  node.name = parent.GetName();
589
877
  node.userData.kind = "scene";
590
878
  node.userData.primPath = parent.GetPath();
@@ -599,7 +887,8 @@ function bindSceneMeshes(stage, robot3d, desc, options = {}) {
599
887
  ...options.curveTubes ? { curveTubes: true } : {},
600
888
  ...options.onWarn ? { onWarn: options.onWarn } : {},
601
889
  ...options.mdl ? { mdl: options.mdl } : {},
602
- ...options.materialFactory ? { materialFactory: options.materialFactory } : {}
890
+ ...options.materialFactory ? { materialFactory: options.materialFactory } : {},
891
+ ...options.shadows ? { shadows: true } : {}
603
892
  };
604
893
  let attached = 0;
605
894
  for (const prim of stage.Traverse()) {
@@ -640,7 +929,11 @@ function attachGprim(stage, linkPrim, meshPath, parent, kind, options) {
640
929
  object.name = meshPrim.GetName();
641
930
  object.userData.kind = kind;
642
931
  object.userData.primPath = meshPath;
643
- if (kind === "collision") object.visible = false;
932
+ if (kind === "collision") {
933
+ object.visible = false;
934
+ object.castShadow = false;
935
+ object.receiveShadow = false;
936
+ }
644
937
  object.matrixAutoUpdate = false;
645
938
  object.matrix.fromArray(relativeTransform(linkPrim, meshPrim));
646
939
  object.matrixWorldNeedsUpdate = true;
@@ -739,8 +1032,9 @@ function isVec2Array(v) {
739
1032
  return Array.isArray(v) && v.every((e) => Array.isArray(e) && e.length === 2);
740
1033
  }
741
1034
  var DEG2RAD = Math.PI / 180;
742
- function createTextureProvider(resolver, baseUrl) {
1035
+ function createTextureProvider(resolver, baseUrl, onWarn) {
743
1036
  const images = /* @__PURE__ */ new Map();
1037
+ let warnedUdim = false;
744
1038
  const imageFor = (url) => {
745
1039
  let p = images.get(url);
746
1040
  if (!p) {
@@ -750,14 +1044,22 @@ function createTextureProvider(resolver, baseUrl) {
750
1044
  return p;
751
1045
  };
752
1046
  return (assetPath, options = {}) => {
1047
+ let path = assetPath;
1048
+ if (/<UDIM>/i.test(path)) {
1049
+ path = path.replace(/<UDIM>/gi, "1001");
1050
+ if (!warnedUdim) {
1051
+ warnedUdim = true;
1052
+ onWarn?.(`UDIM texture sets are not supported; using tile 1001 only (e.g. ${path})`);
1053
+ }
1054
+ }
753
1055
  let url;
754
1056
  try {
755
- url = resolver.resolve(assetPath, baseUrl);
1057
+ url = resolver.resolve(path, baseUrl);
756
1058
  } catch {
757
1059
  return null;
758
1060
  }
759
- const texture = new THREE.Texture();
760
- texture.colorSpace = options.colorSpace === "linear" ? THREE.NoColorSpace : THREE.SRGBColorSpace;
1061
+ const texture = new THREE3.Texture();
1062
+ texture.colorSpace = options.colorSpace === "linear" ? THREE3.NoColorSpace : THREE3.SRGBColorSpace;
761
1063
  texture.wrapS = toThreeWrap(options.wrapS);
762
1064
  texture.wrapT = toThreeWrap(options.wrapT);
763
1065
  if (options.channel !== void 0) texture.channel = options.channel;
@@ -789,11 +1091,11 @@ function toThreeWrap(wrap) {
789
1091
  switch (wrap) {
790
1092
  case "clamp":
791
1093
  case "black":
792
- return THREE.ClampToEdgeWrapping;
1094
+ return THREE3.ClampToEdgeWrapping;
793
1095
  case "mirror":
794
- return THREE.MirroredRepeatWrapping;
1096
+ return THREE3.MirroredRepeatWrapping;
795
1097
  default:
796
- return THREE.RepeatWrapping;
1098
+ return THREE3.RepeatWrapping;
797
1099
  }
798
1100
  }
799
1101
  function applyTransform(texture, t) {
@@ -884,6 +1186,10 @@ var ThreeUsdRobotLoader = class {
884
1186
  const tree = buildKinematicTree(robot);
885
1187
  const robot3d = new ThreeUsdRobot(robot, tree, this.robotOptions());
886
1188
  robot3d.stage = stage;
1189
+ robot3d.assetContext = { resolver, baseUrl };
1190
+ if (this.options.lightIntensityScale !== void 0) {
1191
+ robot3d.lightIntensityScale = this.options.lightIntensityScale;
1192
+ }
887
1193
  const loadVisuals = this.options.loadVisuals ?? true;
888
1194
  const loadCollisions = this.options.loadCollisions ?? false;
889
1195
  const isStaticScene = Object.keys(robot.links).length === 0 && Object.keys(robot.joints).length === 0;
@@ -893,10 +1199,11 @@ var ThreeUsdRobotLoader = class {
893
1199
  );
894
1200
  }
895
1201
  const loadScene = this.options.loadSceneGeometry ?? isStaticScene;
1202
+ const shadows = this.options.shadows ?? true;
1203
+ const onWarn = this.options.onWarn;
896
1204
  if (loadVisuals || loadCollisions || loadScene) {
897
- const textureProvider = this.options.loadTextures ?? true ? createTextureProvider(resolver, baseUrl) : void 0;
1205
+ const textureProvider = this.options.loadTextures ?? true ? createTextureProvider(resolver, baseUrl, onWarn) : void 0;
898
1206
  const curveTubes = this.options.curveTubes ?? false;
899
- const onWarn = this.options.onWarn;
900
1207
  const materialFactory = this.options.materialFactory;
901
1208
  const mdl = await loadMdlModules(stage, resolver, baseUrl);
902
1209
  if (loadVisuals || loadCollisions) {
@@ -907,7 +1214,8 @@ var ThreeUsdRobotLoader = class {
907
1214
  ...curveTubes ? { curveTubes } : {},
908
1215
  ...onWarn ? { onWarn } : {},
909
1216
  ...mdl ? { mdl } : {},
910
- ...materialFactory ? { materialFactory } : {}
1217
+ ...materialFactory ? { materialFactory } : {},
1218
+ ...shadows ? { shadows } : {}
911
1219
  });
912
1220
  }
913
1221
  if (loadScene) {
@@ -916,11 +1224,26 @@ var ThreeUsdRobotLoader = class {
916
1224
  ...curveTubes ? { curveTubes } : {},
917
1225
  ...onWarn ? { onWarn } : {},
918
1226
  ...mdl ? { mdl } : {},
919
- ...materialFactory ? { materialFactory } : {}
1227
+ ...materialFactory ? { materialFactory } : {},
1228
+ ...shadows ? { shadows } : {}
920
1229
  });
921
1230
  }
922
1231
  this.warnUnsupportedGprims(stage);
923
1232
  }
1233
+ if (this.options.loadLights ?? true) {
1234
+ const bound = bindLights(stage, robot3d, {
1235
+ ...this.options.lightIntensityScale !== void 0 ? { lightIntensityScale: this.options.lightIntensityScale } : {},
1236
+ ...shadows ? { shadows } : {},
1237
+ ...onWarn ? { onWarn } : {}
1238
+ });
1239
+ robot3d.lights = bound.lights;
1240
+ robot3d.domeLights = bound.domes;
1241
+ }
1242
+ if (this.options.loadCameras ?? true) {
1243
+ robot3d.cameras = bindCameras(stage, robot3d, {
1244
+ ...onWarn ? { onWarn } : {}
1245
+ });
1246
+ }
924
1247
  return robot3d;
925
1248
  }
926
1249
  /** Surface recognized-but-unrenderable gprim schemas instead of silence (M18). */
@@ -968,6 +1291,6 @@ var ThreeUsdRobotLoader = class {
968
1291
  }
969
1292
  };
970
1293
 
971
- export { ThreeUsdRobotLoader, bindRobotMeshes, bindSceneMeshes, buildGprimGeometry, buildGprimObject, buildMeshGeometry, buildMeshMaterial, createTextureProvider };
972
- //# sourceMappingURL=chunk-GRJGPHLW.js.map
973
- //# sourceMappingURL=chunk-GRJGPHLW.js.map
1294
+ export { ThreeUsdRobotLoader, bindCameras, bindLights, bindRobotMeshes, bindSceneMeshes, buildGprimGeometry, buildGprimObject, buildMeshGeometry, buildMeshMaterial, conformCameraAspect, createTextureProvider };
1295
+ //# sourceMappingURL=chunk-WQRP5IDJ.js.map
1296
+ //# sourceMappingURL=chunk-WQRP5IDJ.js.map