@luma.gl/gltf 9.1.9 → 9.2.0-alpha.2

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 (93) hide show
  1. package/dist/dist.dev.js +659 -585
  2. package/dist/dist.min.js +4 -4
  3. package/dist/gltf/animations/animations.d.ts +16 -0
  4. package/dist/gltf/animations/animations.d.ts.map +1 -0
  5. package/dist/gltf/animations/animations.js +5 -0
  6. package/dist/gltf/animations/animations.js.map +1 -0
  7. package/dist/gltf/animations/interpolate.d.ts +4 -0
  8. package/dist/gltf/animations/interpolate.d.ts.map +1 -0
  9. package/dist/gltf/animations/interpolate.js +94 -0
  10. package/dist/gltf/animations/interpolate.js.map +1 -0
  11. package/dist/gltf/create-gltf-model.d.ts +4 -4
  12. package/dist/gltf/create-gltf-model.d.ts.map +1 -1
  13. package/dist/gltf/create-gltf-model.js +7 -8
  14. package/dist/gltf/create-gltf-model.js.map +1 -1
  15. package/dist/gltf/{create-gltf-objects.d.ts → create-scenegraph-from-gltf.d.ts} +4 -3
  16. package/dist/gltf/create-scenegraph-from-gltf.d.ts.map +1 -0
  17. package/dist/gltf/create-scenegraph-from-gltf.js +16 -0
  18. package/dist/gltf/create-scenegraph-from-gltf.js.map +1 -0
  19. package/dist/gltf/gltf-animator.d.ts +13 -28
  20. package/dist/gltf/gltf-animator.d.ts.map +1 -1
  21. package/dist/gltf/gltf-animator.js +17 -144
  22. package/dist/gltf/gltf-animator.js.map +1 -1
  23. package/dist/index.cjs +483 -447
  24. package/dist/index.cjs.map +4 -4
  25. package/dist/index.d.ts +5 -5
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +2 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/parsers/parse-gltf-animations.d.ts +4 -0
  30. package/dist/parsers/parse-gltf-animations.d.ts.map +1 -0
  31. package/dist/parsers/parse-gltf-animations.js +40 -0
  32. package/dist/parsers/parse-gltf-animations.js.map +1 -0
  33. package/dist/parsers/parse-gltf.d.ts +17 -0
  34. package/dist/parsers/parse-gltf.d.ts.map +1 -0
  35. package/dist/parsers/parse-gltf.js +118 -0
  36. package/dist/parsers/parse-gltf.js.map +1 -0
  37. package/dist/parsers/parse-pbr-material.d.ts +50 -0
  38. package/dist/parsers/parse-pbr-material.d.ts.map +1 -0
  39. package/dist/{pbr → parsers}/parse-pbr-material.js +42 -56
  40. package/dist/parsers/parse-pbr-material.js.map +1 -0
  41. package/dist/pbr/pbr-environment.d.ts.map +1 -1
  42. package/dist/pbr/pbr-environment.js +14 -10
  43. package/dist/pbr/pbr-environment.js.map +1 -1
  44. package/dist/pbr/pbr-material.d.ts +13 -0
  45. package/dist/pbr/pbr-material.d.ts.map +1 -0
  46. package/dist/pbr/pbr-material.js +2 -0
  47. package/dist/pbr/pbr-material.js.map +1 -0
  48. package/dist/utils/deep-copy.d.ts +3 -0
  49. package/dist/utils/deep-copy.d.ts.map +1 -0
  50. package/dist/utils/deep-copy.js +21 -0
  51. package/dist/utils/deep-copy.js.map +1 -0
  52. package/dist/webgl-to-webgpu/convert-webgl-attribute.d.ts +21 -0
  53. package/dist/webgl-to-webgpu/convert-webgl-attribute.d.ts.map +1 -0
  54. package/dist/webgl-to-webgpu/convert-webgl-attribute.js +29 -0
  55. package/dist/webgl-to-webgpu/convert-webgl-attribute.js.map +1 -0
  56. package/dist/webgl-to-webgpu/convert-webgl-sampler.d.ts +11 -0
  57. package/dist/webgl-to-webgpu/convert-webgl-sampler.d.ts.map +1 -0
  58. package/dist/webgl-to-webgpu/convert-webgl-sampler.js +53 -0
  59. package/dist/webgl-to-webgpu/convert-webgl-sampler.js.map +1 -0
  60. package/dist/{gltf/gl-utils.d.ts → webgl-to-webgpu/convert-webgl-topology.d.ts} +1 -1
  61. package/dist/webgl-to-webgpu/convert-webgl-topology.d.ts.map +1 -0
  62. package/dist/{gltf/gl-utils.js → webgl-to-webgpu/convert-webgl-topology.js} +1 -1
  63. package/dist/webgl-to-webgpu/convert-webgl-topology.js.map +1 -0
  64. package/package.json +7 -5
  65. package/src/gltf/animations/animations.ts +22 -0
  66. package/src/gltf/animations/interpolate.ts +153 -0
  67. package/src/gltf/create-gltf-model.ts +12 -13
  68. package/src/gltf/create-scenegraph-from-gltf.ts +27 -0
  69. package/src/gltf/gltf-animator.ts +31 -172
  70. package/src/index.ts +5 -5
  71. package/src/parsers/parse-gltf-animations.ts +55 -0
  72. package/src/parsers/parse-gltf.ts +192 -0
  73. package/src/{pbr → parsers}/parse-pbr-material.ts +90 -73
  74. package/src/pbr/pbr-environment.ts +18 -14
  75. package/src/pbr/pbr-material.ts +13 -0
  76. package/src/utils/deep-copy.ts +22 -0
  77. package/src/webgl-to-webgpu/convert-webgl-attribute.ts +47 -0
  78. package/src/webgl-to-webgpu/convert-webgl-sampler.ts +86 -0
  79. package/dist/gltf/create-gltf-objects.d.ts.map +0 -1
  80. package/dist/gltf/create-gltf-objects.js +0 -11
  81. package/dist/gltf/create-gltf-objects.js.map +0 -1
  82. package/dist/gltf/gl-utils.d.ts.map +0 -1
  83. package/dist/gltf/gl-utils.js.map +0 -1
  84. package/dist/gltf/gltf-instantiator.d.ts +0 -33
  85. package/dist/gltf/gltf-instantiator.d.ts.map +0 -1
  86. package/dist/gltf/gltf-instantiator.js +0 -185
  87. package/dist/gltf/gltf-instantiator.js.map +0 -1
  88. package/dist/pbr/parse-pbr-material.d.ts +0 -27
  89. package/dist/pbr/parse-pbr-material.d.ts.map +0 -1
  90. package/dist/pbr/parse-pbr-material.js.map +0 -1
  91. package/src/gltf/create-gltf-objects.ts +0 -22
  92. package/src/gltf/gltf-instantiator.ts +0 -233
  93. /package/src/{gltf/gl-utils.ts → webgl-to-webgpu/convert-webgl-topology.ts} +0 -0
package/dist/dist.dev.js CHANGED
@@ -4,6 +4,7 @@
4
4
  else if (typeof define === 'function' && define.amd) define([], factory);
5
5
  else if (typeof exports === 'object') exports['luma'] = factory();
