@onerjs/loaders 8.51.6 → 8.51.7

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.
@@ -107,13 +107,19 @@ export function LoadBoundingInfoFromPositionAccessor(accessor) {
107
107
  */
108
108
  export class GLTFLoader {
109
109
  /**
110
- * Test if the given material is of the same type as the one used by the loader
110
+ * Test if the given material is an instance of any PBR material type known to this loader.
111
111
  * @param material The material to test
112
- * @returns true if the material is of the same type, false otherwise
112
+ * @returns true if the material matches one of the loaded PBR implementations
113
113
  */
114
114
  isMatchingMaterialType(material) {
115
- if (material && this._pbrMaterialImpl) {
116
- return material instanceof this._pbrMaterialImpl.materialClass;
115
+ if (!material) {
116
+ return false;
117
+ }
118
+ const materialImpls = Array.from(this._pbrMaterialImpls.values());
119
+ for (const impl of materialImpls) {
120
+ if (material instanceof impl.materialClass) {
121
+ return true;
122
+ }
117
123
  }
118
124
  return false;
119
125
  }
@@ -205,8 +211,13 @@ export class GLTFLoader {
205
211
  this._postSceneLoadActions = new Array();
206
212
  this._materialAdapterCache = new WeakMap();
207
213
  this._materialAdapters = new Set();
208
- /** @internal */
209
- this._pbrMaterialImpl = null;
214
+ /**
215
+ * Loaded PBR material implementations, keyed by their identifier (e.g. "pbr", "openpbr").
216
+ * Only populated after the load has started and only for the types actually needed by the asset.
217
+ * Empty when PBR materials are disabled (skipMaterials).
218
+ * @internal
219
+ */
220
+ this._pbrMaterialImpls = new Map();
210
221
  this._parent = parent;
211
222
  }
212
223
  /**
@@ -218,10 +229,14 @@ export class GLTFLoader {
218
229
  _getOrCreateMaterialAdapter(material) {
219
230
  let adapter = this._materialAdapterCache.get(material);
220
231
  if (!adapter) {
221
- if (this._pbrMaterialImpl) {
222
- adapter = new this._pbrMaterialImpl.adapterClass(material);
232
+ const materialImpls = Array.from(this._pbrMaterialImpls.values());
233
+ for (const impl of materialImpls) {
234
+ if (material instanceof impl.materialClass) {
235
+ adapter = new impl.adapterClass(material);
236
+ break;
237
+ }
223
238
  }
224
- else {
239
+ if (!adapter) {
225
240
  throw new Error(`Appropriate material adapter class not found`);
226
241
  }
227
242
  const createdAdapter = adapter;
@@ -305,20 +320,35 @@ export class GLTFLoader {
305
320
  this._fileName = fileName;
306
321
  this._allMaterialsDirtyRequired = false;
307
322
  await this._loadExtensionsAsync();
308
- // NOTE: Explicitly check _pbrMaterialImpl for null as a value of false means don't use PBR materials at all.
309
- if (!this.parent.skipMaterials && this._pbrMaterialImpl == null) {
310
- if (this.parent.useOpenPBR || this.isExtensionUsed("KHR_materials_openpbr")) {
311
- this._pbrMaterialImpl = {
312
- materialClass: (await import("@onerjs/core/Materials/PBR/openpbrMaterial.js")).OpenPBRMaterial,
313
- adapterClass: (await import("./openpbrMaterialLoadingAdapter.js")).OpenPBRMaterialLoadingAdapter,
314
- };
323
+ if (!this.parent.skipMaterials) {
324
+ const needsOpenPBR = this.parent.useOpenPBR || this.isExtensionUsed("KHR_materials_openpbr");
325
+ let needsPBR = false;
326
+ if (!this.parent.useOpenPBR) {
327
+ // PBR is needed when useOpenPBR is turned off.
328
+ needsPBR = true;
315
329
  }
316
- else {
317
- this._pbrMaterialImpl = {
318
- materialClass: (await import("@onerjs/core/Materials/PBR/pbrMaterial.js")).PBRMaterial,
319
- adapterClass: (await import("./pbrMaterialLoadingAdapter.js")).PBRMaterialLoadingAdapter,
320
- };
330
+ else if (this._gltf.materials?.length && this._gltf.materials.some((m) => !m.extensions?.["KHR_materials_openpbr"])) {
331
+ // PBR is needed if there is at least one material that does not use the KHR_materials_openpbr extension (i.e. relies on the default PBR implementation).
332
+ needsPBR = true;
321
333
  }
334
+ const implPromises = [];
335
+ if (needsOpenPBR && !this._pbrMaterialImpls.has("openpbr")) {
336
+ implPromises.push(Promise.all([import("@onerjs/core/Materials/PBR/openpbrMaterial.js"), import("./openpbrMaterialLoadingAdapter.js")]).then(([{ OpenPBRMaterial: openPBRMaterialClass }, { OpenPBRMaterialLoadingAdapter: openPBRAdapterClass }]) => {
337
+ this._pbrMaterialImpls.set("openpbr", {
338
+ materialClass: openPBRMaterialClass,
339
+ adapterClass: openPBRAdapterClass,
340
+ });
341
+ }));
342
+ }
343
+ if (needsPBR && !this._pbrMaterialImpls.has("pbr")) {
344
+ implPromises.push(Promise.all([import("@onerjs/core/Materials/PBR/pbrMaterial.js"), import("./pbrMaterialLoadingAdapter.js")]).then(([{ PBRMaterial: pbrMaterialClass }, { PBRMaterialLoadingAdapter: pbrAdapterClass }]) => {
345
+ this._pbrMaterialImpls.set("pbr", {
346
+ materialClass: pbrMaterialClass,
347
+ adapterClass: pbrAdapterClass,
348
+ });
349
+ }));
350
+ }
351
+ await Promise.all(implPromises);
322
352
  }
323
353
  const loadingToReadyCounterName = `${GLTFLoaderState[GLTFLoaderState.LOADING]} => ${GLTFLoaderState[GLTFLoaderState.READY]}`;
324
354
  const loadingToCompleteCounterName = `${GLTFLoaderState[GLTFLoaderState.LOADING]} => ${GLTFLoaderState[GLTFLoaderState.COMPLETE]}`;
@@ -890,7 +920,7 @@ export class GLTFLoader {
890
920
  if (primitive.material == undefined) {
891
921
  let babylonMaterial = this._defaultBabylonMaterialData[babylonDrawMode];
892
922
  if (!babylonMaterial) {
893
- babylonMaterial = this._createDefaultMaterial("__GLTFLoader._default", babylonDrawMode);
923
+ babylonMaterial = this._createDefaultMaterial("__GLTFLoader._default", babylonDrawMode, this._getDefaultImpl());
894
924
  this._parent.onMaterialLoadedObservable.notifyObservers(babylonMaterial);
895
925
  this._defaultBabylonMaterialData[babylonDrawMode] = babylonMaterial;
896
926
  }
@@ -1833,16 +1863,52 @@ export class GLTFLoader {
1833
1863
  await babylonData.promise;
1834
1864
  return babylonData.babylonMaterial;
1835
1865
  }
1836
- _createDefaultMaterial(name, babylonDrawMode) {
1837
- if (!this._pbrMaterialImpl) {
1838
- throw new Error("PBR Material class not loaded");
1866
+ /**
1867
+ * Selects the appropriate PBR material implementation for a given glTF material.
1868
+ * Uses OpenPBR when the material carries a "KHR_materials_openpbr" extension or when
1869
+ * the loader-level `useOpenPBR` flag is set; falls back to standard PBR otherwise.
1870
+ * @param material The glTF material
1871
+ * @returns The matching loaded implementation
1872
+ */
1873
+ _selectImplForGltfMaterial(material) {
1874
+ if (this.parent.useOpenPBR || material.extensions?.["KHR_materials_openpbr"]) {
1875
+ const impl = this._pbrMaterialImpls.get("openpbr");
1876
+ if (impl) {
1877
+ return impl;
1878
+ }
1879
+ }
1880
+ const impl = this._pbrMaterialImpls.get("pbr");
1881
+ if (impl) {
1882
+ return impl;
1839
1883
  }
1884
+ throw new Error("No PBR material implementation loaded");
1885
+ }
1886
+ /**
1887
+ * Returns the default PBR material implementation used when there is no per-material
1888
+ * selection context (e.g. when creating the built-in default material for primitives
1889
+ * that have no glTF material assigned). Prefers OpenPBR when `useOpenPBR` is set.
1890
+ * @returns The default loaded implementation
1891
+ */
1892
+ _getDefaultImpl() {
1893
+ if (this.parent.useOpenPBR) {
1894
+ const impl = this._pbrMaterialImpls.get("openpbr");
1895
+ if (impl) {
1896
+ return impl;
1897
+ }
1898
+ }
1899
+ const impl = this._pbrMaterialImpls.get("pbr") ?? this._pbrMaterialImpls.values().next().value;
1900
+ if (impl) {
1901
+ return impl;
1902
+ }
1903
+ throw new Error("No PBR material implementation loaded");
1904
+ }
1905
+ _createDefaultMaterial(name, babylonDrawMode, impl) {
1840
1906
  this._babylonScene._blockEntityCollection = !!this._assetContainer;
1841
- const babylonMaterial = new this._pbrMaterialImpl.materialClass(name, this._babylonScene);
1907
+ const babylonMaterial = new impl.materialClass(name, this._babylonScene);
1842
1908
  babylonMaterial._parentContainer = this._assetContainer;
1843
1909
  this._babylonScene._blockEntityCollection = false;
1844
1910
  babylonMaterial.fillMode = babylonDrawMode;
1845
- babylonMaterial.transparencyMode = this._pbrMaterialImpl.materialClass.MATERIAL_OPAQUE;
1911
+ babylonMaterial.transparencyMode = impl.materialClass.MATERIAL_OPAQUE;
1846
1912
  // Create the material adapter and set some default properties.
1847
1913
  // We don't need to wait for the promise to resolve here.
1848
1914
  const adapter = this._getOrCreateMaterialAdapter(babylonMaterial);
@@ -1865,7 +1931,7 @@ export class GLTFLoader {
1865
1931
  return extensionMaterial;
1866
1932
  }
1867
1933
  const name = material.name || `material${material.index}`;
1868
- const babylonMaterial = this._createDefaultMaterial(name, babylonDrawMode);
1934
+ const babylonMaterial = this._createDefaultMaterial(name, babylonDrawMode, this._selectImplForGltfMaterial(material));
1869
1935
  return babylonMaterial;
1870
1936
  }
1871
1937
  /**
@@ -1955,7 +2021,7 @@ export class GLTFLoader {
1955
2021
  * @param babylonMaterial The Babylon material
1956
2022
  */
1957
2023
  loadMaterialAlphaProperties(context, material, babylonMaterial) {
1958
- if (!this._pbrMaterialImpl) {
2024
+ if (this._pbrMaterialImpls.size === 0) {
1959
2025
  throw new Error(`${context}: Material type not supported`);
1960
2026
  }
1961
2027
  const adapter = this._getOrCreateMaterialAdapter(babylonMaterial);
@@ -1963,12 +2029,12 @@ export class GLTFLoader {
1963
2029
  const alphaMode = material.alphaMode || "OPAQUE" /* MaterialAlphaMode.OPAQUE */;
1964
2030
  switch (alphaMode) {
1965
2031
  case "OPAQUE" /* MaterialAlphaMode.OPAQUE */: {
1966
- babylonMaterial.transparencyMode = this._pbrMaterialImpl.materialClass.MATERIAL_OPAQUE;
2032
+ babylonMaterial.transparencyMode = Material.MATERIAL_OPAQUE;
1967
2033
  babylonMaterial.alpha = 1.0; // Force alpha to 1.0 for opaque mode.
1968
2034
  break;
1969
2035
  }
1970
2036
  case "MASK" /* MaterialAlphaMode.MASK */: {
1971
- babylonMaterial.transparencyMode = this._pbrMaterialImpl.materialClass.MATERIAL_ALPHATEST;
2037
+ babylonMaterial.transparencyMode = Material.MATERIAL_ALPHATEST;
1972
2038
  adapter.alphaCutOff = material.alphaCutoff == undefined ? 0.5 : material.alphaCutoff;
1973
2039
  if (baseColorTexture) {
1974
2040
  baseColorTexture.hasAlpha = true;
@@ -1976,7 +2042,7 @@ export class GLTFLoader {
1976
2042
  break;
1977
2043
  }
1978
2044
  case "BLEND" /* MaterialAlphaMode.BLEND */: {
1979
- babylonMaterial.transparencyMode = this._pbrMaterialImpl.materialClass.MATERIAL_ALPHABLEND;
2045
+ babylonMaterial.transparencyMode = Material.MATERIAL_ALPHABLEND;
1980
2046
  if (baseColorTexture) {
1981
2047
  baseColorTexture.hasAlpha = true;
1982
2048
  adapter.useAlphaFromBaseColorTexture = true;