@luma.gl/gltf 9.3.0-alpha.6 → 9.3.0-alpha.8

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 (65) hide show
  1. package/dist/dist.dev.js +942 -141
  2. package/dist/dist.min.js +4 -4
  3. package/dist/gltf/create-gltf-model.d.ts +9 -1
  4. package/dist/gltf/create-gltf-model.d.ts.map +1 -1
  5. package/dist/gltf/create-gltf-model.js +58 -4
  6. package/dist/gltf/create-gltf-model.js.map +1 -1
  7. package/dist/gltf/create-scenegraph-from-gltf.d.ts +22 -1
  8. package/dist/gltf/create-scenegraph-from-gltf.d.ts.map +1 -1
  9. package/dist/gltf/create-scenegraph-from-gltf.js +63 -1
  10. package/dist/gltf/create-scenegraph-from-gltf.js.map +1 -1
  11. package/dist/gltf/gltf-extension-support.d.ts +10 -0
  12. package/dist/gltf/gltf-extension-support.d.ts.map +1 -0
  13. package/dist/gltf/gltf-extension-support.js +173 -0
  14. package/dist/gltf/gltf-extension-support.js.map +1 -0
  15. package/dist/index.cjs +899 -114
  16. package/dist/index.cjs.map +4 -4
  17. package/dist/index.d.ts +2 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/parsers/parse-gltf-animations.d.ts.map +1 -1
  22. package/dist/parsers/parse-gltf-animations.js +34 -12
  23. package/dist/parsers/parse-gltf-animations.js.map +1 -1
  24. package/dist/parsers/parse-gltf-lights.d.ts.map +1 -1
  25. package/dist/parsers/parse-gltf-lights.js +86 -20
  26. package/dist/parsers/parse-gltf-lights.js.map +1 -1
  27. package/dist/parsers/parse-gltf.d.ts +3 -1
  28. package/dist/parsers/parse-gltf.d.ts.map +1 -1
  29. package/dist/parsers/parse-gltf.js +41 -9
  30. package/dist/parsers/parse-gltf.js.map +1 -1
  31. package/dist/parsers/parse-pbr-material.d.ts +69 -1
  32. package/dist/parsers/parse-pbr-material.d.ts.map +1 -1
  33. package/dist/parsers/parse-pbr-material.js +429 -42
  34. package/dist/parsers/parse-pbr-material.js.map +1 -1
  35. package/dist/pbr/pbr-environment.d.ts.map +1 -1
  36. package/dist/pbr/pbr-environment.js +14 -12
  37. package/dist/pbr/pbr-environment.js.map +1 -1
  38. package/dist/pbr/pbr-material.d.ts +8 -3
  39. package/dist/pbr/pbr-material.d.ts.map +1 -1
  40. package/dist/webgl-to-webgpu/convert-webgl-sampler.d.ts +5 -5
  41. package/dist/webgl-to-webgpu/convert-webgl-sampler.d.ts.map +1 -1
  42. package/dist/webgl-to-webgpu/convert-webgl-sampler.js +12 -12
  43. package/dist/webgl-to-webgpu/convert-webgl-sampler.js.map +1 -1
  44. package/dist/webgl-to-webgpu/convert-webgl-topology.d.ts +1 -10
  45. package/dist/webgl-to-webgpu/convert-webgl-topology.d.ts.map +1 -1
  46. package/dist/webgl-to-webgpu/convert-webgl-topology.js +1 -15
  47. package/dist/webgl-to-webgpu/convert-webgl-topology.js.map +1 -1
  48. package/dist/webgl-to-webgpu/gltf-webgl-constants.d.ts +27 -0
  49. package/dist/webgl-to-webgpu/gltf-webgl-constants.d.ts.map +1 -0
  50. package/dist/webgl-to-webgpu/gltf-webgl-constants.js +34 -0
  51. package/dist/webgl-to-webgpu/gltf-webgl-constants.js.map +1 -0
  52. package/package.json +5 -6
  53. package/src/gltf/create-gltf-model.ts +113 -5
  54. package/src/gltf/create-scenegraph-from-gltf.ts +97 -6
  55. package/src/gltf/gltf-extension-support.ts +214 -0
  56. package/src/index.ts +10 -1
  57. package/src/parsers/parse-gltf-animations.ts +39 -15
  58. package/src/parsers/parse-gltf-lights.ts +114 -25
  59. package/src/parsers/parse-gltf.ts +86 -19
  60. package/src/parsers/parse-pbr-material.ts +664 -69
  61. package/src/pbr/pbr-environment.ts +29 -16
  62. package/src/pbr/pbr-material.ts +13 -3
  63. package/src/webgl-to-webgpu/convert-webgl-sampler.ts +29 -29
  64. package/src/webgl-to-webgpu/convert-webgl-topology.ts +1 -15
  65. package/src/webgl-to-webgpu/gltf-webgl-constants.ts +35 -0
