@luma.gl/gltf 9.2.6 → 9.3.0-alpha.11

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 (96) hide show
  1. package/dist/dist.dev.js +4064 -1967
  2. package/dist/dist.min.js +117 -46
  3. package/dist/gltf/animations/animations.d.ts +57 -5
  4. package/dist/gltf/animations/animations.d.ts.map +1 -1
  5. package/dist/gltf/animations/interpolate.d.ts +6 -3
  6. package/dist/gltf/animations/interpolate.d.ts.map +1 -1
  7. package/dist/gltf/animations/interpolate.js +47 -51
  8. package/dist/gltf/animations/interpolate.js.map +1 -1
  9. package/dist/gltf/create-gltf-model.d.ts +15 -1
  10. package/dist/gltf/create-gltf-model.d.ts.map +1 -1
  11. package/dist/gltf/create-gltf-model.js +168 -43
  12. package/dist/gltf/create-gltf-model.js.map +1 -1
  13. package/dist/gltf/create-scenegraph-from-gltf.d.ts +39 -2
  14. package/dist/gltf/create-scenegraph-from-gltf.d.ts.map +1 -1
  15. package/dist/gltf/create-scenegraph-from-gltf.js +76 -6
  16. package/dist/gltf/create-scenegraph-from-gltf.js.map +1 -1
  17. package/dist/gltf/gltf-animator.d.ts +37 -0
  18. package/dist/gltf/gltf-animator.d.ts.map +1 -1
  19. package/dist/gltf/gltf-animator.js +112 -17
  20. package/dist/gltf/gltf-animator.js.map +1 -1
  21. package/dist/gltf/gltf-extension-support.d.ts +13 -0
  22. package/dist/gltf/gltf-extension-support.d.ts.map +1 -0
  23. package/dist/gltf/gltf-extension-support.js +178 -0
  24. package/dist/gltf/gltf-extension-support.js.map +1 -0
  25. package/dist/index.cjs +1806 -298
  26. package/dist/index.cjs.map +4 -4
  27. package/dist/index.d.ts +3 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/parsers/parse-gltf-animations.d.ts +1 -0
  32. package/dist/parsers/parse-gltf-animations.d.ts.map +1 -1
  33. package/dist/parsers/parse-gltf-animations.js +373 -27
  34. package/dist/parsers/parse-gltf-animations.js.map +1 -1
  35. package/dist/parsers/parse-gltf-lights.d.ts +5 -0
  36. package/dist/parsers/parse-gltf-lights.d.ts.map +1 -0
  37. package/dist/parsers/parse-gltf-lights.js +163 -0
  38. package/dist/parsers/parse-gltf-lights.js.map +1 -0
  39. package/dist/parsers/parse-gltf.d.ts +19 -2
  40. package/dist/parsers/parse-gltf.d.ts.map +1 -1
  41. package/dist/parsers/parse-gltf.js +120 -67
  42. package/dist/parsers/parse-gltf.js.map +1 -1
  43. package/dist/parsers/parse-pbr-material.d.ts +115 -2
  44. package/dist/parsers/parse-pbr-material.d.ts.map +1 -1
  45. package/dist/parsers/parse-pbr-material.js +602 -53
  46. package/dist/parsers/parse-pbr-material.js.map +1 -1
  47. package/dist/pbr/pbr-environment.d.ts +10 -4
  48. package/dist/pbr/pbr-environment.d.ts.map +1 -1
  49. package/dist/pbr/pbr-environment.js +18 -15
  50. package/dist/pbr/pbr-environment.js.map +1 -1
  51. package/dist/pbr/pbr-material.d.ts +13 -3
  52. package/dist/pbr/pbr-material.d.ts.map +1 -1
  53. package/dist/pbr/texture-transform.d.ts +24 -0
  54. package/dist/pbr/texture-transform.d.ts.map +1 -0
  55. package/dist/pbr/texture-transform.js +98 -0
  56. package/dist/pbr/texture-transform.js.map +1 -0
  57. package/dist/webgl-to-webgpu/convert-webgl-attribute.d.ts +12 -1
  58. package/dist/webgl-to-webgpu/convert-webgl-attribute.d.ts.map +1 -1
  59. package/dist/webgl-to-webgpu/convert-webgl-attribute.js +3 -0
  60. package/dist/webgl-to-webgpu/convert-webgl-attribute.js.map +1 -1
  61. package/dist/webgl-to-webgpu/convert-webgl-sampler.d.ts +11 -5
  62. package/dist/webgl-to-webgpu/convert-webgl-sampler.d.ts.map +1 -1
  63. package/dist/webgl-to-webgpu/convert-webgl-sampler.js +16 -12
  64. package/dist/webgl-to-webgpu/convert-webgl-sampler.js.map +1 -1
  65. package/dist/webgl-to-webgpu/convert-webgl-topology.d.ts +2 -9
  66. package/dist/webgl-to-webgpu/convert-webgl-topology.d.ts.map +1 -1
  67. package/dist/webgl-to-webgpu/convert-webgl-topology.js +3 -15
  68. package/dist/webgl-to-webgpu/convert-webgl-topology.js.map +1 -1
  69. package/dist/webgl-to-webgpu/gltf-webgl-constants.d.ts +27 -0
  70. package/dist/webgl-to-webgpu/gltf-webgl-constants.d.ts.map +1 -0
  71. package/dist/webgl-to-webgpu/gltf-webgl-constants.js +34 -0
  72. package/dist/webgl-to-webgpu/gltf-webgl-constants.js.map +1 -0
  73. package/package.json +8 -9
  74. package/src/gltf/animations/animations.ts +88 -6
  75. package/src/gltf/animations/interpolate.ts +84 -96
  76. package/src/gltf/create-gltf-model.ts +233 -48
  77. package/src/gltf/create-scenegraph-from-gltf.ts +134 -11
  78. package/src/gltf/gltf-animator.ts +198 -20
  79. package/src/gltf/gltf-extension-support.ts +226 -0
  80. package/src/index.ts +11 -2
  81. package/src/parsers/parse-gltf-animations.ts +533 -32
  82. package/src/parsers/parse-gltf-lights.ts +218 -0
  83. package/src/parsers/parse-gltf.ts +189 -96
  84. package/src/parsers/parse-pbr-material.ts +974 -79
  85. package/src/pbr/pbr-environment.ts +44 -21
  86. package/src/pbr/pbr-material.ts +18 -3
  87. package/src/pbr/texture-transform.ts +263 -0
  88. package/src/webgl-to-webgpu/convert-webgl-attribute.ts +12 -1
  89. package/src/webgl-to-webgpu/convert-webgl-sampler.ts +38 -29
  90. package/src/webgl-to-webgpu/convert-webgl-topology.ts +3 -15
  91. package/src/webgl-to-webgpu/gltf-webgl-constants.ts +35 -0
  92. package/dist/utils/deep-copy.d.ts +0 -3
  93. package/dist/utils/deep-copy.d.ts.map +0 -1
  94. package/dist/utils/deep-copy.js +0 -21
  95. package/dist/utils/deep-copy.js.map +0 -1
  96. package/src/utils/deep-copy.ts +0 -22