6
6
  else root['luma'] = factory();})(globalThis, function () {
7
+ "use strict";
7
8
  var __exports__ = (() => {
8
9
  var __create = Object.create;
9
10
  var __defProp = Object.defineProperty;
@@ -51,6 +52,13 @@ var __exports__ = (() => {
51
52
  }
52
53
  });
53
54
 
55
+ // external-global-plugin:@luma.gl/constants
56
+ var require_constants = __commonJS({
57
+ "external-global-plugin:@luma.gl/constants"(exports, module) {
58
+ module.exports = globalThis.luma;
59
+ }
60
+ });
61
+
54
62
  // external-global-plugin:@luma.gl/shadertools
55
63
  var require_shadertools = __commonJS({
56
64
  "external-global-plugin:@luma.gl/shadertools"(exports, module) {
@@ -68,170 +76,6 @@ var __exports__ = (() => {
68
76
  });
69
77
  __reExport(bundle_exports, __toESM(require_core(), 1));
70
78
 
71
- // src/pbr/parse-pbr-material.ts
72
- var import_core = __toESM(require_core(), 1);
73
- function parsePBRMaterial(device, material, attributes, options) {
74
- const parsedMaterial = {
75
- defines: {
76
- // TODO: Use EXT_sRGB if available (Standard in WebGL 2.0)
77
- MANUAL_SRGB: 1,
78
- SRGB_FAST_APPROXIMATION: 1
79
- },
80
- bindings: {},
81
- uniforms: {
82
- // TODO: find better values?
83
- camera: [0, 0, 0],
84
- // Model should override
85
- metallicRoughnessValues: [1, 1]
86
- // Default is 1 and 1
87
- },
88
- parameters: {},
89
- glParameters: {},
90
- generatedTextures: []
91
- };
92
- parsedMaterial.defines.USE_TEX_LOD = 1;
93
- const { imageBasedLightingEnvironment } = options;
94
- if (imageBasedLightingEnvironment) {
95
- parsedMaterial.bindings.pbr_diffuseEnvSampler = imageBasedLightingEnvironment.diffuseEnvSampler.texture;
96
- parsedMaterial.bindings.pbr_specularEnvSampler = imageBasedLightingEnvironment.specularEnvSampler.texture;
97
- parsedMaterial.bindings.pbr_BrdfLUT = imageBasedLightingEnvironment.brdfLutTexture.texture;
98
- parsedMaterial.uniforms.scaleIBLAmbient = [1, 1];
99
- }
100
- if (options?.pbrDebug) {
101
- parsedMaterial.defines.PBR_DEBUG = 1;
102
- parsedMaterial.uniforms.scaleDiffBaseMR = [0, 0, 0, 0];
103
- parsedMaterial.uniforms.scaleFGDSpec = [0, 0, 0, 0];
104
- }
105
- if (attributes.NORMAL)
106
- parsedMaterial.defines.HAS_NORMALS = 1;
107
- if (attributes.TANGENT && options?.useTangents)
108
- parsedMaterial.defines.HAS_TANGENTS = 1;
109
- if (attributes.TEXCOORD_0)
110
- parsedMaterial.defines.HAS_UV = 1;
111
- if (options?.imageBasedLightingEnvironment)
112
- parsedMaterial.defines.USE_IBL = 1;
113
- if (options?.lights)
114
- parsedMaterial.defines.USE_LIGHTS = 1;
115
- if (material) {
116
- parseMaterial(device, material, parsedMaterial);
117
- }
118
- return parsedMaterial;
119
- }
120
- function parseMaterial(device, material, parsedMaterial) {
121
- parsedMaterial.uniforms.unlit = Boolean(material.unlit);
122
- if (material.pbrMetallicRoughness) {
123
- parsePbrMetallicRoughness(device, material.pbrMetallicRoughness, parsedMaterial);
124
- }
125
- if (material.normalTexture) {
126
- addTexture(
127
- device,
128
- material.normalTexture,
129
- "pbr_normalSampler",
130
- "HAS_NORMALMAP",
131
- parsedMaterial
132
- );
133
- const { scale: scale4 = 1 } = material.normalTexture;
134
- parsedMaterial.uniforms.normalScale = scale4;
135
- }
136
- if (material.occlusionTexture) {
137
- addTexture(
138
- device,
139
- material.occlusionTexture,
140
- "pbr_occlusionSampler",
141
- "HAS_OCCLUSIONMAP",
142
- parsedMaterial
143
- );
144
- const { strength = 1 } = material.occlusionTexture;
145
- parsedMaterial.uniforms.occlusionStrength = strength;
146
- }
147
- if (material.emissiveTexture) {
148
- addTexture(
149
- device,
150
- material.emissiveTexture,
151
- "pbr_emissiveSampler",
152
- "HAS_EMISSIVEMAP",
153
- parsedMaterial
154
- );
155
- parsedMaterial.uniforms.emissiveFactor = material.emissiveFactor || [0, 0, 0];
156
- }
157
- switch (material.alphaMode) {
158
- case "MASK":
159
- const { alphaCutoff = 0.5 } = material;
160
- parsedMaterial.defines.ALPHA_CUTOFF = 1;
161
- parsedMaterial.uniforms.alphaCutoff = alphaCutoff;
162
- break;
163
- case "BLEND":
164
- import_core.log.warn("glTF BLEND alphaMode might not work well because it requires mesh sorting")();
165
- parsedMaterial.parameters.blendColorOperation = "add";
166
- parsedMaterial.parameters.blendColorSrcFactor = "src-alpha";
167
- parsedMaterial.parameters.blendColorDstFactor = "one-minus-src-alpha";
168
- parsedMaterial.parameters.blendAlphaOperation = "add";
169
- parsedMaterial.parameters.blendAlphaSrcFactor = "one";
170
- parsedMaterial.parameters.blendAlphaDstFactor = "one-minus-src-alpha";
171
- parsedMaterial.glParameters.blend = true;
172
- parsedMaterial.glParameters.blendEquation = 32774 /* FUNC_ADD */;
173
- parsedMaterial.glParameters.blendFunc = [
174
- 770 /* SRC_ALPHA */,
175
- 771 /* ONE_MINUS_SRC_ALPHA */,
176
- 1 /* ONE */,
177
- 771 /* ONE_MINUS_SRC_ALPHA */
178
- ];
179
- break;
180
- }
181
- }
182
- function parsePbrMetallicRoughness(device, pbrMetallicRoughness, parsedMaterial) {
183
- if (pbrMetallicRoughness.baseColorTexture) {
184
- addTexture(
185
- device,
186
- pbrMetallicRoughness.baseColorTexture,
187
- "pbr_baseColorSampler",
188
- "HAS_BASECOLORMAP",
189
- parsedMaterial
190
- );
191
- }
192
- parsedMaterial.uniforms.baseColorFactor = pbrMetallicRoughness.baseColorFactor || [1, 1, 1, 1];
193
- if (pbrMetallicRoughness.metallicRoughnessTexture) {
194
- addTexture(
195
- device,
196
- pbrMetallicRoughness.metallicRoughnessTexture,
197
- "pbr_metallicRoughnessSampler",
198
- "HAS_METALROUGHNESSMAP",
199
- parsedMaterial
200
- );
201
- }
202
- const { metallicFactor = 1, roughnessFactor = 1 } = pbrMetallicRoughness;
203
- parsedMaterial.uniforms.metallicRoughnessValues = [metallicFactor, roughnessFactor];
204
- }
205
- function addTexture(device, gltfTexture, uniformName, define = null, parsedMaterial) {
206
- const parameters = gltfTexture?.texture?.sampler?.parameters || {};
207
- const image = gltfTexture.texture.source.image;
208
- let textureOptions;
209
- let specialTextureParameters = {};
210
- if (image.compressed) {
211
- textureOptions = image;
212
- specialTextureParameters = {
213
- [10241 /* TEXTURE_MIN_FILTER */]: image.data.length > 1 ? 9985 /* LINEAR_MIPMAP_NEAREST */ : 9729 /* LINEAR */
214
- };
215
- } else {
216
- textureOptions = { data: image };
217
- }
218
- const texture = device.createTexture({
219
- id: gltfTexture.uniformName || gltfTexture.id,
220
- parameters: {
221
- ...parameters,
222
- ...specialTextureParameters
223
- },
224
- pixelStore: {
225
- [37440 /* UNPACK_FLIP_Y_WEBGL */]: false
226
- },
227
- ...textureOptions
228
- });
229
- parsedMaterial.bindings[uniformName] = texture;
230
- if (define)
231
- parsedMaterial.defines[define] = 1;
232
- parsedMaterial.generatedTextures.push(texture);
233
- }
234
-
235
79
  // src/pbr/pbr-environment.ts
236
80
  var import_engine = __toESM(require_engine(), 1);
237
81
 
@@ -277,7 +121,7 @@ var __exports__ = (() => {
277
121
  }
278
122
 
279
123
  // ../../node_modules/@loaders.gl/images/dist/lib/utils/version.js
280
- var VERSION = true ? "4.2.1" : "latest";
124
+ var VERSION = true ? "4.3.2" : "latest";
281
125
 
282
126
  // ../../node_modules/@loaders.gl/images/dist/lib/category-api/image-type.js
283
127
  var parseImageNode = globalThis.loaders?.parseImageNode;
@@ -774,10 +618,10 @@ var __exports__ = (() => {
774
618
  const brdfLutTexture = new import_engine.AsyncTexture(device, {
775
619
  id: "brdfLUT",
776
620
  sampler: {
777
- wrapS: "clamp-to-edge",
778
- wrapT: "clamp-to-edge",
621
+ addressModeU: "clamp-to-edge",
622
+ addressModeV: "clamp-to-edge",
779
623
  minFilter: "linear",
780
- maxFilter: "linear"
624
+ magFilter: "linear"
781
625
  },
782
626
  // Texture accepts a promise that returns an image as data (Async Textures)
783
627
  data: loadImageTexture(props.brdfLutUrl)
@@ -786,10 +630,10 @@ var __exports__ = (() => {
786
630
  id: "DiffuseEnvSampler",
787
631
  getTextureForFace: (dir) => loadImageTexture(props.getTexUrl("diffuse", dir, 0)),
788
632
  sampler: {
789
- wrapS: "clamp-to-edge",
790
- wrapT: "clamp-to-edge",
633
+ addressModeU: "clamp-to-edge",
634
+ addressModeV: "clamp-to-edge",
791
635
  minFilter: "linear",
792
- maxFilter: "linear"
636
+ magFilter: "linear"
793
637
  }
794
638
  });
795
639
  const specularEnvSampler = makeCube(device, {
@@ -802,11 +646,11 @@ var __exports__ = (() => {
802
646
  return imageArray;
803
647
  },
804
648
  sampler: {
805
- wrapS: "clamp-to-edge",
806
- wrapT: "clamp-to-edge",
649
+ addressModeU: "clamp-to-edge",
650
+ addressModeV: "clamp-to-edge",
807
651
  minFilter: "linear",
808
652
  // [GL.TEXTURE_MIN_FILTER]: GL.LINEAR_MIPMAP_LINEAR,
809
- maxFilter: "linear"
653
+ magFilter: "linear"
810
654
  }
811
655
  });
812
656
  return {
@@ -835,96 +679,311 @@ var __exports__ = (() => {
835
679
  });
836
680
  }
837
681
 
838
- // src/gltf/gltf-instantiator.ts
839
- var import_engine3 = __toESM(require_engine(), 1);
682
+ // src/parsers/parse-pbr-material.ts
683
+ var import_constants2 = __toESM(require_constants(), 1);
684
+ var import_core = __toESM(require_core(), 1);
840
685
 
841
- // ../../node_modules/@math.gl/core/dist/lib/common.js
842
- var RADIANS_TO_DEGREES = 1 / Math.PI * 180;
843
- var DEGREES_TO_RADIANS = 1 / 180 * Math.PI;
844
- var DEFAULT_CONFIG = {
845
- EPSILON: 1e-12,
846
- debug: false,
847
- precision: 4,
848
- printTypes: false,
849
- printDegrees: false,
850
- printRowMajor: true,
851
- _cartographicRadians: false
852
- };
853
- globalThis.mathgl = globalThis.mathgl || { config: { ...DEFAULT_CONFIG } };
854
- var config = globalThis.mathgl.config;
855
- function formatValue(value, { precision = config.precision } = {}) {
856
- value = round(value);
857
- return `${parseFloat(value.toPrecision(precision))}`;
858
- }
859
- function isArray(value) {
860
- return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
686
+ // src/webgl-to-webgpu/convert-webgl-sampler.ts
687
+ var import_constants = __toESM(require_constants(), 1);
688
+ function convertSampler(gltfSampler) {
689
+ return {
690
+ addressModeU: convertSamplerWrapMode(gltfSampler.wrapS),
691
+ addressModeV: convertSamplerWrapMode(gltfSampler.wrapT),
692
+ magFilter: convertSamplerMagFilter(gltfSampler.magFilter),
693
+ ...convertSamplerMinFilter(gltfSampler.minFilter)
694
+ };
861
695
  }
862
- function equals(a, b, epsilon) {
863
- const oldEpsilon = config.EPSILON;
864
- if (epsilon) {
865
- config.EPSILON = epsilon;
866
- }
867
- try {
868
- if (a === b) {
869
- return true;
870
- }
871
- if (isArray(a) && isArray(b)) {
872
- if (a.length !== b.length) {
873
- return false;
874
- }
875
- for (let i = 0; i < a.length; ++i) {
876
- if (!equals(a[i], b[i])) {
877
- return false;
878
- }
879
- }
880
- return true;
881
- }
882
- if (a && a.equals) {
883
- return a.equals(b);
884
- }
885
- if (b && b.equals) {
886
- return b.equals(a);
887
- }
888
- if (typeof a === "number" && typeof b === "number") {
889
- return Math.abs(a - b) <= config.EPSILON * Math.max(1, Math.abs(a), Math.abs(b));
890
- }
891
- return false;
892
- } finally {
893
- config.EPSILON = oldEpsilon;
696
+ function convertSamplerWrapMode(mode) {
697
+ switch (mode) {
698
+ case import_constants.GL.CLAMP_TO_EDGE:
699
+ return "clamp-to-edge";
700
+ case import_constants.GL.REPEAT:
701
+ return "repeat";
702
+ case import_constants.GL.MIRRORED_REPEAT:
703
+ return "mirror-repeat";
704
+ default:
705
+ return void 0;
894
706
  }
895
707
  }
896
- function round(value) {
897
- return Math.round(value / config.EPSILON) * config.EPSILON;
708
+ function convertSamplerMagFilter(mode) {
709
+ switch (mode) {
710
+ case import_constants.GL.NEAREST:
711
+ return "nearest";
712
+ case import_constants.GL.LINEAR:
713
+ return "linear";
714
+ default:
715
+ return void 0;
716
+ }
717
+ }
718
+ function convertSamplerMinFilter(mode) {
719
+ switch (mode) {
720
+ case import_constants.GL.NEAREST:
721
+ return { minFilter: "nearest" };
722
+ case import_constants.GL.LINEAR:
723
+ return { minFilter: "linear" };
724
+ case import_constants.GL.NEAREST_MIPMAP_NEAREST:
725
+ return { minFilter: "nearest", mipmapFilter: "nearest" };
726
+ case import_constants.GL.LINEAR_MIPMAP_NEAREST:
727
+ return { minFilter: "linear", mipmapFilter: "nearest" };
728
+ case import_constants.GL.NEAREST_MIPMAP_LINEAR:
729
+ return { minFilter: "nearest", mipmapFilter: "linear" };
730
+ case import_constants.GL.LINEAR_MIPMAP_LINEAR:
731
+ return { minFilter: "linear", mipmapFilter: "linear" };
732
+ default:
733
+ return {};
734
+ }
898
735
  }
899
736
 
900
- // ../../node_modules/@math.gl/core/dist/classes/base/math-array.js
901
- var MathArray = class extends Array {
902
- // Common methods
903
- /**
904
- * Clone the current object
905
- * @returns a new copy of this object
906
- */
907
- clone() {
908
- return new this.constructor().copy(this);
737
+ // src/parsers/parse-pbr-material.ts
738
+ function parsePBRMaterial(device, material, attributes, options) {
739
+ const parsedMaterial = {
740
+ defines: {
741
+ // TODO: Use EXT_sRGB if available (Standard in WebGL 2.0)
742
+ MANUAL_SRGB: true,
743
+ SRGB_FAST_APPROXIMATION: true
744
+ },
745
+ bindings: {},
746
+ uniforms: {
747
+ // TODO: find better values?
748
+ camera: [0, 0, 0],
749
+ // Model should override
750
+ metallicRoughnessValues: [1, 1]
751
+ // Default is 1 and 1
752
+ },
753
+ parameters: {},
754
+ glParameters: {},
755
+ generatedTextures: []
756
+ };
757
+ parsedMaterial.defines["USE_TEX_LOD"] = true;
758
+ const { imageBasedLightingEnvironment } = options;
759
+ if (imageBasedLightingEnvironment) {
760
+ parsedMaterial.bindings.pbr_diffuseEnvSampler = imageBasedLightingEnvironment.diffuseEnvSampler.texture;
761
+ parsedMaterial.bindings.pbr_specularEnvSampler = imageBasedLightingEnvironment.specularEnvSampler.texture;
762
+ parsedMaterial.bindings.pbr_BrdfLUT = imageBasedLightingEnvironment.brdfLutTexture.texture;
763
+ parsedMaterial.uniforms.scaleIBLAmbient = [1, 1];
909
764
  }
910
- fromArray(array, offset = 0) {
911
- for (let i = 0; i < this.ELEMENTS; ++i) {
912
- this[i] = array[i + offset];
913
- }
914
- return this.check();
765
+ if (options?.pbrDebug) {
766
+ parsedMaterial.defines["PBR_DEBUG"] = true;
767
+ parsedMaterial.uniforms.scaleDiffBaseMR = [0, 0, 0, 0];
768
+ parsedMaterial.uniforms.scaleFGDSpec = [0, 0, 0, 0];
915
769
  }
916
- toArray(targetArray = [], offset = 0) {
917
- for (let i = 0; i < this.ELEMENTS; ++i) {
918
- targetArray[offset + i] = this[i];
919
- }
920
- return targetArray;
770
+ if (attributes["NORMAL"])
771
+ parsedMaterial.defines["HAS_NORMALS"] = true;
772
+ if (attributes["TANGENT"] && options?.useTangents)
773
+ parsedMaterial.defines["HAS_TANGENTS"] = true;
774
+ if (attributes["TEXCOORD_0"])
775
+ parsedMaterial.defines["HAS_UV"] = true;
776
+ if (options?.imageBasedLightingEnvironment)
777
+ parsedMaterial.defines["USE_IBL"] = true;
778
+ if (options?.lights)
779
+ parsedMaterial.defines["USE_LIGHTS"] = true;
780
+ if (material) {
781
+ parseMaterial(device, material, parsedMaterial);
921
782
  }
922
- toObject(targetObject) {
923
- return targetObject;
783
+ return parsedMaterial;
784
+ }
785
+ function parseMaterial(device, material, parsedMaterial) {
786
+ parsedMaterial.uniforms.unlit = Boolean(material.unlit);
787
+ if (material.pbrMetallicRoughness) {
788
+ parsePbrMetallicRoughness(device, material.pbrMetallicRoughness, parsedMaterial);
924
789
  }
925
- from(arrayOrObject) {
926
- return Array.isArray(arrayOrObject) ? this.copy(arrayOrObject) : (
927
- // @ts-ignore
790
+ if (material.normalTexture) {
791
+ addTexture(
792
+ device,
793
+ material.normalTexture,
794
+ "pbr_normalSampler",
795
+ "HAS_NORMALMAP",
796
+ parsedMaterial
797
+ );
798
+ const { scale: scale4 = 1 } = material.normalTexture;
799
+ parsedMaterial.uniforms.normalScale = scale4;
800
+ }
801
+ if (material.occlusionTexture) {
802
+ addTexture(
803
+ device,
804
+ material.occlusionTexture,
805
+ "pbr_occlusionSampler",
806
+ "HAS_OCCLUSIONMAP",
807
+ parsedMaterial
808
+ );
809
+ const { strength = 1 } = material.occlusionTexture;
810
+ parsedMaterial.uniforms.occlusionStrength = strength;
811
+ }
812
+ if (material.emissiveTexture) {
813
+ addTexture(
814
+ device,
815
+ material.emissiveTexture,
816
+ "pbr_emissiveSampler",
817
+ "HAS_EMISSIVEMAP",
818
+ parsedMaterial
819
+ );
820
+ parsedMaterial.uniforms.emissiveFactor = material.emissiveFactor || [0, 0, 0];
821
+ }
822
+ switch (material.alphaMode || "MASK") {
823
+ case "MASK":
824
+ const { alphaCutoff = 0.5 } = material;
825
+ parsedMaterial.defines["ALPHA_CUTOFF"] = true;
826
+ parsedMaterial.uniforms.alphaCutoff = alphaCutoff;
827
+ break;
828
+ case "BLEND":
829
+ import_core.log.warn("glTF BLEND alphaMode might not work well because it requires mesh sorting")();
830
+ parsedMaterial.parameters.blend = true;
831
+ parsedMaterial.parameters.blendColorOperation = "add";
832
+ parsedMaterial.parameters.blendColorSrcFactor = "src-alpha";
833
+ parsedMaterial.parameters.blendColorDstFactor = "one-minus-src-alpha";
834
+ parsedMaterial.parameters.blendAlphaOperation = "add";
835
+ parsedMaterial.parameters.blendAlphaSrcFactor = "one";
836
+ parsedMaterial.parameters.blendAlphaDstFactor = "one-minus-src-alpha";
837
+ parsedMaterial.glParameters["blend"] = true;
838
+ parsedMaterial.glParameters["blendEquation"] = import_constants2.GL.FUNC_ADD;
839
+ parsedMaterial.glParameters["blendFunc"] = [
840
+ import_constants2.GL.SRC_ALPHA,
841
+ import_constants2.GL.ONE_MINUS_SRC_ALPHA,
842
+ import_constants2.GL.ONE,
843
+ import_constants2.GL.ONE_MINUS_SRC_ALPHA
844
+ ];
845
+ break;
846
+ }
847
+ }
848
+ function parsePbrMetallicRoughness(device, pbrMetallicRoughness, parsedMaterial) {
849
+ if (pbrMetallicRoughness.baseColorTexture) {
850
+ addTexture(
851
+ device,
852
+ pbrMetallicRoughness.baseColorTexture,
853
+ "pbr_baseColorSampler",
854
+ "HAS_BASECOLORMAP",
855
+ parsedMaterial
856
+ );
857
+ }
858
+ parsedMaterial.uniforms.baseColorFactor = pbrMetallicRoughness.baseColorFactor || [1, 1, 1, 1];
859
+ if (pbrMetallicRoughness.metallicRoughnessTexture) {
860
+ addTexture(
861
+ device,
862
+ pbrMetallicRoughness.metallicRoughnessTexture,
863
+ "pbr_metallicRoughnessSampler",
864
+ "HAS_METALROUGHNESSMAP",
865
+ parsedMaterial
866
+ );
867
+ }
868
+ const { metallicFactor = 1, roughnessFactor = 1 } = pbrMetallicRoughness;
869
+ parsedMaterial.uniforms.metallicRoughnessValues = [metallicFactor, roughnessFactor];
870
+ }
871
+ function addTexture(device, gltfTexture, uniformName, define, parsedMaterial) {
872
+ const image = gltfTexture.texture.source.image;
873
+ let textureOptions;
874
+ if (image.compressed) {
875
+ textureOptions = image;
876
+ } else {
877
+ textureOptions = { data: image };
878
+ }
879
+ const gltfSampler = {
880
+ wrapS: 10497,
881
+ // default REPEAT S (U) wrapping mode.
882
+ wrapT: 10497,
883
+ // default REPEAT T (V) wrapping mode.
884
+ ...gltfTexture?.texture?.sampler
885
+ };
886
+ const texture = device.createTexture({
887
+ id: gltfTexture.uniformName || gltfTexture.id,
888
+ sampler: convertSampler(gltfSampler),
889
+ ...textureOptions
890
+ });
891
+ parsedMaterial.bindings[uniformName] = texture;
892
+ if (define)
893
+ parsedMaterial.defines[define] = true;
894
+ parsedMaterial.generatedTextures.push(texture);
895
+ }
896
+
897
+ // src/parsers/parse-gltf.ts
898
+ var import_engine3 = __toESM(require_engine(), 1);
899
+
900
+ // ../../node_modules/@math.gl/core/dist/lib/common.js
901
+ var RADIANS_TO_DEGREES = 1 / Math.PI * 180;
902
+ var DEGREES_TO_RADIANS = 1 / 180 * Math.PI;
903
+ var DEFAULT_CONFIG = {
904
+ EPSILON: 1e-12,
905
+ debug: false,
906
+ precision: 4,
907
+ printTypes: false,
908
+ printDegrees: false,
909
+ printRowMajor: true,
910
+ _cartographicRadians: false
911
+ };
912
+ globalThis.mathgl = globalThis.mathgl || { config: { ...DEFAULT_CONFIG } };
913
+ var config = globalThis.mathgl.config;
914
+ function formatValue(value, { precision = config.precision } = {}) {
915
+ value = round(value);
916
+ return `${parseFloat(value.toPrecision(precision))}`;
917
+ }
918
+ function isArray(value) {
919
+ return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
920
+ }
921
+ function equals(a, b, epsilon) {
922
+ const oldEpsilon = config.EPSILON;
923
+ if (epsilon) {
924
+ config.EPSILON = epsilon;
925
+ }
926
+ try {
927
+ if (a === b) {
928
+ return true;
929
+ }
930
+ if (isArray(a) && isArray(b)) {
931
+ if (a.length !== b.length) {
932
+ return false;
933
+ }
934
+ for (let i = 0; i < a.length; ++i) {
935
+ if (!equals(a[i], b[i])) {
936
+ return false;
937
+ }
938
+ }
939
+ return true;
940
+ }
941
+ if (a && a.equals) {
942
+ return a.equals(b);
943
+ }
944
+ if (b && b.equals) {
945
+ return b.equals(a);
946
+ }
947
+ if (typeof a === "number" && typeof b === "number") {
948
+ return Math.abs(a - b) <= config.EPSILON * Math.max(1, Math.abs(a), Math.abs(b));
949
+ }
950
+ return false;
951
+ } finally {
952
+ config.EPSILON = oldEpsilon;
953
+ }
954
+ }
955
+ function round(value) {
956
+ return Math.round(value / config.EPSILON) * config.EPSILON;
957
+ }
958
+
959
+ // ../../node_modules/@math.gl/core/dist/classes/base/math-array.js
960
+ var MathArray = class extends Array {
961
+ // Common methods
962
+ /**
963
+ * Clone the current object
964
+ * @returns a new copy of this object
965
+ */
966
+ clone() {
967
+ return new this.constructor().copy(this);
968
+ }
969
+ fromArray(array, offset = 0) {
970
+ for (let i = 0; i < this.ELEMENTS; ++i) {
971
+ this[i] = array[i + offset];
972
+ }
973
+ return this.check();
974
+ }
975
+ toArray(targetArray = [], offset = 0) {
976
+ for (let i = 0; i < this.ELEMENTS; ++i) {
977
+ targetArray[offset + i] = this[i];
978
+ }
979
+ return targetArray;
980
+ }
981
+ toObject(targetObject) {
982
+ return targetObject;
983
+ }
984
+ from(arrayOrObject) {
985
+ return Array.isArray(arrayOrObject) ? this.copy(arrayOrObject) : (
986
+ // @ts-ignore
928
987
  this.fromObject(arrayOrObject)
929
988
  );
930
989
  }
@@ -1564,8 +1623,8 @@ var __exports__ = (() => {
1564
1623
  vec4_transformMat2(this, this, matrix2);
1565
1624
  return this.check();
1566
1625
  }
1567
- transformByQuaternion(quaternion2) {
1568
- transformQuat(this, this, quaternion2);
1626
+ transformByQuaternion(quaternion) {
1627
+ transformQuat(this, this, quaternion);
1569
1628
  return this.check();
1570
1629
  }
1571
1630
  // three.js compatibility
@@ -2549,8 +2608,8 @@ var __exports__ = (() => {
2549
2608
  * @param quaternion Quaternion to create matrix from
2550
2609
  * @returns self
2551
2610
  */
2552
- fromQuaternion(quaternion2) {
2553
- fromQuat(this, quaternion2);
2611
+ fromQuaternion(quaternion) {
2612
+ fromQuat(this, quaternion);
2554
2613
  return this.check();
2555
2614
  }
2556
2615
  /**
@@ -3409,184 +3468,26 @@ var __exports__ = (() => {
3409
3468
  }
3410
3469
  };
3411
3470
 
3412
- // src/gltf/gltf-animator.ts
3413
- var import_core2 = __toESM(require_core(), 1);
3414
- var ATTRIBUTE_TYPE_TO_COMPONENTS = {
3415
- SCALAR: 1,
3416
- VEC2: 2,
3417
- VEC3: 3,
3418
- VEC4: 4,
3419
- MAT2: 4,
3420
- MAT3: 9,
3421
- MAT4: 16
3422
- };
3423
- var ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY = {
3424
- 5120: Int8Array,
3425
- 5121: Uint8Array,
3426
- 5122: Int16Array,
3427
- 5123: Uint16Array,
3428
- 5125: Uint32Array,
3429
- 5126: Float32Array
3430
- };
3431
- var GLTFAnimation = class {
3432
- name;
3433
- startTime = 0;
3434
- playing = true;
3435
- speed = 1;
3436
- channels = [];
3437
- constructor(props) {
3438
- Object.assign(this, props);
3439
- }
3440
- animate(timeMs) {
3441
- if (!this.playing) {
3442
- return;
3443
- }
3444
- const absTime = timeMs / 1e3;
3445
- const time = (absTime - this.startTime) * this.speed;
3446
- this.channels.forEach(({ sampler, target, path }) => {
3447
- interpolate(time, sampler, target, path);
3448
- applyTranslationRotationScale(target, target._node);
3449
- });
3450
- }
3451
- };
3452
- var GLTFAnimator = class {
3453
- animations;
3454
- constructor(gltf) {
3455
- this.animations = gltf.animations.map((animation, index) => {
3456
- const name = animation.name || `Animation-${index}`;
3457
- const samplers = animation.samplers.map(({ input, interpolation = "LINEAR", output }) => ({
3458
- input: accessorToJsArray(gltf.accessors[input]),
3459
- interpolation,
3460
- output: accessorToJsArray(gltf.accessors[output])
3461
- }));
3462
- const channels = animation.channels.map(({ sampler, target }) => ({
3463
- sampler: samplers[sampler],
3464
- target: gltf.nodes[target.node],
3465
- path: target.path
3466
- }));
3467
- return new GLTFAnimation({ name, channels });
3468
- });
3469
- }
3470
- /** @deprecated Use .setTime(). Will be removed (deck.gl is using this) */
3471
- animate(time) {
3472
- this.setTime(time);
3473
- }
3474
- setTime(time) {
3475
- this.animations.forEach((animation) => animation.animate(time));
3476
- }
3477
- getAnimations() {
3478
- return this.animations;
3479
- }
3480
- };
3481
- function accessorToJsArray(accessor) {
3482
- if (!accessor._animation) {
3483
- const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[accessor.componentType];
3484
- const components = ATTRIBUTE_TYPE_TO_COMPONENTS[accessor.type];
3485
- const length4 = components * accessor.count;
3486
- const { buffer, byteOffset } = accessor.bufferView.data;
3487
- const array = new ArrayType(buffer, byteOffset + (accessor.byteOffset || 0), length4);
3488
- if (components === 1) {
3489
- accessor._animation = Array.from(array);
3490
- } else {
3491
- const slicedArray = [];
3492
- for (let i = 0; i < array.length; i += components) {
3493
- slicedArray.push(Array.from(array.slice(i, i + components)));
3494
- }
3495
- accessor._animation = slicedArray;
3496
- }
3497
- }
3498
- return accessor._animation;
3499
- }
3500
- var helperMatrix = new Matrix4();
3501
- function applyTranslationRotationScale(gltfNode, node) {
3502
- node.matrix.identity();
3503
- if (gltfNode.translation) {
3504
- node.matrix.translate(gltfNode.translation);
3505
- }
3506
- if (gltfNode.rotation) {
3507
- const rotationMatrix = helperMatrix.fromQuaternion(gltfNode.rotation);
3508
- node.matrix.multiplyRight(rotationMatrix);
3509
- }
3510
- if (gltfNode.scale) {
3511
- node.matrix.scale(gltfNode.scale);
3512
- }
3513
- }
3514
- var quaternion = new Quaternion();
3515
- function linearInterpolate(target, path, start, stop, ratio) {
3516
- if (path === "rotation") {
3517
- quaternion.slerp({ start, target: stop, ratio });
3518
- for (let i = 0; i < quaternion.length; i++) {
3519
- target[path][i] = quaternion[i];
3520
- }
3521
- } else {
3522
- for (let i = 0; i < start.length; i++) {
3523
- target[path][i] = ratio * stop[i] + (1 - ratio) * start[i];
3524
- }
3525
- }
3526
- }
3527
- function cubicsplineInterpolate(target, path, { p0, outTangent0, inTangent1, p1, tDiff, ratio: t }) {
3528
- for (let i = 0; i < target[path].length; i++) {
3529
- const m0 = outTangent0[i] * tDiff;
3530
- const m1 = inTangent1[i] * tDiff;
3531
- target[path][i] = (2 * Math.pow(t, 3) - 3 * Math.pow(t, 2) + 1) * p0[i] + (Math.pow(t, 3) - 2 * Math.pow(t, 2) + t) * m0 + (-2 * Math.pow(t, 3) + 3 * Math.pow(t, 2)) * p1[i] + (Math.pow(t, 3) - Math.pow(t, 2)) * m1;
3532
- }
3533
- }
3534
- function stepInterpolate(target, path, value) {
3535
- for (let i = 0; i < value.length; i++) {
3536
- target[path][i] = value[i];
3537
- }
3538
- }
3539
- function interpolate(time, { input, interpolation, output }, target, path) {
3540
- const maxTime = input[input.length - 1];
3541
- const animationTime = time % maxTime;
3542
- const nextIndex = input.findIndex((t) => t >= animationTime);
3543
- const previousIndex = Math.max(0, nextIndex - 1);
3544
- if (!Array.isArray(target[path])) {
3545
- switch (path) {
3546
- case "translation":
3547
- target[path] = [0, 0, 0];
3548
- break;
3549
- case "rotation":
3550
- target[path] = [0, 0, 0, 1];
3551
- break;
3552
- case "scale":
3553
- target[path] = [1, 1, 1];
3554
- break;
3555
- default:
3556
- import_core2.log.warn(`Bad animation path ${path}`)();
3557
- }
3558
- }
3559
- const previousTime = input[previousIndex];
3560
- const nextTime = input[nextIndex];
3561
- switch (interpolation) {
3562
- case "STEP":
3563
- stepInterpolate(target, path, output[previousIndex]);
3564
- break;
3565
- case "LINEAR":
3566
- if (nextTime > previousTime) {
3567
- const ratio = (animationTime - previousTime) / (nextTime - previousTime);
3568
- linearInterpolate(target, path, output[previousIndex], output[nextIndex], ratio);
3569
- }
3570
- break;
3571
- case "CUBICSPLINE":
3572
- if (nextTime > previousTime) {
3573
- const ratio = (animationTime - previousTime) / (nextTime - previousTime);
3574
- const tDiff = nextTime - previousTime;
3575
- const p0 = output[3 * previousIndex + 1];
3576
- const outTangent0 = output[3 * previousIndex + 2];
3577
- const inTangent1 = output[3 * nextIndex + 0];
3578
- const p1 = output[3 * nextIndex + 1];
3579
- cubicsplineInterpolate(target, path, { p0, outTangent0, inTangent1, p1, tDiff, ratio });
3580
- }
3581
- break;
3582
- default:
3583
- import_core2.log.warn(`Interpolation ${interpolation} not supported`)();
3584
- break;
3471
+ // src/webgl-to-webgpu/convert-webgl-topology.ts
3472
+ function convertGLDrawModeToTopology(drawMode) {
3473
+ switch (drawMode) {
3474
+ case 0 /* POINTS */:
3475
+ return "point-list";
3476
+ case 1 /* LINES */:
3477
+ return "line-list";
3478
+ case 3 /* LINE_STRIP */:
3479
+ return "line-strip";
3480
+ case 4 /* TRIANGLES */:
3481
+ return "triangle-list";
3482
+ case 5 /* TRIANGLE_STRIP */:
3483
+ return "triangle-strip";
3484
+ default:
3485
+ throw new Error(String(drawMode));
3585
3486
  }
3586
3487
  }
3587
3488
 
3588
3489
  // src/gltf/create-gltf-model.ts
3589
- var import_core4 = __toESM(require_core(), 1);
3490
+ var import_core2 = __toESM(require_core(), 1);
3590
3491
  var import_shadertools = __toESM(require_shadertools(), 1);
3591
3492
  var import_engine2 = __toESM(require_engine(), 1);
3592
3493
  var SHADER = (
@@ -3693,9 +3594,8 @@ layout(0) positions: vec4; // in vec4 POSITION;
3693
3594
  `
3694
3595
  );
3695
3596
  function createGLTFModel(device, options) {
3696
- const { id, geometry, material, vertexCount, materialOptions, modelOptions } = options;
3697
- const parsedMaterial = parsePBRMaterial(device, material, geometry.attributes, materialOptions);
3698
- import_core4.log.info(4, "createGLTFModel defines: ", parsedMaterial.defines)();
3597
+ const { id, geometry, parsedPPBRMaterial, vertexCount, modelOptions = {} } = options;
3598
+ import_core2.log.info(4, "createGLTFModel defines: ", parsedPPBRMaterial.defines)();
3699
3599
  const managedResources = [];
3700
3600
  const parameters = {
3701
3601
  depthWriteEnabled: true,
@@ -3713,180 +3613,353 @@ layout(0) positions: vec4; // in vec4 POSITION;
3713
3613
  vertexCount,
3714
3614
  modules: [import_shadertools.pbrMaterial],
3715
3615
  ...modelOptions,
3716
- defines: { ...parsedMaterial.defines, ...modelOptions.defines },
3717
- parameters: { ...parameters, ...parsedMaterial.parameters, ...modelOptions.parameters }
3616
+ defines: { ...parsedPPBRMaterial.defines, ...modelOptions.defines },
3617
+ parameters: { ...parameters, ...parsedPPBRMaterial.parameters, ...modelOptions.parameters }
3718
3618
  };
3719
3619
  const model = new import_engine2.Model(device, modelProps);
3720
3620
  const { camera, ...pbrMaterialProps } = {
3721
- ...parsedMaterial.uniforms,
3621
+ ...parsedPPBRMaterial.uniforms,
3722
3622
  ...modelOptions.uniforms,
3723
- ...parsedMaterial.bindings,
3623
+ ...parsedPPBRMaterial.bindings,
3724
3624
  ...modelOptions.bindings
3725
3625
  };
3726
3626
  model.shaderInputs.setProps({ pbrMaterial: pbrMaterialProps, pbrProjection: { camera } });
3727
3627
  return new import_engine2.ModelNode({ managedResources, model });
3728
3628
  }
3729
3629
 
3730
- // src/gltf/gl-utils.ts
3731
- function convertGLDrawModeToTopology(drawMode) {
3732
- switch (drawMode) {
3733
- case 0 /* POINTS */:
3734
- return "point-list";
3735
- case 1 /* LINES */:
3736
- return "line-list";
3737
- case 3 /* LINE_STRIP */:
3738
- return "line-strip";
3739
- case 4 /* TRIANGLES */:
3740
- return "triangle-list";
3741
- case 5 /* TRIANGLE_STRIP */:
3742
- return "triangle-strip";
3743
- default:
3744
- throw new Error(String(drawMode));
3745
- }
3746
- }
3747
-
3748
- // src/gltf/gltf-instantiator.ts
3749
- var DEFAULT_OPTIONS = {
3630
+ // src/parsers/parse-gltf.ts
3631
+ var defaultOptions = {
3750
3632
  modelOptions: {},
3751
3633
  pbrDebug: false,
3752
- imageBasedLightingEnvironment: null,
3634
+ imageBasedLightingEnvironment: void 0,
3753
3635
  lights: true,
3754
3636
  useTangents: false
3755
3637
  };
3756
- var GLTFInstantiator = class {
3757
- device;
3758
- options;
3759
- gltf;
3760
- constructor(device, options = {}) {
3761
- this.device = device;
3762
- this.options = { ...DEFAULT_OPTIONS, ...options };
3763
- }
3764
- instantiate(gltf) {
3765
- this.gltf = deepCopy(gltf);
3766
- const scenes = (this.gltf.scenes || []).map((scene) => this.createScene(scene));
3767
- return scenes;
3768
- }
3769
- createAnimator() {
3770
- if (Array.isArray(this.gltf.animations)) {
3771
- return new GLTFAnimator(this.gltf);
3638
+ function parseGLTF(device, gltf, options_ = {}) {
3639
+ const options = { ...defaultOptions, ...options_ };
3640
+ const sceneNodes = gltf.scenes.map(
3641
+ (gltfScene) => createScene(device, gltfScene, gltf.nodes, options)
3642
+ );
3643
+ return sceneNodes;
3644
+ }
3645
+ function createScene(device, gltfScene, gltfNodes, options) {
3646
+ const gltfSceneNodes = gltfScene.nodes || [];
3647
+ const nodes = gltfSceneNodes.map((node) => createNode(device, node, gltfNodes, options));
3648
+ const sceneNode = new import_engine3.GroupNode({
3649
+ id: gltfScene.name || gltfScene.id,
3650
+ children: nodes
3651
+ });
3652
+ return sceneNode;
3653
+ }
3654
+ function createNode(device, gltfNode, gltfNodes, options) {
3655
+ if (!gltfNode._node) {
3656
+ const gltfChildren = gltfNode.children || [];
3657
+ const children = gltfChildren.map((child) => createNode(device, child, gltfNodes, options));
3658
+ if (gltfNode.mesh) {
3659
+ children.push(createMesh(device, gltfNode.mesh, options));
3660
+ }
3661
+ const node = new import_engine3.GroupNode({
3662
+ id: gltfNode.name || gltfNode.id,
3663
+ children
3664
+ });
3665
+ if (gltfNode.matrix) {
3666
+ node.setMatrix(gltfNode.matrix);
3667
+ } else {
3668
+ node.matrix.identity();
3669
+ if (gltfNode.translation) {
3670
+ node.matrix.translate(gltfNode.translation);
3671
+ }
3672
+ if (gltfNode.rotation) {
3673
+ const rotationMatrix = new Matrix4().fromQuaternion(gltfNode.rotation);
3674
+ node.matrix.multiplyRight(rotationMatrix);
3675
+ }
3676
+ if (gltfNode.scale) {
3677
+ node.matrix.scale(gltfNode.scale);
3678
+ }
3772
3679
  }
3773
- return null;
3680
+ gltfNode._node = node;
3774
3681
  }
3775
- createScene(gltfScene) {
3776
- const gltfNodes = gltfScene.nodes || [];
3777
- const nodes = gltfNodes.map((node) => this.createNode(node));
3778
- const scene = new import_engine3.GroupNode({
3779
- id: gltfScene.name || gltfScene.id,
3780
- children: nodes
3682
+ const topLevelNode = gltfNodes.find((node) => node.id === gltfNode.id);
3683
+ topLevelNode._node = gltfNode._node;
3684
+ return gltfNode._node;
3685
+ }
3686
+ function createMesh(device, gltfMesh, options) {
3687
+ if (!gltfMesh._mesh) {
3688
+ const gltfPrimitives = gltfMesh.primitives || [];
3689
+ const primitives = gltfPrimitives.map(
3690
+ (gltfPrimitive, i) => createPrimitive(device, gltfPrimitive, i, gltfMesh, options)
3691
+ );
3692
+ const mesh = new import_engine3.GroupNode({
3693
+ id: gltfMesh.name || gltfMesh.id,
3694
+ children: primitives
3781
3695
  });
3782
- return scene;
3783
- }
3784
- createNode(gltfNode) {
3785
- if (!gltfNode._node) {
3786
- const gltfChildren = gltfNode.children || [];
3787
- const children = gltfChildren.map((child) => this.createNode(child));
3788
- if (gltfNode.mesh) {
3789
- children.push(this.createMesh(gltfNode.mesh));
3696
+ gltfMesh._mesh = mesh;
3697
+ }
3698
+ return gltfMesh._mesh;
3699
+ }
3700
+ function createPrimitive(device, gltfPrimitive, i, gltfMesh, options) {
3701
+ const id = gltfPrimitive.name || `${gltfMesh.name || gltfMesh.id}-primitive-${i}`;
3702
+ const topology = convertGLDrawModeToTopology(gltfPrimitive.mode || 4);
3703
+ const vertexCount = gltfPrimitive.indices ? gltfPrimitive.indices.count : getVertexCount(gltfPrimitive.attributes);
3704
+ const geometry = createGeometry(id, gltfPrimitive, topology);
3705
+ const parsedPPBRMaterial = parsePBRMaterial(
3706
+ device,
3707
+ gltfPrimitive.material,
3708
+ geometry.attributes,
3709
+ options
3710
+ );
3711
+ const modelNode = createGLTFModel(device, {
3712
+ id,
3713
+ geometry: createGeometry(id, gltfPrimitive, topology),
3714
+ parsedPPBRMaterial,
3715
+ modelOptions: options.modelOptions,
3716
+ vertexCount
3717
+ });
3718
+ modelNode.bounds = [gltfPrimitive.attributes.POSITION.min, gltfPrimitive.attributes.POSITION.max];
3719
+ return modelNode;
3720
+ }
3721
+ function getVertexCount(attributes) {
3722
+ throw new Error("getVertexCount not implemented");
3723
+ }
3724
+ function createGeometry(id, gltfPrimitive, topology) {
3725
+ const attributes = {};
3726
+ for (const [attributeName, attribute] of Object.entries(gltfPrimitive.attributes)) {
3727
+ const { components, size, value } = attribute;
3728
+ attributes[attributeName] = { size: size ?? components, value };
3729
+ }
3730
+ return new import_engine3.Geometry({
3731
+ id,
3732
+ topology,
3733
+ indices: gltfPrimitive.indices.value,
3734
+ attributes
3735
+ });
3736
+ }
3737
+
3738
+ // src/gltf/gltf-animator.ts
3739
+ var import_core6 = __toESM(require_core(), 1);
3740
+
3741
+ // src/gltf/animations/interpolate.ts
3742
+ var import_core4 = __toESM(require_core(), 1);
3743
+ var scratchQuaternion = new Quaternion();
3744
+ function interpolate(time, { input, interpolation, output }, target, path) {
3745
+ const maxTime = input[input.length - 1];
3746
+ const animationTime = time % maxTime;
3747
+ const nextIndex = input.findIndex((t) => t >= animationTime);
3748
+ const previousIndex = Math.max(0, nextIndex - 1);
3749
+ if (!Array.isArray(target[path])) {
3750
+ switch (path) {
3751
+ case "translation":
3752
+ target[path] = [0, 0, 0];
3753
+ break;
3754
+ case "rotation":
3755
+ target[path] = [0, 0, 0, 1];
3756
+ break;
3757
+ case "scale":
3758
+ target[path] = [1, 1, 1];
3759
+ break;
3760
+ default:
3761
+ import_core4.log.warn(`Bad animation path ${path}`)();
3762
+ }
3763
+ }
3764
+ const previousTime = input[previousIndex];
3765
+ const nextTime = input[nextIndex];
3766
+ switch (interpolation) {
3767
+ case "STEP":
3768
+ stepInterpolate(target, path, output[previousIndex]);
3769
+ break;
3770
+ case "LINEAR":
3771
+ if (nextTime > previousTime) {
3772
+ const ratio = (animationTime - previousTime) / (nextTime - previousTime);
3773
+ linearInterpolate(
3774
+ target,
3775
+ path,
3776
+ output[previousIndex],
3777
+ output[nextIndex],
3778
+ ratio
3779
+ );
3790
3780
  }
3791
- const node = new import_engine3.GroupNode({
3792
- id: gltfNode.name || gltfNode.id,
3793
- children
3794
- });
3795
- if (gltfNode.matrix) {
3796
- node.setMatrix(gltfNode.matrix);
3797
- } else {
3798
- node.matrix.identity();
3799
- if (gltfNode.translation) {
3800
- node.matrix.translate(gltfNode.translation);
3801
- }
3802
- if (gltfNode.rotation) {
3803
- const rotationMatrix = new Matrix4().fromQuaternion(gltfNode.rotation);
3804
- node.matrix.multiplyRight(rotationMatrix);
3805
- }
3806
- if (gltfNode.scale) {
3807
- node.matrix.scale(gltfNode.scale);
3808
- }
3781
+ break;
3782
+ case "CUBICSPLINE":
3783
+ if (nextTime > previousTime) {
3784
+ const ratio = (animationTime - previousTime) / (nextTime - previousTime);
3785
+ const tDiff = nextTime - previousTime;
3786
+ const p0 = output[3 * previousIndex + 1];
3787
+ const outTangent0 = output[3 * previousIndex + 2];
3788
+ const inTangent1 = output[3 * nextIndex + 0];
3789
+ const p1 = output[3 * nextIndex + 1];
3790
+ cubicsplineInterpolate(target, path, { p0, outTangent0, inTangent1, p1, tDiff, ratio });
3809
3791
  }
3810
- gltfNode._node = node;
3811
- }
3812
- const topLevelNode = this.gltf.nodes.find((node) => node.id === gltfNode.id);
3813
- topLevelNode._node = gltfNode._node;
3814
- return gltfNode._node;
3815
- }
3816
- createMesh(gltfMesh) {
3817
- if (!gltfMesh._mesh) {
3818
- const gltfPrimitives = gltfMesh.primitives || [];
3819
- const primitives = gltfPrimitives.map(
3820
- (gltfPrimitive, i) => this.createPrimitive(gltfPrimitive, i, gltfMesh)
3821
- );
3822
- const mesh = new import_engine3.GroupNode({
3823
- id: gltfMesh.name || gltfMesh.id,
3824
- children: primitives
3825
- });
3826
- gltfMesh._mesh = mesh;
3827
- }
3828
- return gltfMesh._mesh;
3829
- }
3830
- createPrimitive(gltfPrimitive, i, gltfMesh) {
3831
- const id = gltfPrimitive.name || `${gltfMesh.name || gltfMesh.id}-primitive-${i}`;
3832
- const topology = convertGLDrawModeToTopology(gltfPrimitive.mode || 4);
3833
- const vertexCount = gltfPrimitive.indices ? gltfPrimitive.indices.count : this.getVertexCount(gltfPrimitive.attributes);
3834
- const modelNode = createGLTFModel(this.device, {
3835
- id,
3836
- geometry: this.createGeometry(id, gltfPrimitive, topology),
3837
- material: gltfPrimitive.material,
3838
- materialOptions: this.options,
3839
- modelOptions: this.options.modelOptions,
3840
- vertexCount
3841
- });
3842
- modelNode.bounds = [
3843
- gltfPrimitive.attributes.POSITION.min,
3844
- gltfPrimitive.attributes.POSITION.max
3845
- ];
3846
- return modelNode;
3847
- }
3848
- getVertexCount(attributes) {
3849
- throw new Error("getVertexCount not implemented");
3850
- }
3851
- createGeometry(id, gltfPrimitive, topology) {
3852
- const attributes = {};
3853
- for (const [attributeName, attribute] of Object.entries(gltfPrimitive.attributes)) {
3854
- const { components, size, value } = attribute;
3855
- attributes[attributeName] = { size: size ?? components, value };
3856
- }
3857
- return new import_engine3.Geometry({
3858
- id,
3859
- topology,
3860
- indices: gltfPrimitive.indices.value,
3861
- attributes
3862
- });
3792
+ break;
3793
+ default:
3794
+ import_core4.log.warn(`Interpolation ${interpolation} not supported`)();
3795
+ break;
3863
3796
  }
3864
- createBuffer(attribute, usage) {
3865
- if (!attribute.bufferView) {
3866
- attribute.bufferView = {};
3797
+ }
3798
+ function linearInterpolate(target, path, start, stop, ratio) {
3799
+ if (!target[path]) {
3800
+ throw new Error();
3801
+ }
3802
+ if (path === "rotation") {
3803
+ scratchQuaternion.slerp({ start, target: stop, ratio });
3804
+ for (let i = 0; i < scratchQuaternion.length; i++) {
3805
+ target[path][i] = scratchQuaternion[i];
3867
3806
  }
3868
- const { bufferView } = attribute;
3869
- if (!bufferView.lumaBuffers) {
3870
- bufferView.lumaBuffers = {};
3807
+ } else {
3808
+ for (let i = 0; i < start.length; i++) {
3809
+ target[path][i] = ratio * stop[i] + (1 - ratio) * start[i];
3871
3810
  }
3872
- if (!bufferView.lumaBuffers[usage]) {
3873
- bufferView.lumaBuffers[usage] = this.device.createBuffer({
3874
- id: `from-${bufferView.id}`,
3875
- // Draco decoded files have attribute.value
3876
- data: bufferView.data || attribute.value
3877
- });
3811
+ }
3812
+ }
3813
+ function cubicsplineInterpolate(target, path, {
3814
+ p0,
3815
+ outTangent0,
3816
+ inTangent1,
3817
+ p1,
3818
+ tDiff,
3819
+ ratio: t
3820
+ }) {
3821
+ if (!target[path]) {
3822
+ throw new Error();
3823
+ }
3824
+ for (let i = 0; i < target[path].length; i++) {
3825
+ const m0 = outTangent0[i] * tDiff;
3826
+ const m1 = inTangent1[i] * tDiff;
3827
+ target[path][i] = (2 * Math.pow(t, 3) - 3 * Math.pow(t, 2) + 1) * p0[i] + (Math.pow(t, 3) - 2 * Math.pow(t, 2) + t) * m0 + (-2 * Math.pow(t, 3) + 3 * Math.pow(t, 2)) * p1[i] + (Math.pow(t, 3) - Math.pow(t, 2)) * m1;
3828
+ }
3829
+ }
3830
+ function stepInterpolate(target, path, value) {
3831
+ if (!target[path]) {
3832
+ throw new Error();
3833
+ }
3834
+ for (let i = 0; i < value.length; i++) {
3835
+ target[path][i] = value[i];
3836
+ }
3837
+ }
3838
+
3839
+ // src/gltf/gltf-animator.ts
3840
+ var GLTFSingleAnimator = class {
3841
+ animation;
3842
+ startTime = 0;
3843
+ playing = true;
3844
+ speed = 1;
3845
+ constructor(props) {
3846
+ this.animation = props.animation;
3847
+ this.animation.name ||= "unnamed";
3848
+ Object.assign(this, props);
3849
+ }
3850
+ setTime(timeMs) {
3851
+ if (!this.playing) {
3852
+ return;
3878
3853
  }
3879
- return bufferView.lumaBuffers[usage];
3854
+ const absTime = timeMs / 1e3;
3855
+ const time = (absTime - this.startTime) * this.speed;
3856
+ this.animation.channels.forEach(({ sampler, target, path }) => {
3857
+ interpolate(time, sampler, target, path);
3858
+ applyTranslationRotationScale(target, target._node);
3859
+ });
3880
3860
  }
3881
- // TODO - create sampler in WebGL2
3882
- createSampler(gltfSampler) {
3883
- return gltfSampler;
3861
+ };
3862
+ var GLTFAnimator = class {
3863
+ animations;
3864
+ constructor(props) {
3865
+ this.animations = props.animations.map((animation, index) => {
3866
+ const name = animation.name || `Animation-${index}`;
3867
+ return new GLTFSingleAnimator({
3868
+ animation: { name, channels: animation.channels }
3869
+ });
3870
+ });
3884
3871
  }
3885
- // Helper methods (move to GLTFLoader.resolve...?)
3886
- needsPOT() {
3887
- return false;
3872
+ /** @deprecated Use .setTime(). Will be removed (deck.gl is using this) */
3873
+ animate(time) {
3874
+ import_core6.log.warn("GLTFAnimator#animate is deprecated. Use GLTFAnimator#setTime instead")();
3875
+ this.setTime(time);
3876
+ }
3877
+ setTime(time) {
3878
+ this.animations.forEach((animation) => animation.setTime(time));
3879
+ }
3880
+ getAnimations() {
3881
+ return this.animations;
3888
3882
  }
3889
3883
  };
3884
+ var scratchMatrix = new Matrix4();
3885
+ function applyTranslationRotationScale(gltfNode, node) {
3886
+ node.matrix.identity();
3887
+ if (gltfNode.translation) {
3888
+ node.matrix.translate(gltfNode.translation);
3889
+ }
3890
+ if (gltfNode.rotation) {
3891
+ const rotationMatrix = scratchMatrix.fromQuaternion(gltfNode.rotation);
3892
+ node.matrix.multiplyRight(rotationMatrix);
3893
+ }
3894
+ if (gltfNode.scale) {
3895
+ node.matrix.scale(gltfNode.scale);
3896
+ }
3897
+ }
3898
+
3899
+ // src/webgl-to-webgpu/convert-webgl-attribute.ts
3900
+ var ATTRIBUTE_TYPE_TO_COMPONENTS = {
3901
+ SCALAR: 1,
3902
+ VEC2: 2,
3903
+ VEC3: 3,
3904
+ VEC4: 4,
3905
+ MAT2: 4,
3906
+ MAT3: 9,
3907
+ MAT4: 16
3908
+ };
3909
+ var ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY = {
3910
+ 5120: Int8Array,
3911
+ 5121: Uint8Array,
3912
+ 5122: Int16Array,
3913
+ 5123: Uint16Array,
3914
+ 5125: Uint32Array,
3915
+ 5126: Float32Array
3916
+ };
3917
+ function accessorToTypedArray(accessor) {
3918
+ const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[accessor.componentType];
3919
+ const components = ATTRIBUTE_TYPE_TO_COMPONENTS[accessor.type];
3920
+ const length4 = components * accessor.count;
3921
+ const { buffer, byteOffset = 0 } = accessor.bufferView?.data ?? {};
3922
+ const typedArray = new ArrayType(buffer, byteOffset + (accessor.byteOffset || 0), length4);
3923
+ return { typedArray, components };
3924
+ }
3925
+
3926
+ // src/parsers/parse-gltf-animations.ts
3927
+ function parseGLTFAnimations(gltf) {
3928
+ const gltfAnimations = gltf.animations || [];
3929
+ return gltfAnimations.map((animation, index) => {
3930
+ const name = animation.name || `Animation-${index}`;
3931
+ const samplers = animation.samplers.map(
3932
+ ({ input, interpolation = "LINEAR", output }) => ({
3933
+ input: accessorToJsArray(gltf.accessors[input]),
3934
+ interpolation,
3935
+ output: accessorToJsArray(gltf.accessors[output])
3936
+ })
3937
+ );
3938
+ const channels = animation.channels.map(({ sampler, target }) => ({
3939
+ sampler: samplers[sampler],
3940
+ target: gltf.nodes[target.node ?? 0],
3941
+ path: target.path
3942
+ }));
3943
+ return { name, channels };
3944
+ });
3945
+ }
3946
+ function accessorToJsArray(accessor) {
3947
+ if (!accessor._animation) {
3948
+ const { typedArray: array, components } = accessorToTypedArray(accessor);
3949
+ if (components === 1) {
3950
+ accessor._animation = Array.from(array);
3951
+ } else {
3952
+ const slicedArray = [];
3953
+ for (let i = 0; i < array.length; i += components) {
3954
+ slicedArray.push(Array.from(array.slice(i, i + components)));
3955
+ }
3956
+ accessor._animation = slicedArray;
3957
+ }
3958
+ }
3959
+ return accessor._animation;
3960
+ }
3961
+
3962
+ // src/utils/deep-copy.ts
3890
3963
  function deepCopy(object) {
3891
3964
  if (ArrayBuffer.isView(object) || object instanceof ArrayBuffer || object instanceof ImageBitmap) {
3892
3965
  return object;
@@ -3904,11 +3977,12 @@ layout(0) positions: vec4; // in vec4 POSITION;
3904
3977
  return object;
3905
3978
  }
3906
3979
 
3907
- // src/gltf/create-gltf-objects.ts
3980
+ // src/gltf/create-scenegraph-from-gltf.ts
3908
3981
  function createScenegraphsFromGLTF(device, gltf, options) {
3909
- const instantiator = new GLTFInstantiator(device, options);
3910
- const scenes = instantiator.instantiate(gltf);
3911
- const animator = instantiator.createAnimator();
3982
+ gltf = deepCopy(gltf);
3983
+ const scenes = parseGLTF(device, gltf, options);
3984
+ const animations = parseGLTFAnimations(gltf);
3985
+ const animator = new GLTFAnimator({ animations });
3912
3986
  return { scenes, animator };
3913
3987
  }
3914
3988
  return __toCommonJS(bundle_exports);