package/dist/index.cjs CHANGED
@@ -22,6 +22,7 @@ var dist_exports = {};
22
22
  __export(dist_exports, {
23
23
  GLTFAnimator: () => GLTFAnimator,
24
24
  createScenegraphsFromGLTF: () => createScenegraphsFromGLTF,
25
+ getGLTFExtensionSupport: () => getGLTFExtensionSupport,
25
26
  loadPBREnvironment: () => loadPBREnvironment,
26
27
  parseGLTFLights: () => parseGLTFLights,
27
28
  parsePBRMaterial: () => parsePBRMaterial
@@ -32,6 +33,7 @@ module.exports = __toCommonJS(dist_exports);
32
33
  var import_engine = require("@luma.gl/engine");
33
34
  var import_textures = require("@loaders.gl/textures");
34
35
  function loadPBREnvironment(device, props) {
36
+ const specularMipLevels = props.specularMipLevels ?? 1;
35
37
  const brdfLutTexture = new import_engine.DynamicTexture(device, {
36
38
  id: "brdfLUT",
37
39
  sampler: {
@@ -45,7 +47,7 @@ function loadPBREnvironment(device, props) {
45
47
  });
46
48
  const diffuseEnvSampler = makeCube(device, {
47
49
  id: "DiffuseEnvSampler",
48
- getTextureForFace: (dir) => (0, import_textures.loadImageTexture)(props.getTexUrl("diffuse", dir, 0)),
50
+ getTextureForFace: (face) => (0, import_textures.loadImageTexture)(props.getTexUrl("diffuse", FACES.indexOf(face), 0)),
49
51
  sampler: {
50
52
  addressModeU: "clamp-to-edge",
51
53
  addressModeV: "clamp-to-edge",
@@ -55,12 +57,13 @@ function loadPBREnvironment(device, props) {
55
57
  });
56
58
  const specularEnvSampler = makeCube(device, {
57
59
  id: "SpecularEnvSampler",
58
- getTextureForFace: (dir) => {
60
+ getTextureForFace: (face) => {
59
61
  const imageArray = [];
60
- for (let lod = 0; lod <= props.specularMipLevels - 1; lod++) {
61
- imageArray.push((0, import_textures.loadImageTexture)(props.getTexUrl("specular", dir, lod)));
62
+ const direction = FACES.indexOf(face);
63
+ for (let lod = 0; lod < specularMipLevels; lod++) {
64
+ imageArray.push((0, import_textures.loadImageTexture)(props.getTexUrl("specular", direction, lod)));
62
65
  }
63
- return imageArray;
66
+ return Promise.all(imageArray);
64
67
  },
65
68
  sampler: {
66
69
  addressModeU: "clamp-to-edge",
@@ -76,28 +79,57 @@ function loadPBREnvironment(device, props) {
76
79
  specularEnvSampler
77
80
  };
78
81
  }
79
- var FACES = [0, 1, 2, 3, 4, 5];
82
+ var FACES = ["+X", "-X", "+Y", "-Y", "+Z", "-Z"];
80
83
  function makeCube(device, { id, getTextureForFace, sampler }) {
81
- const data = {};
82
- FACES.forEach((face) => {
83
- data[String(face)] = getTextureForFace(face);
84
+ const data = Promise.all(FACES.map((face) => getTextureForFace(face))).then((faceDataArray) => {
85
+ const cubeData = {};
86
+ FACES.forEach((face, index) => {
87
+ cubeData[face] = faceDataArray[index];
88
+ });
89
+ return cubeData;
84
90
  });
85
91
  return new import_engine.DynamicTexture(device, {
86
92
  id,
87
93
  dimension: "cube",
88
94
  mipmaps: false,
89
95
  sampler,
90
- // @ts-expect-error
91
96
  data
92
97
  });
93
98
  }
94
99
 
95
100
  // dist/parsers/parse-pbr-material.js
96
101
  var import_core = require("@luma.gl/core");
97
- var import_constants2 = require("@luma.gl/constants");
102
+
103
+ // dist/webgl-to-webgpu/gltf-webgl-constants.js
104
+ var GLEnum;
105
+ (function(GLEnum2) {
106
+ GLEnum2[GLEnum2["POINTS"] = 0] = "POINTS";
107
+ GLEnum2[GLEnum2["LINES"] = 1] = "LINES";
108
+ GLEnum2[GLEnum2["LINE_LOOP"] = 2] = "LINE_LOOP";
109
+ GLEnum2[GLEnum2["LINE_STRIP"] = 3] = "LINE_STRIP";
110
+ GLEnum2[GLEnum2["TRIANGLES"] = 4] = "TRIANGLES";
111
+ GLEnum2[GLEnum2["TRIANGLE_STRIP"] = 5] = "TRIANGLE_STRIP";
112
+ GLEnum2[GLEnum2["TRIANGLE_FAN"] = 6] = "TRIANGLE_FAN";
113
+ GLEnum2[GLEnum2["ONE"] = 1] = "ONE";
114
+ GLEnum2[GLEnum2["SRC_ALPHA"] = 770] = "SRC_ALPHA";
115
+ GLEnum2[GLEnum2["ONE_MINUS_SRC_ALPHA"] = 771] = "ONE_MINUS_SRC_ALPHA";
116
+ GLEnum2[GLEnum2["FUNC_ADD"] = 32774] = "FUNC_ADD";
117
+ GLEnum2[GLEnum2["LINEAR"] = 9729] = "LINEAR";
118
+ GLEnum2[GLEnum2["NEAREST"] = 9728] = "NEAREST";
119
+ GLEnum2[GLEnum2["NEAREST_MIPMAP_NEAREST"] = 9984] = "NEAREST_MIPMAP_NEAREST";
120
+ GLEnum2[GLEnum2["LINEAR_MIPMAP_NEAREST"] = 9985] = "LINEAR_MIPMAP_NEAREST";
121
+ GLEnum2[GLEnum2["NEAREST_MIPMAP_LINEAR"] = 9986] = "NEAREST_MIPMAP_LINEAR";
122
+ GLEnum2[GLEnum2["LINEAR_MIPMAP_LINEAR"] = 9987] = "LINEAR_MIPMAP_LINEAR";
123
+ GLEnum2[GLEnum2["TEXTURE_MIN_FILTER"] = 10241] = "TEXTURE_MIN_FILTER";
124
+ GLEnum2[GLEnum2["TEXTURE_WRAP_S"] = 10242] = "TEXTURE_WRAP_S";
125
+ GLEnum2[GLEnum2["TEXTURE_WRAP_T"] = 10243] = "TEXTURE_WRAP_T";
126
+ GLEnum2[GLEnum2["REPEAT"] = 10497] = "REPEAT";
127
+ GLEnum2[GLEnum2["CLAMP_TO_EDGE"] = 33071] = "CLAMP_TO_EDGE";
128
+ GLEnum2[GLEnum2["MIRRORED_REPEAT"] = 33648] = "MIRRORED_REPEAT";
129
+ GLEnum2[GLEnum2["UNPACK_FLIP_Y_WEBGL"] = 37440] = "UNPACK_FLIP_Y_WEBGL";
130
+ })(GLEnum || (GLEnum = {}));
98
131
 
99
132
  // dist/webgl-to-webgpu/convert-webgl-sampler.js
100
- var import_constants = require("@luma.gl/constants");
101
133
  function convertSampler(gltfSampler) {
102
134
  return {
103
135
  addressModeU: convertSamplerWrapMode(gltfSampler.wrapS),
@@ -108,11 +140,11 @@ function convertSampler(gltfSampler) {
108
140
  }
109
141
  function convertSamplerWrapMode(mode) {
110
142
  switch (mode) {
111
- case 33071:
143
+ case GLEnum.CLAMP_TO_EDGE:
112
144
  return "clamp-to-edge";
113
- case 10497:
145
+ case GLEnum.REPEAT:
114
146
  return "repeat";
115
- case 33648:
147
+ case GLEnum.MIRRORED_REPEAT:
116
148
  return "mirror-repeat";
117
149
  default:
118
150
  return void 0;
@@ -120,9 +152,9 @@ function convertSamplerWrapMode(mode) {
120
152
  }
121
153
  function convertSamplerMagFilter(mode) {
122
154
  switch (mode) {
123
- case 9728:
155
+ case GLEnum.NEAREST:
124
156
  return "nearest";
125
- case 9729:
157
+ case GLEnum.LINEAR:
126
158
  return "linear";
127
159
  default:
128
160
  return void 0;
@@ -130,17 +162,17 @@ function convertSamplerMagFilter(mode) {
130
162
  }
131
163
  function convertSamplerMinFilter(mode) {
132
164
  switch (mode) {
133
- case 9728:
165
+ case GLEnum.NEAREST:
134
166
  return { minFilter: "nearest" };
135
- case 9729:
167
+ case GLEnum.LINEAR:
136
168
  return { minFilter: "linear" };
137
- case 9984:
169
+ case GLEnum.NEAREST_MIPMAP_NEAREST:
138
170
  return { minFilter: "nearest", mipmapFilter: "nearest" };
139
- case 9985:
171
+ case GLEnum.LINEAR_MIPMAP_NEAREST:
140
172
  return { minFilter: "linear", mipmapFilter: "nearest" };
141
- case 9986:
173
+ case GLEnum.NEAREST_MIPMAP_LINEAR:
142
174
  return { minFilter: "nearest", mipmapFilter: "linear" };
143
- case 9987:
175
+ case GLEnum.LINEAR_MIPMAP_LINEAR:
144
176
  return { minFilter: "linear", mipmapFilter: "linear" };
145
177
  default:
146
178
  return {};
@@ -172,7 +204,8 @@ function parsePBRMaterial(device, material, attributes, options) {
172
204
  if (imageBasedLightingEnvironment) {
173
205
  parsedMaterial.bindings.pbr_diffuseEnvSampler = imageBasedLightingEnvironment.diffuseEnvSampler.texture;
174
206
  parsedMaterial.bindings.pbr_specularEnvSampler = imageBasedLightingEnvironment.specularEnvSampler.texture;
175
- parsedMaterial.bindings.pbr_BrdfLUT = imageBasedLightingEnvironment.brdfLutTexture.texture;
207
+ parsedMaterial.bindings.pbr_brdfLUT = imageBasedLightingEnvironment.brdfLutTexture.texture;
208
+ parsedMaterial.uniforms.IBLenabled = true;
176
209
  parsedMaterial.uniforms.scaleIBLAmbient = [1, 1];
177
210
  }
178
211
  if (options == null ? void 0 : options.pbrDebug) {
@@ -195,69 +228,419 @@ function parsePBRMaterial(device, material, attributes, options) {
195
228
  if (options == null ? void 0 : options.lights)
196
229
  parsedMaterial.defines["USE_LIGHTS"] = true;
197
230
  if (material) {
198
- parseMaterial(device, material, parsedMaterial);
231
+ if (options.validateAttributes !== false) {
232
+ warnOnMissingExpectedAttributes(material, attributes);
233
+ }
234
+ parseMaterial(device, material, parsedMaterial, options.gltf);
199
235
  }
200
236
  return parsedMaterial;
201
237
  }
202
- function parseMaterial(device, material, parsedMaterial) {
203
- parsedMaterial.uniforms.unlit = Boolean(material.unlit);
238
+ function warnOnMissingExpectedAttributes(material, attributes) {
239
+ var _a;
240
+ const uvDependentTextureSlots = getUvDependentTextureSlots(material);
241
+ if (uvDependentTextureSlots.length > 0 && !attributes["TEXCOORD_0"]) {
242
+ import_core.log.warn(`glTF material uses ${uvDependentTextureSlots.join(", ")} but primitive is missing TEXCOORD_0; textured shading will sample the default UV coordinates`)();
243
+ }
244
+ const isUnlitMaterial = Boolean(material.unlit || ((_a = material.extensions) == null ? void 0 : _a.KHR_materials_unlit));
245
+ if (isUnlitMaterial || attributes["NORMAL"]) {
246
+ return;
247
+ }
248
+ const missingNormalReason = material.normalTexture ? "lit PBR shading with normalTexture" : "lit PBR shading";
249
+ import_core.log.warn(`glTF primitive is missing NORMAL while using ${missingNormalReason}; shading will fall back to geometric normals`)();
250
+ }
251
+ function getUvDependentTextureSlots(material) {
252
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
253
+ const uvDependentTextureSlots = [];
254
+ if ((_a = material.pbrMetallicRoughness) == null ? void 0 : _a.baseColorTexture) {
255
+ uvDependentTextureSlots.push("baseColorTexture");
256
+ }
257
+ if ((_b = material.pbrMetallicRoughness) == null ? void 0 : _b.metallicRoughnessTexture) {
258
+ uvDependentTextureSlots.push("metallicRoughnessTexture");
259
+ }
260
+ if (material.normalTexture) {
261
+ uvDependentTextureSlots.push("normalTexture");
262
+ }
263
+ if (material.occlusionTexture) {
264
+ uvDependentTextureSlots.push("occlusionTexture");
265
+ }
266
+ if (material.emissiveTexture) {
267
+ uvDependentTextureSlots.push("emissiveTexture");
268
+ }
269
+ if ((_d = (_c = material.extensions) == null ? void 0 : _c.KHR_materials_specular) == null ? void 0 : _d.specularTexture) {
270
+ uvDependentTextureSlots.push("KHR_materials_specular.specularTexture");
271
+ }
272
+ if ((_f = (_e = material.extensions) == null ? void 0 : _e.KHR_materials_specular) == null ? void 0 : _f.specularColorTexture) {
273
+ uvDependentTextureSlots.push("KHR_materials_specular.specularColorTexture");
274
+ }
275
+ if ((_h = (_g = material.extensions) == null ? void 0 : _g.KHR_materials_transmission) == null ? void 0 : _h.transmissionTexture) {
276
+ uvDependentTextureSlots.push("KHR_materials_transmission.transmissionTexture");
277
+ }
278
+ if ((_j = (_i = material.extensions) == null ? void 0 : _i.KHR_materials_clearcoat) == null ? void 0 : _j.clearcoatTexture) {
279
+ uvDependentTextureSlots.push("KHR_materials_clearcoat.clearcoatTexture");
280
+ }
281
+ if ((_l = (_k = material.extensions) == null ? void 0 : _k.KHR_materials_clearcoat) == null ? void 0 : _l.clearcoatRoughnessTexture) {
282
+ uvDependentTextureSlots.push("KHR_materials_clearcoat.clearcoatRoughnessTexture");
283
+ }
284
+ if ((_n = (_m = material.extensions) == null ? void 0 : _m.KHR_materials_sheen) == null ? void 0 : _n.sheenColorTexture) {
285
+ uvDependentTextureSlots.push("KHR_materials_sheen.sheenColorTexture");
286
+ }
287
+ if ((_p = (_o = material.extensions) == null ? void 0 : _o.KHR_materials_sheen) == null ? void 0 : _p.sheenRoughnessTexture) {
288
+ uvDependentTextureSlots.push("KHR_materials_sheen.sheenRoughnessTexture");
289
+ }
290
+ if ((_r = (_q = material.extensions) == null ? void 0 : _q.KHR_materials_iridescence) == null ? void 0 : _r.iridescenceTexture) {
291
+ uvDependentTextureSlots.push("KHR_materials_iridescence.iridescenceTexture");
292
+ }
293
+ if ((_t = (_s = material.extensions) == null ? void 0 : _s.KHR_materials_anisotropy) == null ? void 0 : _t.anisotropyTexture) {
294
+ uvDependentTextureSlots.push("KHR_materials_anisotropy.anisotropyTexture");
295
+ }
296
+ return uvDependentTextureSlots;
297
+ }
298
+ function parseMaterial(device, material, parsedMaterial, gltf) {
299
+ var _a;
300
+ parsedMaterial.uniforms.unlit = Boolean(material.unlit || ((_a = material.extensions) == null ? void 0 : _a.KHR_materials_unlit));
204
301
  if (material.pbrMetallicRoughness) {
205
- parsePbrMetallicRoughness(device, material.pbrMetallicRoughness, parsedMaterial);
302
+ parsePbrMetallicRoughness(device, material.pbrMetallicRoughness, parsedMaterial, gltf);
206
303
  }
207
304
  if (material.normalTexture) {
208
- addTexture(device, material.normalTexture, "pbr_normalSampler", "HAS_NORMALMAP", parsedMaterial);
305
+ addTexture(device, material.normalTexture, "pbr_normalSampler", parsedMaterial, {
306
+ featureOptions: {
307
+ define: "HAS_NORMALMAP",
308
+ enabledUniformName: "normalMapEnabled"
309
+ },
310
+ gltf
311
+ });
209
312
  const { scale = 1 } = material.normalTexture;
210
313
  parsedMaterial.uniforms.normalScale = scale;
211
314
  }
212
315
  if (material.occlusionTexture) {
213
- addTexture(device, material.occlusionTexture, "pbr_occlusionSampler", "HAS_OCCLUSIONMAP", parsedMaterial);
316
+ addTexture(device, material.occlusionTexture, "pbr_occlusionSampler", parsedMaterial, {
317
+ featureOptions: {
318
+ define: "HAS_OCCLUSIONMAP",
319
+ enabledUniformName: "occlusionMapEnabled"
320
+ },
321
+ gltf
322
+ });
214
323
  const { strength = 1 } = material.occlusionTexture;
215
324
  parsedMaterial.uniforms.occlusionStrength = strength;
216
325
  }
326
+ parsedMaterial.uniforms.emissiveFactor = material.emissiveFactor || [0, 0, 0];
217
327
  if (material.emissiveTexture) {
218
- addTexture(device, material.emissiveTexture, "pbr_emissiveSampler", "HAS_EMISSIVEMAP", parsedMaterial);
219
- parsedMaterial.uniforms.emissiveFactor = material.emissiveFactor || [0, 0, 0];
328
+ addTexture(device, material.emissiveTexture, "pbr_emissiveSampler", parsedMaterial, {
329
+ featureOptions: {
330
+ define: "HAS_EMISSIVEMAP",
331
+ enabledUniformName: "emissiveMapEnabled"
332
+ },
333
+ gltf
334
+ });
220
335
  }
221
- switch (material.alphaMode || "MASK") {
222
- case "MASK":
336
+ parseMaterialExtensions(device, material.extensions, parsedMaterial, gltf);
337
+ switch (material.alphaMode || "OPAQUE") {
338
+ case "OPAQUE":
339
+ break;
340
+ case "MASK": {
223
341
  const { alphaCutoff = 0.5 } = material;
224
342
  parsedMaterial.defines["ALPHA_CUTOFF"] = true;
343
+ parsedMaterial.uniforms.alphaCutoffEnabled = true;
225
344
  parsedMaterial.uniforms.alphaCutoff = alphaCutoff;
226
345
  break;
346
+ }
227
347
  case "BLEND":
228
348
  import_core.log.warn("glTF BLEND alphaMode might not work well because it requires mesh sorting")();
229
- parsedMaterial.parameters.blend = true;
230
- parsedMaterial.parameters.blendColorOperation = "add";
231
- parsedMaterial.parameters.blendColorSrcFactor = "src-alpha";
232
- parsedMaterial.parameters.blendColorDstFactor = "one-minus-src-alpha";
233
- parsedMaterial.parameters.blendAlphaOperation = "add";
234
- parsedMaterial.parameters.blendAlphaSrcFactor = "one";
235
- parsedMaterial.parameters.blendAlphaDstFactor = "one-minus-src-alpha";
236
- parsedMaterial.glParameters["blend"] = true;
237
- parsedMaterial.glParameters["blendEquation"] = 32774;
238
- parsedMaterial.glParameters["blendFunc"] = [
239
- 770,
240
- 771,
241
- 1,
242
- 771
243
- ];
349
+ applyAlphaBlendParameters(parsedMaterial);
244
350
  break;
245
351
  }
246
352
  }
247
- function parsePbrMetallicRoughness(device, pbrMetallicRoughness, parsedMaterial) {
353
+ function applyAlphaBlendParameters(parsedMaterial) {
354
+ parsedMaterial.parameters.blend = true;
355
+ parsedMaterial.parameters.blendColorOperation = "add";
356
+ parsedMaterial.parameters.blendColorSrcFactor = "src-alpha";
357
+ parsedMaterial.parameters.blendColorDstFactor = "one-minus-src-alpha";
358
+ parsedMaterial.parameters.blendAlphaOperation = "add";
359
+ parsedMaterial.parameters.blendAlphaSrcFactor = "one";
360
+ parsedMaterial.parameters.blendAlphaDstFactor = "one-minus-src-alpha";
361
+ parsedMaterial.glParameters["blend"] = true;
362
+ parsedMaterial.glParameters["blendEquation"] = GLEnum.FUNC_ADD;
363
+ parsedMaterial.glParameters["blendFunc"] = [
364
+ GLEnum.SRC_ALPHA,
365
+ GLEnum.ONE_MINUS_SRC_ALPHA,
366
+ GLEnum.ONE,
367
+ GLEnum.ONE_MINUS_SRC_ALPHA
368
+ ];
369
+ }
370
+ function applyTransmissionBlendApproximation(parsedMaterial) {
371
+ parsedMaterial.parameters.blend = true;
372
+ parsedMaterial.parameters.depthWriteEnabled = false;
373
+ parsedMaterial.parameters.blendColorOperation = "add";
374
+ parsedMaterial.parameters.blendColorSrcFactor = "one";
375
+ parsedMaterial.parameters.blendColorDstFactor = "one-minus-src-alpha";
376
+ parsedMaterial.parameters.blendAlphaOperation = "add";
377
+ parsedMaterial.parameters.blendAlphaSrcFactor = "one";
378
+ parsedMaterial.parameters.blendAlphaDstFactor = "one-minus-src-alpha";
379
+ parsedMaterial.glParameters["blend"] = true;
380
+ parsedMaterial.glParameters["depthMask"] = false;
381
+ parsedMaterial.glParameters["blendEquation"] = GLEnum.FUNC_ADD;
382
+ parsedMaterial.glParameters["blendFunc"] = [
383
+ GLEnum.ONE,
384
+ GLEnum.ONE_MINUS_SRC_ALPHA,
385
+ GLEnum.ONE,
386
+ GLEnum.ONE_MINUS_SRC_ALPHA
387
+ ];
388
+ }
389
+ function parsePbrMetallicRoughness(device, pbrMetallicRoughness, parsedMaterial, gltf) {
248
390
  if (pbrMetallicRoughness.baseColorTexture) {
249
- addTexture(device, pbrMetallicRoughness.baseColorTexture, "pbr_baseColorSampler", "HAS_BASECOLORMAP", parsedMaterial);
391
+ addTexture(device, pbrMetallicRoughness.baseColorTexture, "pbr_baseColorSampler", parsedMaterial, {
392
+ featureOptions: {
393
+ define: "HAS_BASECOLORMAP",
394
+ enabledUniformName: "baseColorMapEnabled"
395
+ },
396
+ gltf
397
+ });
250
398
  }
251
399
  parsedMaterial.uniforms.baseColorFactor = pbrMetallicRoughness.baseColorFactor || [1, 1, 1, 1];
252
400
  if (pbrMetallicRoughness.metallicRoughnessTexture) {
253
- addTexture(device, pbrMetallicRoughness.metallicRoughnessTexture, "pbr_metallicRoughnessSampler", "HAS_METALROUGHNESSMAP", parsedMaterial);
401
+ addTexture(device, pbrMetallicRoughness.metallicRoughnessTexture, "pbr_metallicRoughnessSampler", parsedMaterial, {
402
+ featureOptions: {
403
+ define: "HAS_METALROUGHNESSMAP",
404
+ enabledUniformName: "metallicRoughnessMapEnabled"
405
+ },
406
+ gltf
407
+ });
254
408
  }
255
409
  const { metallicFactor = 1, roughnessFactor = 1 } = pbrMetallicRoughness;
256
410
  parsedMaterial.uniforms.metallicRoughnessValues = [metallicFactor, roughnessFactor];
257
411
  }
258
- function addTexture(device, gltfTexture, uniformName, define, parsedMaterial) {
259
- var _a;
260
- const image = gltfTexture.texture.source.image;
412
+ function parseMaterialExtensions(device, extensions, parsedMaterial, gltf) {
413
+ if (!extensions) {
414
+ return;
415
+ }
416
+ if (hasMaterialExtensionShading(extensions)) {
417
+ parsedMaterial.defines["USE_MATERIAL_EXTENSIONS"] = true;
418
+ }
419
+ parseSpecularExtension(device, extensions.KHR_materials_specular, parsedMaterial, gltf);
420
+ parseIorExtension(extensions.KHR_materials_ior, parsedMaterial);
421
+ parseTransmissionExtension(device, extensions.KHR_materials_transmission, parsedMaterial, gltf);
422
+ parseVolumeExtension(device, extensions.KHR_materials_volume, parsedMaterial, gltf);
423
+ parseClearcoatExtension(device, extensions.KHR_materials_clearcoat, parsedMaterial, gltf);
424
+ parseSheenExtension(device, extensions.KHR_materials_sheen, parsedMaterial, gltf);
425
+ parseIridescenceExtension(device, extensions.KHR_materials_iridescence, parsedMaterial, gltf);
426
+ parseAnisotropyExtension(device, extensions.KHR_materials_anisotropy, parsedMaterial, gltf);
427
+ parseEmissiveStrengthExtension(extensions.KHR_materials_emissive_strength, parsedMaterial);
428
+ }
429
+ function hasMaterialExtensionShading(extensions) {
430
+ return Boolean(extensions.KHR_materials_specular || extensions.KHR_materials_ior || extensions.KHR_materials_transmission || extensions.KHR_materials_volume || extensions.KHR_materials_clearcoat || extensions.KHR_materials_sheen || extensions.KHR_materials_iridescence || extensions.KHR_materials_anisotropy);
431
+ }
432
+ function parseSpecularExtension(device, extension, parsedMaterial, gltf) {
433
+ if (!extension) {
434
+ return;
435
+ }
436
+ if (extension.specularColorFactor) {
437
+ parsedMaterial.uniforms.specularColorFactor = extension.specularColorFactor;
438
+ }
439
+ if (extension.specularFactor !== void 0) {
440
+ parsedMaterial.uniforms.specularIntensityFactor = extension.specularFactor;
441
+ }
442
+ if (extension.specularColorTexture) {
443
+ addTexture(device, extension.specularColorTexture, "pbr_specularColorSampler", parsedMaterial, {
444
+ featureOptions: {
445
+ define: "HAS_SPECULARCOLORMAP",
446
+ enabledUniformName: "specularColorMapEnabled"
447
+ },
448
+ gltf
449
+ });
450
+ }
451
+ if (extension.specularTexture) {
452
+ addTexture(device, extension.specularTexture, "pbr_specularIntensitySampler", parsedMaterial, {
453
+ featureOptions: {
454
+ define: "HAS_SPECULARINTENSITYMAP",
455
+ enabledUniformName: "specularIntensityMapEnabled"
456
+ },
457
+ gltf
458
+ });
459
+ }
460
+ }
461
+ function parseIorExtension(extension, parsedMaterial) {
462
+ if ((extension == null ? void 0 : extension.ior) !== void 0) {
463
+ parsedMaterial.uniforms.ior = extension.ior;
464
+ }
465
+ }
466
+ function parseTransmissionExtension(device, extension, parsedMaterial, gltf) {
467
+ if (!extension) {
468
+ return;
469
+ }
470
+ if (extension.transmissionFactor !== void 0) {
471
+ parsedMaterial.uniforms.transmissionFactor = extension.transmissionFactor;
472
+ }
473
+ if (extension.transmissionTexture) {
474
+ addTexture(device, extension.transmissionTexture, "pbr_transmissionSampler", parsedMaterial, {
475
+ featureOptions: {
476
+ define: "HAS_TRANSMISSIONMAP",
477
+ enabledUniformName: "transmissionMapEnabled"
478
+ },
479
+ gltf
480
+ });
481
+ }
482
+ if ((extension.transmissionFactor ?? 0) > 0 || extension.transmissionTexture) {
483
+ import_core.log.warn("KHR_materials_transmission uses a premultiplied-alpha blending approximation and may require mesh sorting")();
484
+ applyTransmissionBlendApproximation(parsedMaterial);
485
+ }
486
+ }
487
+ function parseVolumeExtension(device, extension, parsedMaterial, gltf) {
488
+ if (!extension) {
489
+ return;
490
+ }
491
+ if (extension.thicknessFactor !== void 0) {
492
+ parsedMaterial.uniforms.thicknessFactor = extension.thicknessFactor;
493
+ }
494
+ if (extension.thicknessTexture) {
495
+ addTexture(device, extension.thicknessTexture, "pbr_thicknessSampler", parsedMaterial, {
496
+ featureOptions: {
497
+ define: "HAS_THICKNESSMAP"
498
+ },
499
+ gltf
500
+ });
501
+ }
502
+ if (extension.attenuationDistance !== void 0) {
503
+ parsedMaterial.uniforms.attenuationDistance = extension.attenuationDistance;
504
+ }
505
+ if (extension.attenuationColor) {
506
+ parsedMaterial.uniforms.attenuationColor = extension.attenuationColor;
507
+ }
508
+ }
509
+ function parseClearcoatExtension(device, extension, parsedMaterial, gltf) {
510
+ if (!extension) {
511
+ return;
512
+ }
513
+ if (extension.clearcoatFactor !== void 0) {
514
+ parsedMaterial.uniforms.clearcoatFactor = extension.clearcoatFactor;
515
+ }
516
+ if (extension.clearcoatRoughnessFactor !== void 0) {
517
+ parsedMaterial.uniforms.clearcoatRoughnessFactor = extension.clearcoatRoughnessFactor;
518
+ }
519
+ if (extension.clearcoatTexture) {
520
+ addTexture(device, extension.clearcoatTexture, "pbr_clearcoatSampler", parsedMaterial, {
521
+ featureOptions: {
522
+ define: "HAS_CLEARCOATMAP",
523
+ enabledUniformName: "clearcoatMapEnabled"
524
+ },
525
+ gltf
526
+ });
527
+ }
528
+ if (extension.clearcoatRoughnessTexture) {
529
+ addTexture(device, extension.clearcoatRoughnessTexture, "pbr_clearcoatRoughnessSampler", parsedMaterial, {
530
+ featureOptions: {
531
+ define: "HAS_CLEARCOATROUGHNESSMAP",
532
+ enabledUniformName: "clearcoatRoughnessMapEnabled"
533
+ },
534
+ gltf
535
+ });
536
+ }
537
+ if (extension.clearcoatNormalTexture) {
538
+ addTexture(device, extension.clearcoatNormalTexture, "pbr_clearcoatNormalSampler", parsedMaterial, {
539
+ featureOptions: {
540
+ define: "HAS_CLEARCOATNORMALMAP"
541
+ },
542
+ gltf
543
+ });
544
+ }
545
+ }
546
+ function parseSheenExtension(device, extension, parsedMaterial, gltf) {
547
+ if (!extension) {
548
+ return;
549
+ }
550
+ if (extension.sheenColorFactor) {
551
+ parsedMaterial.uniforms.sheenColorFactor = extension.sheenColorFactor;
552
+ }
553
+ if (extension.sheenRoughnessFactor !== void 0) {
554
+ parsedMaterial.uniforms.sheenRoughnessFactor = extension.sheenRoughnessFactor;
555
+ }
556
+ if (extension.sheenColorTexture) {
557
+ addTexture(device, extension.sheenColorTexture, "pbr_sheenColorSampler", parsedMaterial, {
558
+ featureOptions: {
559
+ define: "HAS_SHEENCOLORMAP",
560
+ enabledUniformName: "sheenColorMapEnabled"
561
+ },
562
+ gltf
563
+ });
564
+ }
565
+ if (extension.sheenRoughnessTexture) {
566
+ addTexture(device, extension.sheenRoughnessTexture, "pbr_sheenRoughnessSampler", parsedMaterial, {
567
+ featureOptions: {
568
+ define: "HAS_SHEENROUGHNESSMAP",
569
+ enabledUniformName: "sheenRoughnessMapEnabled"
570
+ },
571
+ gltf
572
+ });
573
+ }
574
+ }
575
+ function parseIridescenceExtension(device, extension, parsedMaterial, gltf) {
576
+ if (!extension) {
577
+ return;
578
+ }
579
+ if (extension.iridescenceFactor !== void 0) {
580
+ parsedMaterial.uniforms.iridescenceFactor = extension.iridescenceFactor;
581
+ }
582
+ if (extension.iridescenceIor !== void 0) {
583
+ parsedMaterial.uniforms.iridescenceIor = extension.iridescenceIor;
584
+ }
585
+ if (extension.iridescenceThicknessMinimum !== void 0 || extension.iridescenceThicknessMaximum !== void 0) {
586
+ parsedMaterial.uniforms.iridescenceThicknessRange = [
587
+ extension.iridescenceThicknessMinimum ?? 100,
588
+ extension.iridescenceThicknessMaximum ?? 400
589
+ ];
590
+ }
591
+ if (extension.iridescenceTexture) {
592
+ addTexture(device, extension.iridescenceTexture, "pbr_iridescenceSampler", parsedMaterial, {
593
+ featureOptions: {
594
+ define: "HAS_IRIDESCENCEMAP",
595
+ enabledUniformName: "iridescenceMapEnabled"
596
+ },
597
+ gltf
598
+ });
599
+ }
600
+ if (extension.iridescenceThicknessTexture) {
601
+ addTexture(device, extension.iridescenceThicknessTexture, "pbr_iridescenceThicknessSampler", parsedMaterial, {
602
+ featureOptions: {
603
+ define: "HAS_IRIDESCENCETHICKNESSMAP"
604
+ },
605
+ gltf
606
+ });
607
+ }
608
+ }
609
+ function parseAnisotropyExtension(device, extension, parsedMaterial, gltf) {
610
+ if (!extension) {
611
+ return;
612
+ }
613
+ if (extension.anisotropyStrength !== void 0) {
614
+ parsedMaterial.uniforms.anisotropyStrength = extension.anisotropyStrength;
615
+ }
616
+ if (extension.anisotropyRotation !== void 0) {
617
+ parsedMaterial.uniforms.anisotropyRotation = extension.anisotropyRotation;
618
+ }
619
+ if (extension.anisotropyTexture) {
620
+ addTexture(device, extension.anisotropyTexture, "pbr_anisotropySampler", parsedMaterial, {
621
+ featureOptions: {
622
+ define: "HAS_ANISOTROPYMAP",
623
+ enabledUniformName: "anisotropyMapEnabled"
624
+ },
625
+ gltf
626
+ });
627
+ }
628
+ }
629
+ function parseEmissiveStrengthExtension(extension, parsedMaterial) {
630
+ if ((extension == null ? void 0 : extension.emissiveStrength) !== void 0) {
631
+ parsedMaterial.uniforms.emissiveStrength = extension.emissiveStrength;
632
+ }
633
+ }
634
+ function addTexture(device, gltfTexture, uniformName, parsedMaterial, textureParseOptions = {}) {
635
+ var _a, _b, _c;
636
+ const { featureOptions = {}, gltf } = textureParseOptions;
637
+ const { define, enabledUniformName } = featureOptions;
638
+ const resolvedTextureInfo = resolveTextureInfo(gltfTexture, gltf);
639
+ const image = (_b = (_a = resolvedTextureInfo.texture) == null ? void 0 : _a.source) == null ? void 0 : _b.image;
640
+ if (!image) {
641
+ import_core.log.warn(`Skipping unresolved glTF texture for ${String(uniformName)}`)();
642
+ return;
643
+ }
261
644
  const gltfSampler = {
262
645
  wrapS: 10497,
263
646
  // default REPEAT S (U) wrapping mode.
@@ -267,10 +650,10 @@ function addTexture(device, gltfTexture, uniformName, define, parsedMaterial) {
267
650
  // default LINEAR filtering
268
651
  magFilter: 9729,
269
652
  // default LINEAR filtering
270
- ...(_a = gltfTexture == null ? void 0 : gltfTexture.texture) == null ? void 0 : _a.sampler
653
+ ...(_c = resolvedTextureInfo == null ? void 0 : resolvedTextureInfo.texture) == null ? void 0 : _c.sampler
271
654
  };
272
655
  const baseOptions = {
273
- id: gltfTexture.uniformName || gltfTexture.id,
656
+ id: resolvedTextureInfo.uniformName || resolvedTextureInfo.id,
274
657
  sampler: convertSampler(gltfSampler)
275
658
  };
276
659
  let texture;
@@ -288,8 +671,34 @@ function addTexture(device, gltfTexture, uniformName, define, parsedMaterial) {
288
671
  parsedMaterial.bindings[uniformName] = texture;
289
672
  if (define)
290
673
  parsedMaterial.defines[define] = true;
674
+ if (enabledUniformName) {
675
+ parsedMaterial.uniforms[enabledUniformName] = true;
676
+ }
291
677
  parsedMaterial.generatedTextures.push(texture);
292
678
  }
679
+ function resolveTextureInfo(gltfTexture, gltf) {
680
+ if (gltfTexture.texture || gltfTexture.index === void 0 || !(gltf == null ? void 0 : gltf.textures)) {
681
+ return gltfTexture;
682
+ }
683
+ const resolvedTextureEntry = gltf.textures[gltfTexture.index];
684
+ if (!resolvedTextureEntry) {
685
+ return gltfTexture;
686
+ }
687
+ if ("texture" in resolvedTextureEntry && resolvedTextureEntry.texture) {
688
+ return {
689
+ ...resolvedTextureEntry,
690
+ ...gltfTexture,
691
+ texture: resolvedTextureEntry.texture
692
+ };
693
+ }
694
+ if (!("source" in resolvedTextureEntry)) {
695
+ return gltfTexture;
696
+ }
697
+ return {
698
+ ...gltfTexture,
699
+ texture: resolvedTextureEntry
700
+ };
701
+ }
293
702
  function createCompressedTextureFallback(device, baseOptions) {
294
703
  return device.createTexture({
295
704
  ...baseOptions,
@@ -383,6 +792,7 @@ function createCompressedTexture(device, image, baseOptions) {
383
792
 
384
793
  // dist/parsers/parse-gltf-lights.js
385
794
  var import_core2 = require("@math.gl/core");
795
+ var GLTF_COLOR_FACTOR = 255;
386
796
  function parseGLTFLights(gltf) {
387
797
  var _a, _b, _c, _d;
388
798
  const lightDefs = (
@@ -393,6 +803,8 @@ function parseGLTFLights(gltf) {
393
803
  return [];
394
804
  }
395
805
  const lights = [];
806
+ const parentNodeById = createParentNodeMap(gltf.nodes || []);
807
+ const worldMatrixByNodeId = /* @__PURE__ */ new Map();
396
808
  for (const node of gltf.nodes || []) {
397
809
  const lightIndex = node.light ?? ((_d = (_c = node.extensions) == null ? void 0 : _c.KHR_lights_punctual) == null ? void 0 : _d.light);
398
810
  if (typeof lightIndex !== "number") {
@@ -402,18 +814,19 @@ function parseGLTFLights(gltf) {
402
814
  if (!gltfLight) {
403
815
  continue;
404
816
  }
405
- const color = gltfLight.color || [1, 1, 1];
817
+ const color = normalizeGLTFLightColor(gltfLight.color || [1, 1, 1]);
406
818
  const intensity = gltfLight.intensity ?? 1;
407
819
  const range = gltfLight.range;
820
+ const worldMatrix = getNodeWorldMatrix(node, parentNodeById, worldMatrixByNodeId);
408
821
  switch (gltfLight.type) {
409
822
  case "directional":
410
- lights.push(parseDirectionalLight(node, color, intensity));
823
+ lights.push(parseDirectionalLight(worldMatrix, color, intensity));
411
824
  break;
412
825
  case "point":
413
- lights.push(parsePointLight(node, color, intensity, range));
826
+ lights.push(parsePointLight(worldMatrix, color, intensity, range));
414
827
  break;
415
828
  case "spot":
416
- lights.push(parsePointLight(node, color, intensity, range));
829
+ lights.push(parseSpotLight(worldMatrix, color, intensity, range, gltfLight.spot));
417
830
  break;
418
831
  default:
419
832
  break;
@@ -421,8 +834,11 @@ function parseGLTFLights(gltf) {
421
834
  }
422
835
  return lights;
423
836
  }
424
- function parsePointLight(node, color, intensity, range) {
425
- const position = getNodePosition(node);
837
+ function normalizeGLTFLightColor(color) {
838
+ return color.map((component) => component * GLTF_COLOR_FACTOR);
839
+ }
840
+ function parsePointLight(worldMatrix, color, intensity, range) {
841
+ const position = getLightPosition(worldMatrix);
426
842
  let attenuation = [1, 0, 0];
427
843
  if (range !== void 0 && range > 0) {
428
844
  attenuation = [1, 0, 1 / (range * range)];
@@ -435,8 +851,8 @@ function parsePointLight(node, color, intensity, range) {
435
851
  attenuation
436
852
  };
437
853
  }
438
- function parseDirectionalLight(node, color, intensity) {
439
- const direction = getNodeDirection(node);
854
+ function parseDirectionalLight(worldMatrix, color, intensity) {
855
+ const direction = getLightDirection(worldMatrix);
440
856
  return {
441
857
  type: "directional",
442
858
  direction,
@@ -444,39 +860,72 @@ function parseDirectionalLight(node, color, intensity) {
444
860
  intensity
445
861
  };
446
862
  }
447
- function getNodePosition(node) {
448
- if (node.matrix) {
449
- return new import_core2.Matrix4(node.matrix).transformAsPoint([0, 0, 0]);
863
+ function parseSpotLight(worldMatrix, color, intensity, range, spot = {}) {
864
+ const position = getLightPosition(worldMatrix);
865
+ const direction = getLightDirection(worldMatrix);
866
+ let attenuation = [1, 0, 0];
867
+ if (range !== void 0 && range > 0) {
868
+ attenuation = [1, 0, 1 / (range * range)];
450
869
  }
451
- if (node.translation) {
452
- return [...node.translation];
870
+ return {
871
+ type: "spot",
872
+ position,
873
+ direction,
874
+ color,
875
+ intensity,
876
+ attenuation,
877
+ innerConeAngle: spot.innerConeAngle ?? 0,
878
+ outerConeAngle: spot.outerConeAngle ?? Math.PI / 4
879
+ };
880
+ }
881
+ function createParentNodeMap(nodes) {
882
+ const parentNodeById = /* @__PURE__ */ new Map();
883
+ for (const node of nodes) {
884
+ for (const childNode of node.children || []) {
885
+ parentNodeById.set(childNode.id, node);
886
+ }
887
+ }
888
+ return parentNodeById;
889
+ }
890
+ function getNodeWorldMatrix(node, parentNodeById, worldMatrixByNodeId) {
891
+ const cachedWorldMatrix = worldMatrixByNodeId.get(node.id);
892
+ if (cachedWorldMatrix) {
893
+ return cachedWorldMatrix;
453
894
  }
454
- return [0, 0, 0];
895
+ const localMatrix = getNodeLocalMatrix(node);
896
+ const parentNode = parentNodeById.get(node.id);
897
+ const worldMatrix = parentNode ? new import_core2.Matrix4(getNodeWorldMatrix(parentNode, parentNodeById, worldMatrixByNodeId)).multiplyRight(localMatrix) : localMatrix;
898
+ worldMatrixByNodeId.set(node.id, worldMatrix);
899
+ return worldMatrix;
455
900
  }
456
- function getNodeDirection(node) {
901
+ function getNodeLocalMatrix(node) {
457
902
  if (node.matrix) {
458
- return new import_core2.Matrix4(node.matrix).transformDirection([0, 0, -1]);
903
+ return new import_core2.Matrix4(node.matrix);
904
+ }
905
+ const matrix = new import_core2.Matrix4();
906
+ if (node.translation) {
907
+ matrix.translate(node.translation);
459
908
  }
460
909
  if (node.rotation) {
461
- return new import_core2.Matrix4().fromQuaternion(node.rotation).transformDirection([0, 0, -1]);
910
+ matrix.multiplyRight(new import_core2.Matrix4().fromQuaternion(node.rotation));
911
+ }
912
+ if (node.scale) {
913
+ matrix.scale(node.scale);
462
914
  }
463
- return [0, 0, -1];
915
+ return matrix;
916
+ }
917
+ function getLightPosition(worldMatrix) {
918
+ return worldMatrix.transformAsPoint([0, 0, 0]);
919
+ }
920
+ function getLightDirection(worldMatrix) {
921
+ return worldMatrix.transformDirection([0, 0, -1]);
464
922
  }
465
923
 
466
924
  // dist/parsers/parse-gltf.js
467
- var import_engine3 = require("@luma.gl/engine");
925
+ var import_engine4 = require("@luma.gl/engine");
926
+ var import_shadertools2 = require("@luma.gl/shadertools");
468
927
 
469
928
  // dist/webgl-to-webgpu/convert-webgl-topology.js
470
- var GLEnum;
471
- (function(GLEnum2) {
472
- GLEnum2[GLEnum2["POINTS"] = 0] = "POINTS";
473
- GLEnum2[GLEnum2["LINES"] = 1] = "LINES";
474
- GLEnum2[GLEnum2["LINE_LOOP"] = 2] = "LINE_LOOP";
475
- GLEnum2[GLEnum2["LINE_STRIP"] = 3] = "LINE_STRIP";
476
- GLEnum2[GLEnum2["TRIANGLES"] = 4] = "TRIANGLES";
477
- GLEnum2[GLEnum2["TRIANGLE_STRIP"] = 5] = "TRIANGLE_STRIP";
478
- GLEnum2[GLEnum2["TRIANGLE_FAN"] = 6] = "TRIANGLE_FAN";
479
- })(GLEnum || (GLEnum = {}));
480
929
  function convertGLDrawModeToTopology(drawMode) {
481
930
  switch (drawMode) {
482
931
  case GLEnum.POINTS:
@@ -496,8 +945,9 @@ function convertGLDrawModeToTopology(drawMode) {
496
945
 
497
946
  // dist/gltf/create-gltf-model.js
498
947
  var import_core3 = require("@luma.gl/core");
499
- var import_shadertools = require("@luma.gl/shadertools");
500
948
  var import_engine2 = require("@luma.gl/engine");
949
+ var import_shadertools = require("@luma.gl/shadertools");
950
+ var import_engine3 = require("@luma.gl/engine");
501
951
  var SHADER = (
502
952
  /* WGSL */
503
953
  `
@@ -653,6 +1103,21 @@ var fs = (
653
1103
  }
654
1104
  `
655
1105
  );
1106
+ function createGLTFMaterial(device, options) {
1107
+ const materialFactory = options.materialFactory || new import_engine3.MaterialFactory(device, { modules: [import_shadertools.pbrMaterial] });
1108
+ const pbrMaterialProps = { ...options.parsedPPBRMaterial.uniforms };
1109
+ delete pbrMaterialProps.camera;
1110
+ const materialBindings = Object.fromEntries(Object.entries({
1111
+ ...pbrMaterialProps,
1112
+ ...options.parsedPPBRMaterial.bindings
1113
+ }).filter(([name, value]) => materialFactory.ownsBinding(name) && isMaterialBindingResource(value)));
1114
+ const material = materialFactory.createMaterial({
1115
+ id: options.id,
1116
+ bindings: materialBindings
1117
+ });
1118
+ material.setProps({ pbrMaterial: pbrMaterialProps });
1119
+ return material;
1120
+ }
656
1121
  function createGLTFModel(device, options) {
657
1122
  const { id, geometry, parsedPPBRMaterial, vertexCount, modelOptions = {} } = options;
658
1123
  import_core3.log.info(4, "createGLTFModel defines: ", parsedPPBRMaterial.defines)();
@@ -676,15 +1141,48 @@ function createGLTFModel(device, options) {
676
1141
  defines: { ...parsedPPBRMaterial.defines, ...modelOptions.defines },
677
1142
  parameters: { ...parameters, ...parsedPPBRMaterial.parameters, ...modelOptions.parameters }
678
1143
  };
679
- const model = new import_engine2.Model(device, modelProps);
680
- const { camera, ...pbrMaterialProps } = {
1144
+ const material = options.material || createGLTFMaterial(device, {
1145
+ id: id ? `${id}-material` : void 0,
1146
+ parsedPPBRMaterial
1147
+ });
1148
+ modelProps.material = material;
1149
+ const model = new import_engine3.Model(device, modelProps);
1150
+ const sceneShaderInputValues = {
681
1151
  ...parsedPPBRMaterial.uniforms,
682
1152
  ...modelOptions.uniforms,
683
1153
  ...parsedPPBRMaterial.bindings,
684
1154
  ...modelOptions.bindings
685
1155
  };
686
- model.shaderInputs.setProps({ pbrMaterial: pbrMaterialProps, pbrProjection: { camera } });
687
- return new import_engine2.ModelNode({ managedResources, model });
1156
+ const sceneShaderInputProps = getSceneShaderInputProps(model.shaderInputs.getModules(), material, sceneShaderInputValues);
1157
+ model.shaderInputs.setProps(sceneShaderInputProps);
1158
+ return new import_engine3.ModelNode({ managedResources, model });
1159
+ }
1160
+ function isMaterialBindingResource(value) {
1161
+ return value instanceof import_core3.Buffer || value instanceof import_engine2.DynamicTexture || value instanceof import_core3.Sampler || value instanceof import_core3.Texture || value instanceof import_core3.TextureView;
1162
+ }
1163
+ function getSceneShaderInputProps(modules, material, shaderInputValues) {
1164
+ const propertyToModuleNameMap = /* @__PURE__ */ new Map();
1165
+ for (const module2 of modules) {
1166
+ for (const uniformName of Object.keys(module2.uniformTypes || {})) {
1167
+ propertyToModuleNameMap.set(uniformName, module2.name);
1168
+ }
1169
+ for (const binding of module2.bindingLayout || []) {
1170
+ propertyToModuleNameMap.set(binding.name, module2.name);
1171
+ }
1172
+ }
1173
+ const sceneShaderInputProps = {};
1174
+ for (const [propertyName, value] of Object.entries(shaderInputValues)) {
1175
+ if (value === void 0) {
1176
+ continue;
1177
+ }
1178
+ const moduleName = propertyToModuleNameMap.get(propertyName);
1179
+ if (!moduleName || material.ownsModule(moduleName)) {
1180
+ continue;
1181
+ }
1182
+ sceneShaderInputProps[moduleName] ||= {};
1183
+ sceneShaderInputProps[moduleName][propertyName] = value;
1184
+ }
1185
+ return sceneShaderInputProps;
688
1186
  }
689
1187
 
690
1188
  // dist/parsers/parse-gltf.js
@@ -697,9 +1195,23 @@ var defaultOptions = {
697
1195
  };
698
1196
  function parseGLTF(device, gltf, options = {}) {
699
1197
  const combinedOptions = { ...defaultOptions, ...options };
1198
+ const materialFactory = new import_engine4.MaterialFactory(device, { modules: [import_shadertools2.pbrMaterial] });
1199
+ const materials = (gltf.materials || []).map((gltfMaterial, materialIndex) => createGLTFMaterial(device, {
1200
+ id: getGLTFMaterialId(gltfMaterial, materialIndex),
1201
+ parsedPPBRMaterial: parsePBRMaterial(device, gltfMaterial, {}, {
1202
+ ...combinedOptions,
1203
+ gltf,
1204
+ validateAttributes: false
1205
+ }),
1206
+ materialFactory
1207
+ }));
1208
+ const gltfMaterialIdToMaterialMap = /* @__PURE__ */ new Map();
1209
+ (gltf.materials || []).forEach((gltfMaterial, materialIndex) => {
1210
+ gltfMaterialIdToMaterialMap.set(gltfMaterial.id, materials[materialIndex]);
1211
+ });
700
1212
  const gltfMeshIdToNodeMap = /* @__PURE__ */ new Map();
701
1213
  gltf.meshes.forEach((gltfMesh, idx) => {
702
- const newMesh = createNodeForGLTFMesh(device, gltfMesh, combinedOptions);
1214
+ const newMesh = createNodeForGLTFMesh(device, gltfMesh, gltf, gltfMaterialIdToMaterialMap, combinedOptions);
703
1215
  gltfMeshIdToNodeMap.set(gltfMesh.id, newMesh);
704
1216
  });
705
1217
  const gltfNodeIndexToNodeMap = /* @__PURE__ */ new Map();
@@ -731,15 +1243,15 @@ function parseGLTF(device, gltf, options = {}) {
731
1243
  throw new Error(`Cannot find child ${id} of scene ${gltfScene.name || gltfScene.id}`);
732
1244
  return child;
733
1245
  });
734
- return new import_engine3.GroupNode({
1246
+ return new import_engine4.GroupNode({
735
1247
  id: gltfScene.name || gltfScene.id,
736
1248
  children
737
1249
  });
738
1250
  });
739
- return { scenes, gltfMeshIdToNodeMap, gltfNodeIdToNodeMap, gltfNodeIndexToNodeMap };
1251
+ return { scenes, materials, gltfMeshIdToNodeMap, gltfNodeIdToNodeMap, gltfNodeIndexToNodeMap };
740
1252
  }
741
1253
  function createNodeForGLTFNode(device, gltfNode, options) {
742
- return new import_engine3.GroupNode({
1254
+ return new import_engine4.GroupNode({
743
1255
  id: gltfNode.name || gltfNode.id,
744
1256
  children: [],
745
1257
  matrix: gltfNode.matrix,
@@ -748,24 +1260,36 @@ function createNodeForGLTFNode(device, gltfNode, options) {
748
1260
  scale: gltfNode.scale
749
1261
  });
750
1262
  }
751
- function createNodeForGLTFMesh(device, gltfMesh, options) {
1263
+ function createNodeForGLTFMesh(device, gltfMesh, gltf, gltfMaterialIdToMaterialMap, options) {
752
1264
  const gltfPrimitives = gltfMesh.primitives || [];
753
- const primitives = gltfPrimitives.map((gltfPrimitive, i) => createNodeForGLTFPrimitive(device, gltfPrimitive, i, gltfMesh, options));
754
- const mesh = new import_engine3.GroupNode({
1265
+ const primitives = gltfPrimitives.map((gltfPrimitive, i) => createNodeForGLTFPrimitive({
1266
+ device,
1267
+ gltfPrimitive,
1268
+ primitiveIndex: i,
1269
+ gltfMesh,
1270
+ gltf,
1271
+ gltfMaterialIdToMaterialMap,
1272
+ options
1273
+ }));
1274
+ const mesh = new import_engine4.GroupNode({
755
1275
  id: gltfMesh.name || gltfMesh.id,
756
1276
  children: primitives
757
1277
  });
758
1278
  return mesh;
759
1279
  }
760
- function createNodeForGLTFPrimitive(device, gltfPrimitive, i, gltfMesh, options) {
761
- const id = gltfPrimitive.name || `${gltfMesh.name || gltfMesh.id}-primitive-${i}`;
1280
+ function createNodeForGLTFPrimitive({ device, gltfPrimitive, primitiveIndex, gltfMesh, gltf, gltfMaterialIdToMaterialMap, options }) {
1281
+ const id = gltfPrimitive.name || `${gltfMesh.name || gltfMesh.id}-primitive-${primitiveIndex}`;
762
1282
  const topology = convertGLDrawModeToTopology(gltfPrimitive.mode || 4);
763
1283
  const vertexCount = gltfPrimitive.indices ? gltfPrimitive.indices.count : getVertexCount(gltfPrimitive.attributes);
764
1284
  const geometry = createGeometry(id, gltfPrimitive, topology);
765
- const parsedPPBRMaterial = parsePBRMaterial(device, gltfPrimitive.material, geometry.attributes, options);
1285
+ const parsedPPBRMaterial = parsePBRMaterial(device, gltfPrimitive.material, geometry.attributes, {
1286
+ ...options,
1287
+ gltf
1288
+ });
766
1289
  const modelNode = createGLTFModel(device, {
767
1290
  id,
768
1291
  geometry: createGeometry(id, gltfPrimitive, topology),
1292
+ material: gltfPrimitive.material ? gltfMaterialIdToMaterialMap.get(gltfPrimitive.material.id) || null : null,
769
1293
  parsedPPBRMaterial,
770
1294
  modelOptions: options.modelOptions,
771
1295
  vertexCount
@@ -782,13 +1306,16 @@ function createGeometry(id, gltfPrimitive, topology) {
782
1306
  const { components, size, value } = attribute;
783
1307
  attributes[attributeName] = { size: size ?? components, value };
784
1308
  }
785
- return new import_engine3.Geometry({
1309
+ return new import_engine4.Geometry({
786
1310
  id,
787
1311
  topology,
788
1312
  indices: gltfPrimitive.indices.value,
789
1313
  attributes
790
1314
  });
791
1315
  }
1316
+ function getGLTFMaterialId(gltfMaterial, materialIndex) {
1317
+ return gltfMaterial.name || gltfMaterial.id || `material-${materialIndex}`;
1318
+ }
792
1319
 
793
1320
  // dist/gltf/gltf-animator.js
794
1321
  var import_core6 = require("@luma.gl/core");
@@ -929,6 +1456,9 @@ var GLTFAnimator = class {
929
1456
  }
930
1457
  };
931
1458
 
1459
+ // dist/parsers/parse-gltf-animations.js
1460
+ var import_core7 = require("@luma.gl/core");
1461
+
932
1462
  // dist/webgl-to-webgpu/convert-webgl-attribute.js
933
1463
  var ATTRIBUTE_TYPE_TO_COMPONENTS = {
934
1464
  SCALAR: 1,
@@ -962,27 +1492,48 @@ function parseGLTFAnimations(gltf) {
962
1492
  const gltfAnimations = gltf.animations || [];
963
1493
  const accessorCache1D = /* @__PURE__ */ new Map();
964
1494
  const accessorCache2D = /* @__PURE__ */ new Map();
965
- return gltfAnimations.map((animation, index) => {
1495
+ return gltfAnimations.flatMap((animation, index) => {
966
1496
  const name = animation.name || `Animation-${index}`;
967
- const samplers = animation.samplers.map(({ input, interpolation = "LINEAR", output }) => ({
968
- input: accessorToJsArray1D(gltf.accessors[input], accessorCache1D),
969
- interpolation,
970
- output: accessorToJsArray2D(gltf.accessors[output], accessorCache2D)
971
- }));
972
- const channels = animation.channels.map(({ sampler, target }) => {
1497
+ const samplerCache = /* @__PURE__ */ new Map();
1498
+ const channels = animation.channels.flatMap(({ sampler, target }) => {
1499
+ const path = getSupportedAnimationPath(target.path);
1500
+ if (!path) {
1501
+ return [];
1502
+ }
973
1503
  const targetNode = gltf.nodes[target.node ?? 0];
974
1504
  if (!targetNode) {
975
1505
  throw new Error(`Cannot find animation target ${target.node}`);
976
1506
  }
1507
+ let parsedSampler = samplerCache.get(sampler);
1508
+ if (!parsedSampler) {
1509
+ const gltfSampler = animation.samplers[sampler];
1510
+ if (!gltfSampler) {
1511
+ throw new Error(`Cannot find animation sampler ${sampler}`);
1512
+ }
1513
+ const { input, interpolation = "LINEAR", output } = gltfSampler;
1514
+ parsedSampler = {
1515
+ input: accessorToJsArray1D(gltf.accessors[input], accessorCache1D),
1516
+ interpolation,
1517
+ output: accessorToJsArray2D(gltf.accessors[output], accessorCache2D)
1518
+ };
1519
+ samplerCache.set(sampler, parsedSampler);
1520
+ }
977
1521
  return {
978
- sampler: samplers[sampler],
1522
+ sampler: parsedSampler,
979
1523
  targetNodeId: targetNode.id,
980
- path: target.path
1524
+ path
981
1525
  };
982
1526
  });
983
- return { name, channels };
1527
+ return channels.length ? [{ name, channels }] : [];
984
1528
  });
985
1529
  }
1530
+ function getSupportedAnimationPath(path) {
1531
+ if (path === "pointer") {
1532
+ import_core7.log.warn("KHR_animation_pointer channels are not supported and will be skipped")();
1533
+ return null;
1534
+ }
1535
+ return path;
1536
+ }
986
1537
  function accessorToJsArray1D(accessor, accessorCache) {
987
1538
  if (accessorCache.has(accessor)) {
988
1539
  return accessorCache.get(accessor);
@@ -998,7 +1549,7 @@ function accessorToJsArray2D(accessor, accessorCache) {
998
1549
  return accessorCache.get(accessor);
999
1550
  }
1000
1551
  const { typedArray: array, components } = accessorToTypedArray(accessor);
1001
- assert(components > 1, "accessorToJsArray2D must have more than 1 component");
1552
+ assert(components >= 1, "accessorToJsArray2D must have at least 1 component");
1002
1553
  const result = [];
1003
1554
  for (let i = 0; i < array.length; i += components) {
1004
1555
  result.push(Array.from(array.slice(i, i + components)));
@@ -1012,20 +1563,254 @@ function assert(condition, message) {
1012
1563
  }
1013
1564
  }
1014
1565
 
1566
+ // dist/gltf/gltf-extension-support.js
1567
+ var UNKNOWN_EXTENSION_SUPPORT = {
1568
+ supportLevel: "none",
1569
+ comment: "Not currently listed in the luma.gl glTF extension support registry."
1570
+ };
1571
+ var GLTF_EXTENSION_SUPPORT_REGISTRY = {
1572
+ KHR_draco_mesh_compression: {
1573
+ supportLevel: "built-in",
1574
+ comment: "Decoded by loaders.gl before luma.gl builds the scenegraph."
1575
+ },
1576
+ EXT_meshopt_compression: {
1577
+ supportLevel: "built-in",
1578
+ comment: "Meshopt-compressed primitives are decoded during load."
1579
+ },
1580
+ KHR_mesh_quantization: {
1581
+ supportLevel: "built-in",
1582
+ comment: "Quantized accessors are unpacked before geometry creation."
1583
+ },
1584
+ KHR_lights_punctual: {
1585
+ supportLevel: "built-in",
1586
+ comment: "Parsed into luma.gl Light objects."
1587
+ },
1588
+ KHR_materials_unlit: {
1589
+ supportLevel: "built-in",
1590
+ comment: "Unlit materials bypass the default lighting path."
1591
+ },
1592
+ KHR_materials_emissive_strength: {
1593
+ supportLevel: "built-in",
1594
+ comment: "Applied by the stock PBR shader."
1595
+ },
1596
+ KHR_texture_basisu: {
1597
+ supportLevel: "built-in",
1598
+ comment: "BasisU / KTX2 textures pass through when the device supports them."
1599
+ },
1600
+ KHR_texture_transform: {
1601
+ supportLevel: "built-in",
1602
+ comment: "UV transforms are applied during load."
1603
+ },
1604
+ EXT_texture_webp: {
1605
+ supportLevel: "loader-only",
1606
+ comment: "Texture source is resolved during load; final support depends on browser and device decode support."
1607
+ },
1608
+ EXT_texture_avif: {
1609
+ supportLevel: "loader-only",
1610
+ comment: "Texture source is resolved during load; final support depends on browser and device decode support."
1611
+ },
1612
+ KHR_materials_specular: {
1613
+ supportLevel: "built-in",
1614
+ comment: "The stock shader now applies specular factors and textures to the dielectric F0 term."
1615
+ },
1616
+ KHR_materials_ior: {
1617
+ supportLevel: "built-in",
1618
+ comment: "The stock shader now drives dielectric reflectance from the glTF IOR value."
1619
+ },
1620
+ KHR_materials_transmission: {
1621
+ supportLevel: "built-in",
1622
+ comment: "The stock shader now applies transmission to the base layer and exposes transparency through alpha, without a scene-color refraction buffer."
1623
+ },
1624
+ KHR_materials_volume: {
1625
+ supportLevel: "built-in",
1626
+ comment: "Thickness and attenuation now tint transmitted light in the stock shader."
1627
+ },
1628
+ KHR_materials_clearcoat: {
1629
+ supportLevel: "built-in",
1630
+ comment: "The stock shader now adds a secondary clearcoat specular lobe."
1631
+ },
1632
+ KHR_materials_sheen: {
1633
+ supportLevel: "built-in",
1634
+ comment: "The stock shader now adds a sheen lobe for cloth-like materials."
1635
+ },
1636
+ KHR_materials_iridescence: {
1637
+ supportLevel: "built-in",
1638
+ comment: "The stock shader now tints specular response with a view-dependent thin-film iridescence approximation."
1639
+ },
1640
+ KHR_materials_anisotropy: {
1641
+ supportLevel: "built-in",
1642
+ comment: "The stock shader now shapes highlights and IBL response with an anisotropy-direction approximation."
1643
+ },
1644
+ KHR_materials_pbrSpecularGlossiness: {
1645
+ supportLevel: "loader-only",
1646
+ comment: "Extension data can be loaded, but it is not translated into the default metallic-roughness material path."
1647
+ },
1648
+ KHR_materials_variants: {
1649
+ supportLevel: "loader-only",
1650
+ comment: "Variant metadata can be loaded, but applications must choose and apply variants."
1651
+ },
1652
+ EXT_mesh_gpu_instancing: {
1653
+ supportLevel: "none",
1654
+ comment: "GPU instancing data is not yet converted into luma.gl instanced draw setup."
1655
+ },
1656
+ KHR_node_visibility: {
1657
+ supportLevel: "none",
1658
+ comment: "Node-visibility animations and toggles are not mapped onto runtime scenegraph state."
1659
+ },
1660
+ KHR_animation_pointer: {
1661
+ supportLevel: "none",
1662
+ comment: "Animation pointers are not mapped onto runtime scenegraph updates."
1663
+ },
1664
+ KHR_materials_diffuse_transmission: {
1665
+ supportLevel: "none",
1666
+ comment: "Diffuse-transmission shading is not implemented in the stock PBR shader."
1667
+ },
1668
+ KHR_materials_dispersion: {
1669
+ supportLevel: "none",
1670
+ comment: "Chromatic dispersion is not implemented in the stock PBR shader."
1671
+ },
1672
+ KHR_materials_volume_scatter: {
1673
+ supportLevel: "none",
1674
+ comment: "Volume scattering is not implemented in the stock PBR shader."
1675
+ },
1676
+ KHR_xmp: {
1677
+ supportLevel: "none",
1678
+ comment: "Metadata payloads remain in the loaded glTF, but luma.gl does not interpret them."
1679
+ },
1680
+ KHR_xmp_json_ld: {
1681
+ supportLevel: "none",
1682
+ comment: "Metadata is preserved in the glTF, but luma.gl does not interpret it."
1683
+ },
1684
+ EXT_lights_image_based: {
1685
+ supportLevel: "none",
1686
+ comment: "Use loadPBREnvironment() or custom environment setup instead."
1687
+ },
1688
+ EXT_texture_video: {
1689
+ supportLevel: "none",
1690
+ comment: "Video textures are not created automatically by the stock pipeline."
1691
+ },
1692
+ MSFT_lod: {
1693
+ supportLevel: "none",
1694
+ comment: "Level-of-detail switching is not implemented in the stock scenegraph loader."
1695
+ }
1696
+ };
1697
+ function getGLTFExtensionSupport(gltf) {
1698
+ const extensionNames = Array.from(collectGLTFExtensionNames(gltf)).sort();
1699
+ const extensionSupportEntries = extensionNames.map((extensionName) => {
1700
+ const extensionSupportDefinition = GLTF_EXTENSION_SUPPORT_REGISTRY[extensionName] || UNKNOWN_EXTENSION_SUPPORT;
1701
+ return [
1702
+ extensionName,
1703
+ {
1704
+ extensionName,
1705
+ supported: extensionSupportDefinition.supportLevel === "built-in",
1706
+ supportLevel: extensionSupportDefinition.supportLevel,
1707
+ comment: extensionSupportDefinition.comment
1708
+ }
1709
+ ];
1710
+ });
1711
+ return new Map(extensionSupportEntries);
1712
+ }
1713
+ function collectGLTFExtensionNames(gltf) {
1714
+ var _a;
1715
+ const gltfWithRemovedExtensions = gltf;
1716
+ const extensionNames = /* @__PURE__ */ new Set();
1717
+ addExtensionNames(extensionNames, gltf.extensionsUsed);
1718
+ addExtensionNames(extensionNames, gltf.extensionsRequired);
1719
+ addExtensionNames(extensionNames, gltfWithRemovedExtensions.extensionsRemoved);
1720
+ addExtensionNames(extensionNames, Object.keys(gltf.extensions || {}));
1721
+ if (((_a = gltfWithRemovedExtensions.lights) == null ? void 0 : _a.length) || gltf.nodes.some((node) => "light" in node)) {
1722
+ extensionNames.add("KHR_lights_punctual");
1723
+ }
1724
+ if (gltf.materials.some((material) => {
1725
+ var _a2;
1726
+ const gltfMaterial = material;
1727
+ return gltfMaterial.unlit || ((_a2 = gltfMaterial.extensions) == null ? void 0 : _a2.KHR_materials_unlit);
1728
+ })) {
1729
+ extensionNames.add("KHR_materials_unlit");
1730
+ }
1731
+ return extensionNames;
1732
+ }
1733
+ function addExtensionNames(extensionNames, newExtensionNames = []) {
1734
+ for (const extensionName of newExtensionNames) {
1735
+ extensionNames.add(extensionName);
1736
+ }
1737
+ }
1738
+
1015
1739
  // dist/gltf/create-scenegraph-from-gltf.js
1016
1740
  function createScenegraphsFromGLTF(device, gltf, options) {
1017
- const { scenes, gltfMeshIdToNodeMap, gltfNodeIdToNodeMap, gltfNodeIndexToNodeMap } = parseGLTF(device, gltf, options);
1741
+ const { scenes, materials, gltfMeshIdToNodeMap, gltfNodeIdToNodeMap, gltfNodeIndexToNodeMap } = parseGLTF(device, gltf, options);
1018
1742
  const animations = parseGLTFAnimations(gltf);
1019
1743
  const animator = new GLTFAnimator({ animations, gltfNodeIdToNodeMap });
1020
1744
  const lights = parseGLTFLights(gltf);
1745
+ const extensionSupport = getGLTFExtensionSupport(gltf);
1746
+ const sceneBounds = scenes.map((scene) => getScenegraphBounds(scene.getBounds()));
1747
+ const modelBounds = getCombinedScenegraphBounds(sceneBounds);
1021
1748
  return {
1022
1749
  scenes,
1750
+ materials,
1023
1751
  animator,
1024
1752
  lights,
1753
+ extensionSupport,
1754
+ sceneBounds,
1755
+ modelBounds,
1025
1756
  gltfMeshIdToNodeMap,
1026
1757
  gltfNodeIdToNodeMap,
1027
1758
  gltfNodeIndexToNodeMap,
1028
1759
  gltf
1029
1760
  };
1030
1761
  }
1762
+ function getScenegraphBounds(bounds) {
1763
+ if (!bounds) {
1764
+ return {
1765
+ bounds: null,
1766
+ center: [0, 0, 0],
1767
+ size: [0, 0, 0],
1768
+ radius: 0.5,
1769
+ recommendedOrbitDistance: 1
1770
+ };
1771
+ }
1772
+ const normalizedBounds = [
1773
+ [bounds[0][0], bounds[0][1], bounds[0][2]],
1774
+ [bounds[1][0], bounds[1][1], bounds[1][2]]
1775
+ ];
1776
+ const size = [
1777
+ normalizedBounds[1][0] - normalizedBounds[0][0],
1778
+ normalizedBounds[1][1] - normalizedBounds[0][1],
1779
+ normalizedBounds[1][2] - normalizedBounds[0][2]
1780
+ ];
1781
+ const center = [
1782
+ normalizedBounds[0][0] + size[0] * 0.5,
1783
+ normalizedBounds[0][1] + size[1] * 0.5,
1784
+ normalizedBounds[0][2] + size[2] * 0.5
1785
+ ];
1786
+ const maxHalfExtent = Math.max(size[0], size[1], size[2]) * 0.5;
1787
+ const radius = Math.max(0.5 * Math.hypot(size[0], size[1], size[2]), 1e-3);
1788
+ return {
1789
+ bounds: normalizedBounds,
1790
+ center,
1791
+ size,
1792
+ radius,
1793
+ recommendedOrbitDistance: Math.max(Math.max(maxHalfExtent, 1e-3) / Math.tan(Math.PI / 6) * 1.15, radius * 1.1)
1794
+ };
1795
+ }
1796
+ function getCombinedScenegraphBounds(sceneBounds) {
1797
+ let combinedBounds = null;
1798
+ for (const sceneBoundInfo of sceneBounds) {
1799
+ if (!sceneBoundInfo.bounds) {
1800
+ continue;
1801
+ }
1802
+ if (!combinedBounds) {
1803
+ combinedBounds = [
1804
+ [...sceneBoundInfo.bounds[0]],
1805
+ [...sceneBoundInfo.bounds[1]]
1806
+ ];
1807
+ continue;
1808
+ }
1809
+ for (let axis = 0; axis < 3; axis++) {
1810
+ combinedBounds[0][axis] = Math.min(combinedBounds[0][axis], sceneBoundInfo.bounds[0][axis]);
1811
+ combinedBounds[1][axis] = Math.max(combinedBounds[1][axis], sceneBoundInfo.bounds[1][axis]);
1812
+ }
1813
+ }
1814
+ return getScenegraphBounds(combinedBounds);
1815
+ }
1031
1816
  //# sourceMappingURL=index.cjs.map