@@ -2,32 +2,77 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {GLTFNodePostprocessed} from '@loaders.gl/gltf';
6
5
  import {log} from '@luma.gl/core';
7
- import {GroupNode} from '@luma.gl/engine';
8
- import {Matrix4} from '@math.gl/core';
9
- import {GLTFAnimation} from './animations/animations';
10
- import {interpolate} from './animations/interpolate';
6
+ import {GroupNode, Material} from '@luma.gl/engine';
7
+ import {
8
+ GLTFAnimation,
9
+ GLTFMaterialAnimationChannel,
10
+ GLTFMaterialAnimationProperty,
11
+ GLTFTextureTransformAnimationChannel
12
+ } from './animations/animations';
13
+ import {evaluateSampler, interpolate} from './animations/interpolate';
14
+ import {
15
+ getTextureTransformDeltaMatrix,
16
+ getTextureTransformSlotDefinition,
17
+ type PBRTextureTransform,
18
+ type PBRTextureTransformSlot
19
+ } from '../pbr/texture-transform';
11
20
 
21
+ /** Construction props for a single glTF animation controller. */
12
22
  type GLTFSingleAnimatorProps = {
23
+ /** Animation data to evaluate. */
13
24
  animation: GLTFAnimation;
25
+ /** Mapping from glTF node ids to scenegraph nodes. */
26
+ gltfNodeIdToNodeMap: Map<string, GroupNode>;
27
+ /** Materials aligned with the source glTF materials array. */
28
+ materials?: Material[];
29
+ /** Start time in seconds. */
14
30
  startTime?: number;
31
+ /** Whether playback is active. */
15
32
  playing?: boolean;
33
+ /** Playback speed multiplier. */
16
34
  speed?: number;
17
35
  };
