@woosh/meep-engine 3.0.0 → 3.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/editor/particles/rebuildParticleEmitter.js +8 -26
- package/editor/process/symbolic/CameraSymbolicDisplay.js +146 -146
- package/editor/tools/SelectionTool.js +1 -2
- package/editor/tools/TransformToolV2.js +2 -3
- package/editor/tools/v2/BlenderCameraOrientationGizmo.js +501 -501
- package/editor/tools/v2/TransformControls.js +1 -1
- package/package.json +95 -96
- package/src/core/geom/3d/mat4/m4_look_at.d.ts +25 -0
- package/src/core/geom/3d/mat4/m4_look_at.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_look_at.js +96 -0
- package/src/core/geom/3d/mat4/m4_make_rotation_x.d.ts +18 -0
- package/src/core/geom/3d/mat4/m4_make_rotation_x.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_make_rotation_x.js +47 -0
- package/src/core/geom/3d/mat4/m4_make_rotation_y.d.ts +18 -0
- package/src/core/geom/3d/mat4/m4_make_rotation_y.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_make_rotation_y.js +47 -0
- package/src/core/geom/3d/mat4/m4_make_rotation_z.d.ts +18 -0
- package/src/core/geom/3d/mat4/m4_make_rotation_z.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_make_rotation_z.js +47 -0
- package/src/core/geom/3d/mat4/m4_perspective.d.ts +25 -0
- package/src/core/geom/3d/mat4/m4_perspective.d.ts.map +1 -0
- package/src/core/geom/3d/mat4/m4_perspective.js +66 -0
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2045 -2052
- package/src/engine/ecs/gui/hud/testHudEdgeStick.js +2 -2
- package/src/engine/ecs/terrain/ecs/TerrainSystem.d.ts.map +1 -1
- package/src/engine/ecs/terrain/ecs/TerrainSystem.js +14 -27
- package/src/engine/ecs/terrain/util/loadVisibleTerrainTiles.d.ts.map +1 -1
- package/src/engine/ecs/terrain/util/loadVisibleTerrainTiles.js +129 -126
- package/src/engine/graphics/ecs/camera/Camera.d.ts +36 -48
- package/src/engine/graphics/ecs/camera/Camera.d.ts.map +1 -1
- package/src/engine/graphics/ecs/camera/Camera.js +165 -303
- package/src/engine/graphics/ecs/camera/camera_active_frustum.d.ts +14 -0
- package/src/engine/graphics/ecs/camera/camera_active_frustum.d.ts.map +1 -0
- package/src/engine/graphics/ecs/camera/camera_active_frustum.js +25 -0
- package/src/engine/graphics/ecs/camera/camera_find_active.d.ts +16 -0
- package/src/engine/graphics/ecs/camera/camera_find_active.d.ts.map +1 -0
- package/src/engine/graphics/ecs/camera/camera_find_active.js +28 -0
- package/src/engine/graphics/ecs/camera/camera_traverse_active.d.ts +12 -0
- package/src/engine/graphics/ecs/camera/camera_traverse_active.d.ts.map +1 -0
- package/src/engine/graphics/ecs/camera/camera_traverse_active.js +18 -0
- package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +170 -170
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +5 -1
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
- package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +296 -281
- package/src/engine/graphics/ecs/render_layers_compute_depth_range.d.ts +1 -1
- package/src/engine/graphics/ecs/render_layers_compute_depth_range.js +1 -1
- package/src/engine/graphics/geometry/AttributeData.d.ts +52 -0
- package/src/engine/graphics/geometry/AttributeData.d.ts.map +1 -0
- package/src/engine/graphics/geometry/AttributeData.js +84 -0
- package/src/engine/graphics/particles/particular/engine/ParticularEngine.d.ts +1 -14
- package/src/engine/graphics/particles/particular/engine/ParticularEngine.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/ParticularEngine.js +229 -253
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +25 -12
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1149 -1194
- package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.d.ts +4 -8
- package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +472 -540
- package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.d.ts +19 -90
- package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.js +135 -514
- package/src/engine/graphics3/CameraSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/CameraSystem3.js +10 -1
- package/src/engine/graphics3/GraphicsEngine3.d.ts +3 -3
- package/src/engine/graphics3/GraphicsEngine3.js +3 -3
- package/src/engine/graphics3/ParticleEmitterSystem3.d.ts +11 -0
- package/src/engine/graphics3/ParticleEmitterSystem3.d.ts.map +1 -1
- package/src/engine/graphics3/ParticleEmitterSystem3.js +289 -265
- package/src/engine/graphics3/ShadeCameraAdapter.d.ts +3 -3
- package/src/engine/graphics3/ShadeCameraAdapter.js +3 -3
- package/src/engine/graphics3/camera_sync_from_transform.d.ts +2 -2
- package/src/engine/graphics3/camera_sync_from_transform.js +2 -2
- package/src/engine/graphics3/shade_camera_projection_ray.js +2 -2
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/shade/renderer/camera/Camera.d.ts +3 -5
- package/src/shade/renderer/camera/Camera.d.ts.map +1 -1
- package/src/shade/renderer/camera/Camera.js +281 -280
- package/src/shade/renderer/camera/GPUCameraContext.js +233 -233
- package/src/shade/renderer/loader/usd/parse_usda.js +1 -1
- package/src/shade/renderer/loader/usd/usd_build_scene.d.ts.map +1 -1
- package/src/shade/renderer/loader/usd/usd_build_scene.js +658 -652
- package/src/shade/renderer/loader/usd/usd_compose_transform.d.ts.map +1 -1
- package/src/shade/renderer/loader/usd/usd_compose_transform.js +58 -23
- package/src/shade/renderer/particles/prototypeParticleSystem.js +450 -443
- package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +7 -3
- package/src/view/minimap/dom/MinimapCameraView.d.ts +2 -2
- package/src/view/minimap/dom/MinimapCameraView.js +206 -206
- package/src/engine/graphics/ecs/camera/CameraSystem.d.ts +0 -74
- package/src/engine/graphics/ecs/camera/CameraSystem.d.ts.map +0 -1
- package/src/engine/graphics/ecs/camera/CameraSystem.js +0 -331
- package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.d.ts +0 -10
- package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.d.ts.map +0 -1
- package/src/engine/graphics/ecs/camera/auto_set_camera_clipping_planes.js +0 -105
- package/src/engine/graphics/ecs/camera/build_three_camera_object.d.ts +0 -7
- package/src/engine/graphics/ecs/camera/build_three_camera_object.d.ts.map +0 -1
- package/src/engine/graphics/ecs/camera/build_three_camera_object.js +0 -29
- package/src/engine/graphics/ecs/camera/frustum_from_camera.d.ts +0 -8
- package/src/engine/graphics/ecs/camera/frustum_from_camera.d.ts.map +0 -1
- package/src/engine/graphics/ecs/camera/frustum_from_camera.js +0 -20
- package/src/engine/graphics/ecs/camera/set_camera_aspect_ratio.d.ts +0 -9
- package/src/engine/graphics/ecs/camera/set_camera_aspect_ratio.d.ts.map +0 -1
- package/src/engine/graphics/ecs/camera/set_camera_aspect_ratio.js +0 -46
- package/src/engine/graphics/ecs/camera/unprojectPoint.d.ts +0 -9
- package/src/engine/graphics/ecs/camera/unprojectPoint.d.ts.map +0 -1
- package/src/engine/graphics/ecs/camera/unprojectPoint.js +0 -14
- package/src/engine/graphics/ecs/camera/update_camera_transform.d.ts +0 -6
- package/src/engine/graphics/ecs/camera/update_camera_transform.d.ts.map +0 -1
- package/src/engine/graphics/ecs/camera/update_camera_transform.js +0 -17
- package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.d.ts +0 -67
- package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.d.ts.map +0 -1
- package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.js +0 -291
- package/src/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.d.ts +0 -11
- package/src/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.d.ts.map +0 -1
- package/src/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +0 -497
- package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.d.ts +0 -40
- package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.d.ts.map +0 -1
- package/src/engine/graphics/particles/particular/engine/shader/MaterialRecord.js +0 -47
- package/src/engine/graphics/texture/sampler/writeSampler2DDataToDataTexture.d.ts +0 -7
- package/src/engine/graphics/texture/sampler/writeSampler2DDataToDataTexture.d.ts.map +0 -1
- package/src/engine/graphics/texture/sampler/writeSampler2DDataToDataTexture.js +0 -40
|
@@ -1,652 +1,658 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Converts the unified `specsByPath` intermediate representation into
|
|
3
|
-
* the engine's scene graph (Node3D, Mesh, StandardShadeMaterial).
|
|
4
|
-
*
|
|
5
|
-
* This module is format-agnostic — it consumes the same specsByPath
|
|
6
|
-
* dictionary regardless of whether the source was USDA, USDC, or USDZ.
|
|
7
|
-
*
|
|
8
|
-
* @see https://openusd.org/release/glossary.html#usdglossary-prim — Prim concept
|
|
9
|
-
* @see https://openusd.org/release/glossary.html#usdglossary-attribute — Attribute concept
|
|
10
|
-
* @see https://openusd.org/release/api/class_usd_geom_mesh.html — UsdGeomMesh schema
|
|
11
|
-
* @see https://openusd.org/release/api/class_usd_preview_surface.html — UsdPreviewSurface
|
|
12
|
-
*
|
|
13
|
-
* @module usd_build_scene
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { clamp01 } from "../../../../core/math/clamp01.js";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// ---
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* @
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
* - `
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* @param {
|
|
214
|
-
* @param {
|
|
215
|
-
* @param {
|
|
216
|
-
* @
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
//
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
if (
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
//
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
//
|
|
475
|
-
const
|
|
476
|
-
if (
|
|
477
|
-
material.
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
//
|
|
481
|
-
const
|
|
482
|
-
if (typeof
|
|
483
|
-
material.
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
//
|
|
487
|
-
const
|
|
488
|
-
if (typeof
|
|
489
|
-
material.
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Converts the unified `specsByPath` intermediate representation into
|
|
3
|
+
* the engine's scene graph (Node3D, Mesh, StandardShadeMaterial).
|
|
4
|
+
*
|
|
5
|
+
* This module is format-agnostic — it consumes the same specsByPath
|
|
6
|
+
* dictionary regardless of whether the source was USDA, USDC, or USDZ.
|
|
7
|
+
*
|
|
8
|
+
* @see https://openusd.org/release/glossary.html#usdglossary-prim — Prim concept
|
|
9
|
+
* @see https://openusd.org/release/glossary.html#usdglossary-attribute — Attribute concept
|
|
10
|
+
* @see https://openusd.org/release/api/class_usd_geom_mesh.html — UsdGeomMesh schema
|
|
11
|
+
* @see https://openusd.org/release/api/class_usd_preview_surface.html — UsdPreviewSurface
|
|
12
|
+
*
|
|
13
|
+
* @module usd_build_scene
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { clamp01 } from "../../../../core/math/clamp01.js";
|
|
17
|
+
import { m4_allocate } from "../../../../core/geom/3d/mat4/m4_allocate.js";
|
|
18
|
+
import { m4_make_rotation_x } from "../../../../core/geom/3d/mat4/m4_make_rotation_x.js";
|
|
19
|
+
import { m4_make_scale } from "../../../../core/geom/3d/mat4/m4_make_scale.js";
|
|
20
|
+
import { m4_multiply } from "../../../../core/geom/3d/mat4/m4_multiply.js";
|
|
21
|
+
import { Attribute } from "../../geometry/Attribute.js";
|
|
22
|
+
import { Geometry } from "../../geometry/Geometry.js";
|
|
23
|
+
import { meshlet_geometry_build_from_geometry } from "../../geometry/meshlet_geometry_build_from_geometry.js";
|
|
24
|
+
import { StandardAttributes } from "../../geometry/StandardAttributes.js";
|
|
25
|
+
import { normalize_attribute } from "../../geometry/util/normalize_attribute.js";
|
|
26
|
+
import { ShadeDrawSide } from "../../material/ShadeDrawSide.js";
|
|
27
|
+
import { StandardShadeMaterial } from "../../material/StandardShadeMaterial.js";
|
|
28
|
+
import { TransparencyMode } from "../../material/TransparencyMode.js";
|
|
29
|
+
import { Mesh } from "../../scene/Mesh.js";
|
|
30
|
+
import { Node3D } from "../../scene/Node3D.js";
|
|
31
|
+
import { usd_compose_transform } from "./usd_compose_transform.js";
|
|
32
|
+
import { usd_expand_face_varying, usd_triangulate } from "./usd_triangulate.js";
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @typedef {Object} UsdBuildOptions
|
|
37
|
+
* @property {Map<string, Uint8Array>} [assetFiles] - Map of relative paths to file data (from USDZ)
|
|
38
|
+
* @property {import("./UsdExtensionRegistry.js").UsdExtensionRegistry} [extensions] - Extension registry consulted per prim
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Build engine Node3D trees from the parsed specsByPath.
|
|
44
|
+
*
|
|
45
|
+
* Stage metadata (upAxis, metersPerUnit) is consumed here and baked
|
|
46
|
+
* into a root correction transform, so the consumer receives a Y-up,
|
|
47
|
+
* meters-scale scene.
|
|
48
|
+
*
|
|
49
|
+
* @param {Object.<string, { specType: number, fields: Object }>} specs_by_path
|
|
50
|
+
* @param {UsdBuildOptions} [options]
|
|
51
|
+
* @returns {Node3D[]} Root-level nodes
|
|
52
|
+
*/
|
|
53
|
+
export function usd_build_scene(specs_by_path, options = {}) {
|
|
54
|
+
|
|
55
|
+
const root_spec = specs_by_path["/"];
|
|
56
|
+
const root_fields = root_spec ? root_spec.fields : {};
|
|
57
|
+
|
|
58
|
+
// --- Stage metadata ---
|
|
59
|
+
// @see https://openusd.org/release/api/class_usd_geom_set_stage_up_axis.html
|
|
60
|
+
const up_axis = root_fields.upAxis || "Y";
|
|
61
|
+
// @see https://openusd.org/release/api/class_usd_geom_linear_units.html
|
|
62
|
+
const meters_per_unit = root_fields.metersPerUnit ?? 1.0;
|
|
63
|
+
|
|
64
|
+
// Build a root correction matrix that converts the source coordinate
|
|
65
|
+
// system to the engine's convention (Y-up, meters).
|
|
66
|
+
const correction = m4_allocate();
|
|
67
|
+
|
|
68
|
+
if (up_axis === "Z") {
|
|
69
|
+
// Z-up → Y-up: rotate -90° around X
|
|
70
|
+
// @see https://openusd.org/release/api/group___usd_geom_up_axis__group.html
|
|
71
|
+
m4_make_rotation_x(correction, -Math.PI / 2);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (meters_per_unit !== 1.0) {
|
|
75
|
+
// NOTE: float64 metersPerUnit → float32 scale factor.
|
|
76
|
+
// Precision loss point for very small or very large unit ratios.
|
|
77
|
+
const s = meters_per_unit;
|
|
78
|
+
|
|
79
|
+
const scale = m4_make_scale(m4_allocate(), [s, s, s]);
|
|
80
|
+
|
|
81
|
+
m4_multiply(correction, correction, scale);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// --- Resolve materials ---
|
|
85
|
+
const materials = build_materials(specs_by_path);
|
|
86
|
+
|
|
87
|
+
// Extension registry (if provided)
|
|
88
|
+
const registry = options.extensions || null;
|
|
89
|
+
|
|
90
|
+
// --- Build prim hierarchy ---
|
|
91
|
+
const prim_children = root_fields.primChildren || [];
|
|
92
|
+
const roots = [];
|
|
93
|
+
|
|
94
|
+
// Check if correction is non-identity
|
|
95
|
+
const has_correction = up_axis === "Z" || meters_per_unit !== 1.0;
|
|
96
|
+
|
|
97
|
+
for (const child_name of prim_children) {
|
|
98
|
+
const child_path = "/" + child_name;
|
|
99
|
+
const node = build_prim(child_path, specs_by_path, materials, correction, options, registry);
|
|
100
|
+
|
|
101
|
+
if (node !== null) {
|
|
102
|
+
// Bake correction into root nodes' local transforms so that
|
|
103
|
+
// updateMatrices() propagates it correctly to global transforms
|
|
104
|
+
if (has_correction) {
|
|
105
|
+
const corrected = m4_allocate();
|
|
106
|
+
m4_multiply(corrected, correction, node.transform_local.matrix);
|
|
107
|
+
node.transform_local.fromMatrix(corrected);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
roots.push(node);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Propagate local transforms → global transforms and compute bounds
|
|
115
|
+
for (const root of roots) {
|
|
116
|
+
root.updateMatrices();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return roots;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Recursively build a Node3D from a prim spec.
|
|
125
|
+
*
|
|
126
|
+
* @param {string} path
|
|
127
|
+
* @param {Object} specs_by_path
|
|
128
|
+
* @param {Map<string, StandardShadeMaterial>} materials
|
|
129
|
+
* @param {mat4} parent_world_transform
|
|
130
|
+
* @param {UsdBuildOptions} options
|
|
131
|
+
* @param {import("./UsdExtensionRegistry.js").UsdExtensionRegistry|null} registry
|
|
132
|
+
* @returns {Node3D|null}
|
|
133
|
+
*/
|
|
134
|
+
function build_prim(path, specs_by_path, materials, parent_world_transform, options, registry) {
|
|
135
|
+
|
|
136
|
+
const spec = specs_by_path[path];
|
|
137
|
+
|
|
138
|
+
if (!spec || spec.specType !== 6) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const fields = spec.fields;
|
|
143
|
+
const type_name = fields.typeName || "";
|
|
144
|
+
const prim_name = path.split("/").pop();
|
|
145
|
+
|
|
146
|
+
// --- Extension hook: let registered extensions handle custom prim types ---
|
|
147
|
+
if (registry) {
|
|
148
|
+
for (const ext of registry.values()) {
|
|
149
|
+
if (ext.processPrim) {
|
|
150
|
+
const result = ext.processPrim(path, fields, { specs_by_path, materials, options });
|
|
151
|
+
|
|
152
|
+
if (result !== null && result !== undefined) {
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Compose local transform from xformOpOrder
|
|
160
|
+
// @see https://openusd.org/release/api/class_usd_geom_xformable.html#details
|
|
161
|
+
const local_transform = usd_compose_transform(fields, specs_by_path, path);
|
|
162
|
+
|
|
163
|
+
// Compute world transform
|
|
164
|
+
const world_transform = m4_allocate();
|
|
165
|
+
m4_multiply(world_transform, parent_world_transform, local_transform);
|
|
166
|
+
|
|
167
|
+
// Attempt to build a Mesh if this is a UsdGeomMesh
|
|
168
|
+
// @see https://openusd.org/release/api/class_usd_geom_mesh.html
|
|
169
|
+
if (type_name === "Mesh") {
|
|
170
|
+
return build_mesh_node(path, prim_name, fields, specs_by_path, materials, local_transform, world_transform, options, registry);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Warn on unrecognized prim types that carry data we silently ignore
|
|
174
|
+
if (type_name !== "" && type_name !== "Xform" && type_name !== "Scope" && type_name !== "Material" && type_name !== "Shader") {
|
|
175
|
+
console.warn(`[USD] Unhandled prim type "${type_name}" at ${path}, treating as group node`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// For Xform, Scope, and other grouping types, create a Node3D container
|
|
179
|
+
const node = new Node3D();
|
|
180
|
+
node.name = prim_name;
|
|
181
|
+
node.transform_local.fromMatrix(local_transform);
|
|
182
|
+
|
|
183
|
+
// Recurse into children
|
|
184
|
+
const children = fields.primChildren || [];
|
|
185
|
+
|
|
186
|
+
for (const child_name of children) {
|
|
187
|
+
const child_path = path + "/" + child_name;
|
|
188
|
+
const child = build_prim(child_path, specs_by_path, materials, world_transform, options, registry);
|
|
189
|
+
|
|
190
|
+
if (child !== null) {
|
|
191
|
+
node.addChild(child);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return node;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Build a Mesh node from a UsdGeomMesh prim.
|
|
201
|
+
*
|
|
202
|
+
* @see https://openusd.org/release/api/class_usd_geom_mesh.html
|
|
203
|
+
*
|
|
204
|
+
* UsdGeomMesh topology is defined by:
|
|
205
|
+
* - `faceVertexCounts`: int[] — number of vertices per face
|
|
206
|
+
* - `faceVertexIndices`: int[] — flattened vertex indices
|
|
207
|
+
* - `points`: point3f[] — vertex positions
|
|
208
|
+
*
|
|
209
|
+
* Primvars (per-vertex/per-face-varying data):
|
|
210
|
+
* - `primvars:st` / `primvars:st:indices`: texCoord2f[] — UV coordinates
|
|
211
|
+
* - `normals`: normal3f[] — can be vertex or faceVarying interpolation
|
|
212
|
+
*
|
|
213
|
+
* @param {string} path
|
|
214
|
+
* @param {string} name
|
|
215
|
+
* @param {Object} fields
|
|
216
|
+
* @param {Object} specs_by_path
|
|
217
|
+
* @param {Map<string, StandardShadeMaterial>} materials
|
|
218
|
+
* @param {mat4} local_transform
|
|
219
|
+
* @param {mat4} world_transform
|
|
220
|
+
* @param {UsdBuildOptions} options
|
|
221
|
+
* @param {import("./UsdExtensionRegistry.js").UsdExtensionRegistry|null} registry
|
|
222
|
+
* @returns {Mesh|Node3D}
|
|
223
|
+
*/
|
|
224
|
+
function build_mesh_node(path, name, fields, specs_by_path, materials, local_transform, world_transform, options, registry) {
|
|
225
|
+
|
|
226
|
+
// --- Read topology ---
|
|
227
|
+
const face_vertex_counts = read_attr(specs_by_path, path, "faceVertexCounts");
|
|
228
|
+
const face_vertex_indices = read_attr(specs_by_path, path, "faceVertexIndices");
|
|
229
|
+
const points_raw = read_attr(specs_by_path, path, "points");
|
|
230
|
+
|
|
231
|
+
if (!face_vertex_counts || !face_vertex_indices || !points_raw) {
|
|
232
|
+
// Not enough data to build a mesh — return as empty node
|
|
233
|
+
const node = new Node3D();
|
|
234
|
+
node.name = name;
|
|
235
|
+
node.transform_local.fromMatrix(local_transform);
|
|
236
|
+
return node;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Validate that vertex indices are within bounds
|
|
240
|
+
const vertex_count = points_raw.length / 3;
|
|
241
|
+
for (let i = 0; i < face_vertex_indices.length; i++) {
|
|
242
|
+
if (face_vertex_indices[i] >= vertex_count || face_vertex_indices[i] < 0) {
|
|
243
|
+
console.warn(
|
|
244
|
+
`[USD] faceVertexIndices[${i}] = ${face_vertex_indices[i]} is out of bounds ` +
|
|
245
|
+
`(vertex count: ${vertex_count}) at ${path}`
|
|
246
|
+
);
|
|
247
|
+
break; // Only warn once per mesh
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// points may be float64 from USDA; downcast to float32
|
|
252
|
+
// NOTE: Precision loss point — positions far from origin lose sub-mm precision
|
|
253
|
+
const points = ensure_float32(points_raw);
|
|
254
|
+
|
|
255
|
+
// --- Triangulate ---
|
|
256
|
+
// @see https://openusd.org/release/api/class_usd_geom_mesh.html#details
|
|
257
|
+
// USD meshes can have arbitrary polygons; we fan-triangulate them.
|
|
258
|
+
const { indices, face_map } = usd_triangulate(face_vertex_counts, face_vertex_indices);
|
|
259
|
+
|
|
260
|
+
// --- Gather per-vertex attributes ---
|
|
261
|
+
// Any faceVarying primvar forces flat (de-indexed) topology; the flag is
|
|
262
|
+
// tracked explicitly so every per-point attribute is re-expanded through
|
|
263
|
+
// the triangulated indices, regardless of attribute order.
|
|
264
|
+
let deindexed = false;
|
|
265
|
+
|
|
266
|
+
// Normals
|
|
267
|
+
// @see https://openusd.org/release/glossary.html#usdglossary-interpolation
|
|
268
|
+
let normal_data = null;
|
|
269
|
+
let normal_is_per_point = false;
|
|
270
|
+
|
|
271
|
+
const normals_raw = read_attr(specs_by_path, path, "normals");
|
|
272
|
+
|
|
273
|
+
if (normals_raw) {
|
|
274
|
+
const normals = ensure_float32(normals_raw);
|
|
275
|
+
const normals_interp = read_attr_interpolation(specs_by_path, path, "normals");
|
|
276
|
+
|
|
277
|
+
if (normals_interp === "faceVarying") {
|
|
278
|
+
// faceVarying: one value per face-vertex, re-index after triangulation
|
|
279
|
+
normal_data = usd_expand_face_varying(face_vertex_counts, normals, 3);
|
|
280
|
+
deindexed = true;
|
|
281
|
+
} else {
|
|
282
|
+
// vertex interpolation: one normal per point
|
|
283
|
+
normal_data = normals;
|
|
284
|
+
normal_is_per_point = true;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// UVs (primvars:st)
|
|
289
|
+
// @see https://openusd.org/release/api/class_usd_geom_primvars_a_p_i.html
|
|
290
|
+
let uv_data = null;
|
|
291
|
+
let uv_is_per_point = false;
|
|
292
|
+
|
|
293
|
+
const st_raw = read_attr(specs_by_path, path, "primvars:st");
|
|
294
|
+
|
|
295
|
+
if (st_raw) {
|
|
296
|
+
let st = ensure_float32(st_raw);
|
|
297
|
+
const st_indices = read_attr(specs_by_path, path, "primvars:st:indices");
|
|
298
|
+
const st_interp = read_attr_interpolation(specs_by_path, path, "primvars:st");
|
|
299
|
+
|
|
300
|
+
if (st_indices) {
|
|
301
|
+
// Indexed UVs — expand using the UV index array
|
|
302
|
+
st = expand_by_indices(st, st_indices, 2);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (st_interp === "faceVarying") {
|
|
306
|
+
uv_data = usd_expand_face_varying(face_vertex_counts, st, 2);
|
|
307
|
+
deindexed = true;
|
|
308
|
+
} else {
|
|
309
|
+
uv_data = st;
|
|
310
|
+
uv_is_per_point = true;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// --- Assemble geometry ---
|
|
315
|
+
const geometry = new Geometry();
|
|
316
|
+
|
|
317
|
+
if (deindexed) {
|
|
318
|
+
// Flat topology: expand positions and every per-point attribute
|
|
319
|
+
// through the triangulated indices so all attributes agree
|
|
320
|
+
const position_data = expand_indexed_to_flat(indices, points, 3);
|
|
321
|
+
geometry.addAttribute(normalize_attribute(Attribute.from(position_data, 3, StandardAttributes.Position)));
|
|
322
|
+
|
|
323
|
+
if (normal_data !== null) {
|
|
324
|
+
const flat_normals = normal_is_per_point
|
|
325
|
+
? expand_indexed_to_flat(indices, normal_data, 3)
|
|
326
|
+
: normal_data;
|
|
327
|
+
|
|
328
|
+
geometry.addAttribute(normalize_attribute(Attribute.from(flat_normals, 3, StandardAttributes.Normal)));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (uv_data !== null) {
|
|
332
|
+
const flat_uvs = uv_is_per_point
|
|
333
|
+
? expand_indexed_to_flat(indices, uv_data, 2)
|
|
334
|
+
: uv_data;
|
|
335
|
+
|
|
336
|
+
geometry.addAttribute(normalize_attribute(Attribute.from(flat_uvs, 2, StandardAttributes.TextureCoordinates0)));
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
// Indexed topology: all attributes are per-point
|
|
340
|
+
geometry.addAttribute(normalize_attribute(Attribute.from(points, 3, StandardAttributes.Position)));
|
|
341
|
+
geometry.index = Attribute.from(indices, 1, "index");
|
|
342
|
+
|
|
343
|
+
if (normal_data !== null) {
|
|
344
|
+
geometry.addAttribute(normalize_attribute(Attribute.from(normal_data, 3, StandardAttributes.Normal)));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (uv_data !== null) {
|
|
348
|
+
geometry.addAttribute(normalize_attribute(Attribute.from(uv_data, 2, StandardAttributes.TextureCoordinates0)));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// --- Resolve material binding ---
|
|
353
|
+
// @see https://openusd.org/release/api/class_usd_shade_material_binding_a_p_i.html
|
|
354
|
+
const binding_path = path + ".material:binding";
|
|
355
|
+
const binding_spec = specs_by_path[binding_path];
|
|
356
|
+
let material = new StandardShadeMaterial();
|
|
357
|
+
|
|
358
|
+
if (binding_spec && binding_spec.fields.targetPaths) {
|
|
359
|
+
const mat_path = binding_spec.fields.targetPaths[0];
|
|
360
|
+
|
|
361
|
+
if (materials.has(mat_path)) {
|
|
362
|
+
material = materials.get(mat_path);
|
|
363
|
+
} else {
|
|
364
|
+
console.warn(`[USD] Material binding at ${path} references "${mat_path}" which was not found`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Handle doubleSided
|
|
369
|
+
// @see https://openusd.org/release/api/class_usd_geom_mesh.html
|
|
370
|
+
// doubleSided is a per-gprim flag; the bound material is shared between
|
|
371
|
+
// meshes and must not be mutated — clone it for this mesh instead
|
|
372
|
+
const double_sided = read_attr(specs_by_path, path, "doubleSided");
|
|
373
|
+
if (double_sided === true && material.draw_side !== ShadeDrawSide.Double) {
|
|
374
|
+
material = material.clone();
|
|
375
|
+
material.draw_side = ShadeDrawSide.Double;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// --- Build engine Mesh ---
|
|
379
|
+
const meshlet_geo = meshlet_geometry_build_from_geometry(geometry);
|
|
380
|
+
|
|
381
|
+
const mesh = new Mesh();
|
|
382
|
+
mesh.name = name;
|
|
383
|
+
mesh.geometry = meshlet_geo;
|
|
384
|
+
mesh.material = material;
|
|
385
|
+
mesh.transform_local.fromMatrix(local_transform);
|
|
386
|
+
|
|
387
|
+
// Recurse into children (mesh prims can have child prims)
|
|
388
|
+
const children = fields.primChildren || [];
|
|
389
|
+
|
|
390
|
+
if (children.length > 0) {
|
|
391
|
+
for (const child_name of children) {
|
|
392
|
+
const child_path = path + "/" + child_name;
|
|
393
|
+
const child = build_prim(child_path, specs_by_path, materials, world_transform, options, registry);
|
|
394
|
+
|
|
395
|
+
if (child !== null) {
|
|
396
|
+
mesh.addChild(child);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return mesh;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
// =============================================================================
|
|
406
|
+
// Material Building
|
|
407
|
+
// =============================================================================
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Build materials from UsdPreviewSurface shader prims.
|
|
411
|
+
*
|
|
412
|
+
* @see https://openusd.org/release/spec_usdpreviewsurface.html — UsdPreviewSurface specification
|
|
413
|
+
*
|
|
414
|
+
* @param {Object} specs_by_path
|
|
415
|
+
* @returns {Map<string, StandardShadeMaterial>}
|
|
416
|
+
*/
|
|
417
|
+
function build_materials(specs_by_path) {
|
|
418
|
+
|
|
419
|
+
/** @type {Map<string, StandardShadeMaterial>} */
|
|
420
|
+
const result = new Map();
|
|
421
|
+
|
|
422
|
+
for (const path in specs_by_path) {
|
|
423
|
+
const spec = specs_by_path[path];
|
|
424
|
+
|
|
425
|
+
if (spec.specType !== 6) continue;
|
|
426
|
+
|
|
427
|
+
const type_name = spec.fields.typeName;
|
|
428
|
+
|
|
429
|
+
if (type_name !== "Material") continue;
|
|
430
|
+
|
|
431
|
+
const material = build_material(path, specs_by_path);
|
|
432
|
+
result.set(path, material);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return result;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Build a single StandardShadeMaterial from a UsdShadeMaterial prim.
|
|
441
|
+
*
|
|
442
|
+
* Walks the material's shader network to find UsdPreviewSurface inputs.
|
|
443
|
+
*
|
|
444
|
+
* @see https://openusd.org/release/spec_usdpreviewsurface.html
|
|
445
|
+
*
|
|
446
|
+
* @param {string} mat_path
|
|
447
|
+
* @param {Object} specs_by_path
|
|
448
|
+
* @returns {StandardShadeMaterial}
|
|
449
|
+
*/
|
|
450
|
+
function build_material(mat_path, specs_by_path) {
|
|
451
|
+
|
|
452
|
+
const material = new StandardShadeMaterial();
|
|
453
|
+
material.name = mat_path.split("/").pop();
|
|
454
|
+
|
|
455
|
+
// Find the UsdPreviewSurface shader child
|
|
456
|
+
const mat_spec = specs_by_path[mat_path];
|
|
457
|
+
const children = mat_spec.fields.primChildren || [];
|
|
458
|
+
|
|
459
|
+
for (const child_name of children) {
|
|
460
|
+
const shader_path = mat_path + "/" + child_name;
|
|
461
|
+
const shader_spec = specs_by_path[shader_path];
|
|
462
|
+
|
|
463
|
+
if (!shader_spec || shader_spec.specType !== 6) continue;
|
|
464
|
+
if (shader_spec.fields.typeName !== "Shader") continue;
|
|
465
|
+
|
|
466
|
+
// Check info:id for UsdPreviewSurface
|
|
467
|
+
const info_id = read_attr(specs_by_path, shader_path, "info:id");
|
|
468
|
+
|
|
469
|
+
if (info_id !== "UsdPreviewSurface") continue;
|
|
470
|
+
|
|
471
|
+
// --- Map UsdPreviewSurface inputs to engine material ---
|
|
472
|
+
// @see https://openusd.org/release/spec_usdpreviewsurface.html#inputs
|
|
473
|
+
|
|
474
|
+
// Diffuse color
|
|
475
|
+
const diffuse = read_attr(specs_by_path, shader_path, "inputs:diffuseColor");
|
|
476
|
+
if (diffuse && Array.isArray(diffuse)) {
|
|
477
|
+
material.diffuse_color.setRGB(diffuse[0], diffuse[1], diffuse[2]);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Metallic
|
|
481
|
+
const metallic = read_attr(specs_by_path, shader_path, "inputs:metallic");
|
|
482
|
+
if (typeof metallic === "number") {
|
|
483
|
+
material.metallic_factor = clamp01(metallic);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Roughness
|
|
487
|
+
const roughness = read_attr(specs_by_path, shader_path, "inputs:roughness");
|
|
488
|
+
if (typeof roughness === "number") {
|
|
489
|
+
material.roughness_factor = clamp01(roughness);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Opacity
|
|
493
|
+
const opacity = read_attr(specs_by_path, shader_path, "inputs:opacity");
|
|
494
|
+
if (typeof opacity === "number" && opacity < 1.0) {
|
|
495
|
+
material.diffuse_color.a = clamp01(opacity);
|
|
496
|
+
material.transparency_mode = TransparencyMode.Transparent;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Emissive color
|
|
500
|
+
const emissive = read_attr(specs_by_path, shader_path, "inputs:emissiveColor");
|
|
501
|
+
if (emissive && Array.isArray(emissive)) {
|
|
502
|
+
const intensity = Math.max(emissive[0], emissive[1], emissive[2]);
|
|
503
|
+
if (intensity > 0) {
|
|
504
|
+
material.emissive_factor.setRGB(emissive[0], emissive[1], emissive[2]);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
break; // Only use the first UsdPreviewSurface
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return material;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
// =============================================================================
|
|
516
|
+
// Helpers
|
|
517
|
+
// =============================================================================
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Read an attribute's default value from specsByPath.
|
|
521
|
+
*
|
|
522
|
+
* @param {Object} specs_by_path
|
|
523
|
+
* @param {string} prim_path
|
|
524
|
+
* @param {string} attr_name
|
|
525
|
+
* @returns {*}
|
|
526
|
+
*/
|
|
527
|
+
function read_attr(specs_by_path, prim_path, attr_name) {
|
|
528
|
+
|
|
529
|
+
const spec = specs_by_path[prim_path + "." + attr_name];
|
|
530
|
+
|
|
531
|
+
if (!spec || !spec.fields) return undefined;
|
|
532
|
+
|
|
533
|
+
// USD value resolution: timeSamples win over default when both are authored
|
|
534
|
+
// @see https://openusd.org/release/glossary.html#usdglossary-valueresolution
|
|
535
|
+
if (spec.fields.timeSamples && spec.fields.timeSamples.values.length > 0) {
|
|
536
|
+
return spec.fields.timeSamples.values[0];
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (spec.fields.default !== undefined) {
|
|
540
|
+
return spec.fields.default;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return undefined;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Read interpolation metadata for an attribute.
|
|
549
|
+
*
|
|
550
|
+
* @see https://openusd.org/release/glossary.html#usdglossary-interpolation
|
|
551
|
+
*
|
|
552
|
+
* @param {Object} specs_by_path
|
|
553
|
+
* @param {string} prim_path
|
|
554
|
+
* @param {string} attr_name
|
|
555
|
+
* @returns {string} "vertex" | "faceVarying" | "uniform" | "constant"
|
|
556
|
+
*/
|
|
557
|
+
function read_attr_interpolation(specs_by_path, prim_path, attr_name) {
|
|
558
|
+
|
|
559
|
+
const spec = specs_by_path[prim_path + "." + attr_name];
|
|
560
|
+
|
|
561
|
+
if (spec && spec.fields && spec.fields.interpolation) {
|
|
562
|
+
return spec.fields.interpolation;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Default interpolation for most geometry attributes
|
|
566
|
+
return "vertex";
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Ensure data is Float32Array. Downcasts Float64Array if needed.
|
|
572
|
+
*
|
|
573
|
+
* NOTE: Precision loss point — float64 → float32 conversion.
|
|
574
|
+
*
|
|
575
|
+
* @param {number[]|Float32Array|Float64Array} data
|
|
576
|
+
* @returns {Float32Array}
|
|
577
|
+
*/
|
|
578
|
+
function ensure_float32(data) {
|
|
579
|
+
|
|
580
|
+
if (data instanceof Float32Array) {
|
|
581
|
+
return data;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return new Float32Array(data);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Expand indexed data using an index array.
|
|
590
|
+
*
|
|
591
|
+
* @param {Float32Array} data - Source data (item_size per element)
|
|
592
|
+
* @param {number[]|Int32Array} index_array - Index into data
|
|
593
|
+
* @param {number} item_size - Components per element
|
|
594
|
+
* @returns {Float32Array}
|
|
595
|
+
*/
|
|
596
|
+
function expand_by_indices(data, index_array, item_size) {
|
|
597
|
+
|
|
598
|
+
const result = new Float32Array(index_array.length * item_size);
|
|
599
|
+
|
|
600
|
+
for (let i = 0; i < index_array.length; i++) {
|
|
601
|
+
const src = index_array[i] * item_size;
|
|
602
|
+
|
|
603
|
+
for (let c = 0; c < item_size; c++) {
|
|
604
|
+
result[i * item_size + c] = data[src + c];
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
return result;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Expand indexed vertex data to flat (un-indexed) arrays.
|
|
614
|
+
*
|
|
615
|
+
* @param {Uint32Array} indices
|
|
616
|
+
* @param {Float32Array} positions - Flat positions (3 per vertex)
|
|
617
|
+
* @param {number} item_size
|
|
618
|
+
* @returns {Float32Array}
|
|
619
|
+
*/
|
|
620
|
+
function expand_indexed_to_flat(indices, positions, item_size) {
|
|
621
|
+
|
|
622
|
+
const result = new Float32Array(indices.length * item_size);
|
|
623
|
+
|
|
624
|
+
for (let i = 0; i < indices.length; i++) {
|
|
625
|
+
const src = indices[i] * item_size;
|
|
626
|
+
|
|
627
|
+
for (let c = 0; c < item_size; c++) {
|
|
628
|
+
result[i * item_size + c] = positions[src + c];
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
return result;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Replace geometry positions with expanded (un-indexed) data and
|
|
638
|
+
* optionally set normals.
|
|
639
|
+
*
|
|
640
|
+
* @param {Geometry} geometry
|
|
641
|
+
* @param {Float32Array} expanded_positions
|
|
642
|
+
* @param {Float32Array|null} expanded_normals
|
|
643
|
+
*/
|
|
644
|
+
function replace_geometry_positions(geometry, expanded_positions, expanded_normals) {
|
|
645
|
+
|
|
646
|
+
// Remove index and replace positions
|
|
647
|
+
geometry.index = null;
|
|
648
|
+
|
|
649
|
+
const pos_attr = Attribute.from(expanded_positions, 3, StandardAttributes.Position);
|
|
650
|
+
geometry.removeAttribute(StandardAttributes.Position);
|
|
651
|
+
geometry.addAttribute(normalize_attribute(pos_attr));
|
|
652
|
+
|
|
653
|
+
if (expanded_normals) {
|
|
654
|
+
const normal_attr = Attribute.from(expanded_normals, 3, StandardAttributes.Normal);
|
|
655
|
+
geometry.removeAttribute(StandardAttributes.Normal);
|
|
656
|
+
geometry.addAttribute(normalize_attribute(normal_attr));
|
|
657
|
+
}
|
|
658
|
+
}
|