18
36
 
37
+ /** Evaluates one glTF animation against the generated scenegraph. */
19
38
  class GLTFSingleAnimator {
39
+ /** Animation definition being played. */
20
40
  animation: GLTFAnimation;
41
+ /** Target scenegraph lookup table. */
42
+ gltfNodeIdToNodeMap: Map<string, GroupNode>;
43
+ /** Materials aligned with the source glTF materials array. */
44
+ materials: Material[];
45
+ /** Playback start time in seconds. */
21
46
  startTime: number = 0;
47
+ /** Whether playback is currently enabled. */
22
48
  playing: boolean = true;
49
+ /** Playback speed multiplier. */
23
50
  speed: number = 1;
51
+ /** Mutable runtime texture-transform state for animated material slots. */
52
+ materialTextureTransformState = new Map<
53
+ Material,
54
+ Partial<Record<PBRTextureTransformSlot, PBRTextureTransform>>
55
+ >();
24
56
 
57
+ /** Creates a single-animation controller. */
25
58
  constructor(props: GLTFSingleAnimatorProps) {
26
59
  this.animation = props.animation;
60
+ this.gltfNodeIdToNodeMap = props.gltfNodeIdToNodeMap;
61
+ this.materials = props.materials || [];
27
62
  this.animation.name ||= 'unnamed';
28
63
  Object.assign(this, props);
64
+
65
+ if (
66
+ this.animation.channels.some(channel => channel.type !== 'node') &&
67
+ !this.materials.length
68
+ ) {
69
+ throw new Error(
70
+ `Animation ${this.animation.name} targets materials, but GLTFAnimator was created without a materials array`
71
+ );
72
+ }
29
73
  }
30
74
 
75
+ /** Advances the animation to the supplied wall-clock time in milliseconds. */
31
76
  setTime(timeMs: number) {
32
77
  if (!this.playing) {
33
78
  return;
@@ -36,24 +81,64 @@ class GLTFSingleAnimator {
36
81
  const absTime = timeMs / 1000;
37
82
  const time = (absTime - this.startTime) * this.speed;
38
83
 
39
- this.animation.channels.forEach(({sampler, target, path}) => {
40
- interpolate(time, sampler, target, path);
41
- applyTranslationRotationScale(target, (target as any)._node as GroupNode);
84
+ this.animation.channels.forEach(channel => {
85
+ if (channel.type === 'node') {
86
+ const {sampler, targetNodeId, path} = channel;
87
+ const targetNode = this.gltfNodeIdToNodeMap.get(targetNodeId);
88
+ if (!targetNode) {
89
+ throw new Error(`Cannot find animation target node ${targetNodeId}`);
90
+ }
91
+
92
+ interpolate(time, sampler, targetNode, path);
93
+ return;
94
+ }
95
+
96
+ const material = this.materials[channel.targetMaterialIndex];
97
+ if (!material) {
98
+ throw new Error(
99
+ `Cannot find animation target material ${channel.targetMaterialIndex} for ${channel.pointer}`
100
+ );
101
+ }
102
+
103
+ const value = evaluateSampler(time, channel.sampler);
104
+ if (value) {
105
+ if (channel.type === 'material') {
106
+ applyMaterialAnimationValue(material, channel, value);
107
+ } else {
108
+ applyTextureTransformAnimationValue(
109
+ material,
110
+ channel,
111
+ value,
112
+ this.materialTextureTransformState
113
+ );
114
+ }
115
+ }
42
116
  });
43
117
  }
44
118
  }
45
119
 
120
+ /** Construction props for {@link GLTFAnimator}. */
46
121
  export type GLTFAnimatorProps = {
122
+ /** Parsed animations from the source glTF. */
47
123
  animations: GLTFAnimation[];
124
+ /** Mapping from glTF node ids to scenegraph nodes. */
125
+ gltfNodeIdToNodeMap: Map<string, GroupNode>;
126
+ /** Materials aligned with the source glTF materials array. */
127
+ materials?: Material[];
48
128
  };
49
129
 
130
+ /** Coordinates playback of every animation found in a glTF scene. */
50
131
  export class GLTFAnimator {
132
+ /** Individual animation controllers. */
51
133
  animations: GLTFSingleAnimator[];
52
134
 
135
+ /** Creates an animator for the supplied glTF scenegraph. */
53
136
  constructor(props: GLTFAnimatorProps) {
54
137
  this.animations = props.animations.map((animation, index) => {
55
138
  const name = animation.name || `Animation-${index}`;
56
139
  return new GLTFSingleAnimator({
140
+ gltfNodeIdToNodeMap: props.gltfNodeIdToNodeMap,
141
+ materials: props.materials,
57
142
  animation: {name, channels: animation.channels}
58
143
  });
59
144
  });
@@ -65,31 +150,124 @@ export class GLTFAnimator {
65
150
  this.setTime(time);
66
151
  }
67
152
 
153
+ /** Advances every animation to the supplied wall-clock time in milliseconds. */
68
154
  setTime(time: number): void {
69
155
  this.animations.forEach(animation => animation.setTime(time));
70
156
  }
71
157
 
158
+ /** Returns the per-animation controllers managed by this animator. */
72
159
  getAnimations() {
73
160
  return this.animations;
74
161
  }
75
162
  }
76
163
 
77
- // TODO: share with GLTFInstantiator
78
- const scratchMatrix = new Matrix4();
164
+ function applyMaterialAnimationValue(
165
+ material: Material,
166
+ channel: GLTFMaterialAnimationChannel,
167
+ value: number[]
168
+ ): void {
169
+ const pbrMaterial =
170
+ channel.component !== undefined
171
+ ? {
172
+ [channel.property]: updateMaterialArrayComponent(
173
+ getCurrentMaterialValue(material, channel.property),
174
+ channel.component,
175
+ value[0]
176
+ )
177
+ }
178
+ : {
179
+ [channel.property]: value.length === 1 ? value[0] : value
180
+ };
79
181
 
80
- function applyTranslationRotationScale(gltfNode: GLTFNodePostprocessed, node: GroupNode) {
81
- node.matrix.identity();
182
+ material.setProps({pbrMaterial});
183
+ }
82
184
 
83
- if (gltfNode.translation) {
84
- node.matrix.translate(gltfNode.translation);
85
- }
185
+ function getCurrentMaterialValue(
186
+ material: Material,
187
+ property: GLTFMaterialAnimationProperty
188
+ ): number[] {
189
+ const uniformValues = material.shaderInputs.getUniformValues() as Record<string, any>;
190
+ const currentValue = uniformValues['pbrMaterial']?.[property];
191
+ return Array.isArray(currentValue) ? [...currentValue] : [];
192
+ }
86
193
 
87
- if (gltfNode.rotation) {
88
- const rotationMatrix = scratchMatrix.fromQuaternion(gltfNode.rotation);
89
- node.matrix.multiplyRight(rotationMatrix);
194
+ function updateMaterialArrayComponent(
195
+ currentValue: number[],
196
+ component: number,
197
+ nextValue: number
198
+ ): number[] {
199
+ const updatedValue = [...currentValue];
200
+ updatedValue[component] = nextValue;
201
+ return updatedValue;
202
+ }
203
+
204
+ function applyTextureTransformAnimationValue(
205
+ material: Material,
206
+ channel: GLTFTextureTransformAnimationChannel,
207
+ value: number[],
208
+ materialTextureTransformState: Map<
209
+ Material,
210
+ Partial<Record<PBRTextureTransformSlot, PBRTextureTransform>>
211
+ >
212
+ ): void {
213
+ const slotDefinition = getTextureTransformSlotDefinition(channel.textureSlot);
214
+ const currentTransform = getCurrentTextureTransform(
215
+ materialTextureTransformState,
216
+ material,
217
+ channel
218
+ );
219
+
220
+ switch (channel.path) {
221
+ case 'offset':
222
+ if (channel.component !== undefined) {
223
+ currentTransform.offset[channel.component] = value[0];
224
+ } else {
225
+ currentTransform.offset = [value[0], value[1]];
226
+ }
227
+ break;
228
+
229
+ case 'rotation':
230
+ currentTransform.rotation = value[0];
231
+ break;
232
+
233
+ case 'scale':
234
+ if (channel.component !== undefined) {
235
+ currentTransform.scale[channel.component] = value[0];
236
+ } else {
237
+ currentTransform.scale = [value[0], value[1]];
238
+ }
239
+ break;
90
240
  }
91
241
 
92
- if (gltfNode.scale) {
93
- node.matrix.scale(gltfNode.scale);
242
+ material.setProps({
243
+ pbrMaterial: {
244
+ [slotDefinition.uvTransformUniform]: getTextureTransformDeltaMatrix(
245
+ channel.baseTransform,
246
+ currentTransform
247
+ )
248
+ }
249
+ });
250
+ }
251
+
252
+ function getCurrentTextureTransform(
253
+ materialTextureTransformState: Map<
254
+ Material,
255
+ Partial<Record<PBRTextureTransformSlot, PBRTextureTransform>>
256
+ >,
257
+ material: Material,
258
+ channel: GLTFTextureTransformAnimationChannel
259
+ ): PBRTextureTransform {
260
+ const materialState = materialTextureTransformState.get(material) || {};
261
+ let textureTransformState = materialState[channel.textureSlot];
262
+ if (!textureTransformState) {
263
+ textureTransformState = {
264
+ offset: [...channel.baseTransform.offset] as [number, number],
265
+ rotation: channel.baseTransform.rotation,
266
+ scale: [...channel.baseTransform.scale] as [number, number]
267
+ };
268
+ materialState[channel.textureSlot] = textureTransformState;
269
+ materialTextureTransformState.set(material, materialState);
94
270
  }
271
+
272
+ return textureTransformState;
95
273
  }
@@ -0,0 +1,226 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {GLTFPostprocessed} from '@loaders.gl/gltf';
6
+
7
+ export type GLTFExtensionSupportLevel = 'built-in' | 'parsed-and-wired' | 'loader-only' | 'none';
8
+
9
+ export type GLTFExtensionSupport = {
10
+ extensionName: string;
11
+ supported: boolean;
12
+ supportLevel: GLTFExtensionSupportLevel;
13
+ comment: string;
14
+ };
15
+
16
+ type GLTFExtensionSupportDefinition = Omit<GLTFExtensionSupport, 'extensionName' | 'supported'>;
17
+
18
+ type GLTFPostprocessedWithRemovedExtensions = GLTFPostprocessed & {
19
+ extensionsRemoved?: string[];
20
+ lights?: unknown[];
21
+ };
22
+
23
+ const UNKNOWN_EXTENSION_SUPPORT: GLTFExtensionSupportDefinition = {
24
+ supportLevel: 'none',
25
+ comment: 'Not currently listed in the luma.gl glTF extension support registry.'
26
+ };
27
+
28
+ const GLTF_EXTENSION_SUPPORT_REGISTRY: Record<string, GLTFExtensionSupportDefinition> = {
29
+ KHR_draco_mesh_compression: {
30
+ supportLevel: 'built-in',
31
+ comment: 'Decoded by loaders.gl before luma.gl builds the scenegraph.'
32
+ },
33
+ EXT_meshopt_compression: {
34
+ supportLevel: 'built-in',
35
+ comment: 'Meshopt-compressed primitives are decoded during load.'
36
+ },
37
+ KHR_mesh_quantization: {
38
+ supportLevel: 'built-in',
39
+ comment: 'Quantized accessors are unpacked before geometry creation.'
40
+ },
41
+ KHR_lights_punctual: {
42
+ supportLevel: 'built-in',
43
+ comment: 'Parsed into luma.gl Light objects.'
44
+ },
45
+ KHR_materials_unlit: {
46
+ supportLevel: 'built-in',
47
+ comment: 'Unlit materials bypass the default lighting path.'
48
+ },
49
+ KHR_materials_emissive_strength: {
50
+ supportLevel: 'built-in',
51
+ comment: 'Applied by the stock PBR shader.'
52
+ },
53
+ KHR_texture_basisu: {
54
+ supportLevel: 'built-in',
55
+ comment: 'BasisU / KTX2 textures pass through when the device supports them.'
56
+ },
57
+ KHR_texture_transform: {
58
+ supportLevel: 'built-in',
59
+ comment: 'UV transforms are applied during load.'
60
+ },
61
+ EXT_texture_webp: {
62
+ supportLevel: 'loader-only',
63
+ comment:
64
+ 'Texture source is resolved during load; final support depends on browser and device decode support.'
65
+ },
66
+ EXT_texture_avif: {
67
+ supportLevel: 'loader-only',
68
+ comment:
69
+ 'Texture source is resolved during load; final support depends on browser and device decode support.'
70
+ },
71
+ KHR_materials_specular: {
72
+ supportLevel: 'built-in',
73
+ comment: 'The stock shader now applies specular factors and textures to the dielectric F0 term.'
74
+ },
75
+ KHR_materials_ior: {
76
+ supportLevel: 'built-in',
77
+ comment: 'The stock shader now drives dielectric reflectance from the glTF IOR value.'
78
+ },
79
+ KHR_materials_transmission: {
80
+ supportLevel: 'built-in',
81
+ comment:
82
+ 'The stock shader now applies transmission to the base layer and exposes transparency through alpha, without a scene-color refraction buffer.'
83
+ },
84
+ KHR_materials_volume: {
85
+ supportLevel: 'built-in',
86
+ comment: 'Thickness and attenuation now tint transmitted light in the stock shader.'
87
+ },
88
+ KHR_materials_clearcoat: {
89
+ supportLevel: 'built-in',
90
+ comment: 'The stock shader now adds a secondary clearcoat specular lobe.'
91
+ },
92
+ KHR_materials_sheen: {
93
+ supportLevel: 'built-in',
94
+ comment: 'The stock shader now adds a sheen lobe for cloth-like materials.'
95
+ },
96
+ KHR_materials_iridescence: {
97
+ supportLevel: 'built-in',
98
+ comment:
99
+ 'The stock shader now tints specular response with a view-dependent thin-film iridescence approximation.'
100
+ },
101
+ KHR_materials_anisotropy: {
102
+ supportLevel: 'built-in',
103
+ comment:
104
+ 'The stock shader now shapes highlights and IBL response with an anisotropy-direction approximation.'
105
+ },
106
+ KHR_materials_pbrSpecularGlossiness: {
107
+ supportLevel: 'loader-only',
108
+ comment:
109
+ 'Extension data can be loaded, but it is not translated into the default metallic-roughness material path.'
110
+ },
111
+ KHR_materials_variants: {
112
+ supportLevel: 'loader-only',
113
+ comment: 'Variant metadata can be loaded, but applications must choose and apply variants.'
114
+ },
115
+ EXT_mesh_gpu_instancing: {
116
+ supportLevel: 'none',
117
+ comment: 'GPU instancing data is not yet converted into luma.gl instanced draw setup.'
118
+ },
119
+ KHR_node_visibility: {
120
+ supportLevel: 'none',
121
+ comment: 'Node-visibility animations and toggles are not mapped onto runtime scenegraph state.'
122
+ },
123
+ KHR_animation_pointer: {
124
+ supportLevel: 'parsed-and-wired',
125
+ comment:
126
+ 'Selected node TRS, material factor, and KHR_texture_transform offset/rotation/scale pointers are wired to runtime updates; unsupported targets are skipped.'
127
+ },
128
+ KHR_materials_diffuse_transmission: {
129
+ supportLevel: 'none',
130
+ comment: 'Diffuse-transmission shading is not implemented in the stock PBR shader.'
131
+ },
132
+ KHR_materials_dispersion: {
133
+ supportLevel: 'none',
134
+ comment: 'Chromatic dispersion is not implemented in the stock PBR shader.'
135
+ },
136
+ KHR_materials_volume_scatter: {
137
+ supportLevel: 'none',
138
+ comment: 'Volume scattering is not implemented in the stock PBR shader.'
139
+ },
140
+ KHR_xmp: {
141
+ supportLevel: 'none',
142
+ comment: 'Metadata payloads remain in the loaded glTF, but luma.gl does not interpret them.'
143
+ },
144
+ KHR_xmp_json_ld: {
145
+ supportLevel: 'none',
146
+ comment: 'Metadata is preserved in the glTF, but luma.gl does not interpret it.'
147
+ },
148
+ EXT_lights_image_based: {
149
+ supportLevel: 'none',
150
+ comment: 'Use loadPBREnvironment() or custom environment setup instead.'
151
+ },
152
+ EXT_texture_video: {
153
+ supportLevel: 'none',
154
+ comment: 'Video textures are not created automatically by the stock pipeline.'
155
+ },
156
+ MSFT_lod: {
157
+ supportLevel: 'none',
158
+ comment: 'Level-of-detail switching is not implemented in the stock scenegraph loader.'
159
+ }
160
+ };
161
+
162
+ export function getGLTFExtensionSupport(
163
+ gltf: GLTFPostprocessed
164
+ ): Map<string, GLTFExtensionSupport> {
165
+ const extensionNames = Array.from(collectGLTFExtensionNames(gltf)).sort();
166
+ const extensionSupportEntries: [string, GLTFExtensionSupport][] = extensionNames.map(
167
+ extensionName => {
168
+ const extensionSupportDefinition =
169
+ GLTF_EXTENSION_SUPPORT_REGISTRY[extensionName] || UNKNOWN_EXTENSION_SUPPORT;
170
+
171
+ return [
172
+ extensionName,
173
+ {
174
+ extensionName,
175
+ supported:
176
+ extensionSupportDefinition.supportLevel === 'built-in' ||
177
+ extensionSupportDefinition.supportLevel === 'parsed-and-wired',
178
+ supportLevel: extensionSupportDefinition.supportLevel,
179
+ comment: extensionSupportDefinition.comment
180
+ }
181
+ ];
182
+ }
183
+ );
184
+
185
+ return new Map(extensionSupportEntries);
186
+ }
187
+
188
+ export function getRegisteredGLTFExtensionSupport(
189
+ extensionName: string
190
+ ): GLTFExtensionSupportDefinition | null {
191
+ return GLTF_EXTENSION_SUPPORT_REGISTRY[extensionName] || null;
192
+ }
193
+
194
+ function collectGLTFExtensionNames(gltf: GLTFPostprocessed): Set<string> {
195
+ const gltfWithRemovedExtensions = gltf as GLTFPostprocessedWithRemovedExtensions;
196
+ const extensionNames = new Set<string>();
197
+
198
+ addExtensionNames(extensionNames, gltf.extensionsUsed);
199
+ addExtensionNames(extensionNames, gltf.extensionsRequired);
200
+ addExtensionNames(extensionNames, gltfWithRemovedExtensions.extensionsRemoved);
201
+ addExtensionNames(extensionNames, Object.keys(gltf.extensions || {}));
202
+
203
+ if (
204
+ gltfWithRemovedExtensions.lights?.length ||
205
+ (gltf.nodes || []).some(node => 'light' in node)
206
+ ) {
207
+ extensionNames.add('KHR_lights_punctual');
208
+ }
209
+
210
+ if (
211
+ (gltf.materials || []).some(material => {
212
+ const gltfMaterial = material as typeof material & {unlit?: boolean};
213
+ return gltfMaterial.unlit || gltfMaterial.extensions?.KHR_materials_unlit;
214
+ })
215
+ ) {
216
+ extensionNames.add('KHR_materials_unlit');
217
+ }
218
+
219
+ return extensionNames;
220
+ }
221
+
222
+ function addExtensionNames(extensionNames: Set<string>, newExtensionNames: string[] = []): void {
223
+ for (const extensionName of newExtensionNames) {
224
+ extensionNames.add(extensionName);
225
+ }
226
+ }
package/src/index.ts CHANGED
@@ -3,8 +3,17 @@
3
3
  export {loadPBREnvironment, type PBREnvironment} from './pbr/pbr-environment';
4
4
  export {type ParsedPBRMaterial} from './pbr/pbr-material';
5
5
  export {parsePBRMaterial, type ParsePBRMaterialOptions} from './parsers/parse-pbr-material';
6
- export {} from './pbr/pbr-environment';
6
+ export {parseGLTFLights} from './parsers/parse-gltf-lights';
7
7
 
8
8
  // glTF Scenegraph Instantiator
9
- export {createScenegraphsFromGLTF} from './gltf/create-scenegraph-from-gltf';
9
+ export {
10
+ createScenegraphsFromGLTF,
11
+ type GLTFScenegraphBounds,
12
+ type GLTFScenegraphs
13
+ } from './gltf/create-scenegraph-from-gltf';
14
+ export {
15
+ getGLTFExtensionSupport,
16
+ type GLTFExtensionSupport,
17
+ type GLTFExtensionSupportLevel
18
+ } from './gltf/gltf-extension-support';
10
19
  export {GLTFAnimator} from './gltf/gltf-animator';