@luma.gl/gltf 9.3.0-alpha.9 → 9.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dist.dev.js +4396 -3081
- package/dist/dist.min.js +33 -14
- package/dist/gltf/animations/animations.d.ts +43 -3
- package/dist/gltf/animations/animations.d.ts.map +1 -1
- package/dist/gltf/animations/interpolate.d.ts +2 -0
- package/dist/gltf/animations/interpolate.d.ts.map +1 -1
- package/dist/gltf/animations/interpolate.js +27 -22
- package/dist/gltf/animations/interpolate.js.map +1 -1
- package/dist/gltf/create-gltf-model.d.ts.map +1 -1
- package/dist/gltf/create-gltf-model.js +29 -10
- package/dist/gltf/create-gltf-model.js.map +1 -1
- package/dist/gltf/create-scenegraph-from-gltf.js +2 -2
- package/dist/gltf/create-scenegraph-from-gltf.js.map +1 -1
- package/dist/gltf/gltf-animator.d.ts +12 -1
- package/dist/gltf/gltf-animator.d.ts.map +1 -1
- package/dist/gltf/gltf-animator.js +98 -6
- package/dist/gltf/gltf-animator.js.map +1 -1
- package/dist/gltf/gltf-extension-support.d.ts +3 -0
- package/dist/gltf/gltf-extension-support.d.ts.map +1 -1
- package/dist/gltf/gltf-extension-support.js +10 -5
- package/dist/gltf/gltf-extension-support.js.map +1 -1
- package/dist/index.cjs +763 -272
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/parsers/parse-gltf-animations.d.ts.map +1 -1
- package/dist/parsers/parse-gltf-animations.js +319 -18
- package/dist/parsers/parse-gltf-animations.js.map +1 -1
- package/dist/parsers/parse-gltf-lights.d.ts +6 -2
- package/dist/parsers/parse-gltf-lights.d.ts.map +1 -1
- package/dist/parsers/parse-gltf-lights.js +9 -6
- package/dist/parsers/parse-gltf-lights.js.map +1 -1
- package/dist/parsers/parse-gltf.d.ts +2 -0
- package/dist/parsers/parse-gltf.d.ts.map +1 -1
- package/dist/parsers/parse-gltf.js +21 -7
- package/dist/parsers/parse-gltf.js.map +1 -1
- package/dist/parsers/parse-pbr-material.d.ts.map +1 -1
- package/dist/parsers/parse-pbr-material.js +114 -81
- package/dist/parsers/parse-pbr-material.js.map +1 -1
- package/dist/pbr/pbr-environment.d.ts.map +1 -1
- package/dist/pbr/pbr-environment.js +7 -3
- package/dist/pbr/pbr-environment.js.map +1 -1
- package/dist/pbr/texture-transform.d.ts +24 -0
- package/dist/pbr/texture-transform.d.ts.map +1 -0
- package/dist/pbr/texture-transform.js +98 -0
- package/dist/pbr/texture-transform.js.map +1 -0
- package/dist/webgl-to-webgpu/convert-webgl-topology.js +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-topology.js.map +1 -1
- package/package.json +5 -5
- package/src/gltf/animations/animations.ts +73 -3
- package/src/gltf/animations/interpolate.ts +50 -43
- package/src/gltf/create-gltf-model.ts +29 -10
- package/src/gltf/create-scenegraph-from-gltf.ts +2 -2
- package/src/gltf/gltf-animator.ts +177 -8
- package/src/gltf/gltf-extension-support.ts +17 -5
- package/src/index.ts +1 -1
- package/src/parsers/parse-gltf-animations.ts +461 -21
- package/src/parsers/parse-gltf-lights.ts +27 -8
- package/src/parsers/parse-gltf.ts +23 -7
- package/src/parsers/parse-pbr-material.ts +184 -79
- package/src/pbr/pbr-environment.ts +10 -3
- package/src/pbr/texture-transform.ts +263 -0
- package/src/webgl-to-webgpu/convert-webgl-topology.ts +1 -1
|
@@ -3,9 +3,20 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import {log} from '@luma.gl/core';
|
|
6
|
-
import {GroupNode} from '@luma.gl/engine';
|
|
7
|
-
import {
|
|
8
|
-
|
|
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';
|
|
9
20
|
|
|
10
21
|
/** Construction props for a single glTF animation controller. */
|
|
11
22
|
type GLTFSingleAnimatorProps = {
|
|
@@ -13,6 +24,8 @@ type GLTFSingleAnimatorProps = {
|
|
|
13
24
|
animation: GLTFAnimation;
|
|
14
25
|
/** Mapping from glTF node ids to scenegraph nodes. */
|
|
15
26
|
gltfNodeIdToNodeMap: Map<string, GroupNode>;
|
|
27
|
+
/** Materials aligned with the source glTF materials array. */
|
|
28
|
+
materials?: Material[];
|
|
16
29
|
/** Start time in seconds. */
|
|
17
30
|
startTime?: number;
|
|
18
31
|
/** Whether playback is active. */
|
|
@@ -27,19 +40,36 @@ class GLTFSingleAnimator {
|
|
|
27
40
|
animation: GLTFAnimation;
|
|
28
41
|
/** Target scenegraph lookup table. */
|
|
29
42
|
gltfNodeIdToNodeMap: Map<string, GroupNode>;
|
|
43
|
+
/** Materials aligned with the source glTF materials array. */
|
|
44
|
+
materials: Material[];
|
|
30
45
|
/** Playback start time in seconds. */
|
|
31
46
|
startTime: number = 0;
|
|
32
47
|
/** Whether playback is currently enabled. */
|
|
33
48
|
playing: boolean = true;
|
|
34
49
|
/** Playback speed multiplier. */
|
|
35
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
|
+
>();
|
|
36
56
|
|
|
37
57
|
/** Creates a single-animation controller. */
|
|
38
58
|
constructor(props: GLTFSingleAnimatorProps) {
|
|
39
59
|
this.animation = props.animation;
|
|
40
60
|
this.gltfNodeIdToNodeMap = props.gltfNodeIdToNodeMap;
|
|
61
|
+
this.materials = props.materials || [];
|
|
41
62
|
this.animation.name ||= 'unnamed';
|
|
42
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
|
+
}
|
|
43
73
|
}
|
|
44
74
|
|
|
45
75
|
/** Advances the animation to the supplied wall-clock time in milliseconds. */
|
|
@@ -51,13 +81,38 @@ class GLTFSingleAnimator {
|
|
|
51
81
|
const absTime = timeMs / 1000;
|
|
52
82
|
const time = (absTime - this.startTime) * this.speed;
|
|
53
83
|
|
|
54
|
-
this.animation.channels.forEach(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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;
|
|
58
94
|
}
|
|
59
95
|
|
|
60
|
-
|
|
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
|
+
}
|
|
61
116
|
});
|
|
62
117
|
}
|
|
63
118
|
}
|
|
@@ -68,6 +123,8 @@ export type GLTFAnimatorProps = {
|
|
|
68
123
|
animations: GLTFAnimation[];
|
|
69
124
|
/** Mapping from glTF node ids to scenegraph nodes. */
|
|
70
125
|
gltfNodeIdToNodeMap: Map<string, GroupNode>;
|
|
126
|
+
/** Materials aligned with the source glTF materials array. */
|
|
127
|
+
materials?: Material[];
|
|
71
128
|
};
|
|
72
129
|
|
|
73
130
|
/** Coordinates playback of every animation found in a glTF scene. */
|
|
@@ -81,6 +138,7 @@ export class GLTFAnimator {
|
|
|
81
138
|
const name = animation.name || `Animation-${index}`;
|
|
82
139
|
return new GLTFSingleAnimator({
|
|
83
140
|
gltfNodeIdToNodeMap: props.gltfNodeIdToNodeMap,
|
|
141
|
+
materials: props.materials,
|
|
84
142
|
animation: {name, channels: animation.channels}
|
|
85
143
|
});
|
|
86
144
|
});
|
|
@@ -102,3 +160,114 @@ export class GLTFAnimator {
|
|
|
102
160
|
return this.animations;
|
|
103
161
|
}
|
|
104
162
|
}
|
|
163
|
+
|
|
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
|
+
};
|
|
181
|
+
|
|
182
|
+
material.setProps({pbrMaterial});
|
|
183
|
+
}
|
|
184
|
+
|
|
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
|
+
}
|
|
193
|
+
|
|
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;
|
|
240
|
+
}
|
|
241
|
+
|
|
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);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return textureTransformState;
|
|
273
|
+
}
|
|
@@ -121,8 +121,9 @@ const GLTF_EXTENSION_SUPPORT_REGISTRY: Record<string, GLTFExtensionSupportDefini
|
|
|
121
121
|
comment: 'Node-visibility animations and toggles are not mapped onto runtime scenegraph state.'
|
|
122
122
|
},
|
|
123
123
|
KHR_animation_pointer: {
|
|
124
|
-
supportLevel: '
|
|
125
|
-
comment:
|
|
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.'
|
|
126
127
|
},
|
|
127
128
|
KHR_materials_diffuse_transmission: {
|
|
128
129
|
supportLevel: 'none',
|
|
@@ -171,7 +172,9 @@ export function getGLTFExtensionSupport(
|
|
|
171
172
|
extensionName,
|
|
172
173
|
{
|
|
173
174
|
extensionName,
|
|
174
|
-
supported:
|
|
175
|
+
supported:
|
|
176
|
+
extensionSupportDefinition.supportLevel === 'built-in' ||
|
|
177
|
+
extensionSupportDefinition.supportLevel === 'parsed-and-wired',
|
|
175
178
|
supportLevel: extensionSupportDefinition.supportLevel,
|
|
176
179
|
comment: extensionSupportDefinition.comment
|
|
177
180
|
}
|
|
@@ -182,6 +185,12 @@ export function getGLTFExtensionSupport(
|
|
|
182
185
|
return new Map(extensionSupportEntries);
|
|
183
186
|
}
|
|
184
187
|
|
|
188
|
+
export function getRegisteredGLTFExtensionSupport(
|
|
189
|
+
extensionName: string
|
|
190
|
+
): GLTFExtensionSupportDefinition | null {
|
|
191
|
+
return GLTF_EXTENSION_SUPPORT_REGISTRY[extensionName] || null;
|
|
192
|
+
}
|
|
193
|
+
|
|
185
194
|
function collectGLTFExtensionNames(gltf: GLTFPostprocessed): Set<string> {
|
|
186
195
|
const gltfWithRemovedExtensions = gltf as GLTFPostprocessedWithRemovedExtensions;
|
|
187
196
|
const extensionNames = new Set<string>();
|
|
@@ -191,12 +200,15 @@ function collectGLTFExtensionNames(gltf: GLTFPostprocessed): Set<string> {
|
|
|
191
200
|
addExtensionNames(extensionNames, gltfWithRemovedExtensions.extensionsRemoved);
|
|
192
201
|
addExtensionNames(extensionNames, Object.keys(gltf.extensions || {}));
|
|
193
202
|
|
|
194
|
-
if (
|
|
203
|
+
if (
|
|
204
|
+
gltfWithRemovedExtensions.lights?.length ||
|
|
205
|
+
(gltf.nodes || []).some(node => 'light' in node)
|
|
206
|
+
) {
|
|
195
207
|
extensionNames.add('KHR_lights_punctual');
|
|
196
208
|
}
|
|
197
209
|
|
|
198
210
|
if (
|
|
199
|
-
gltf.materials.some(material => {
|
|
211
|
+
(gltf.materials || []).some(material => {
|
|
200
212
|
const gltfMaterial = material as typeof material & {unlit?: boolean};
|
|
201
213
|
return gltfMaterial.unlit || gltfMaterial.extensions?.KHR_materials_unlit;
|
|
202
214
|
})
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
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 {parseGLTFLights} from './parsers/parse-gltf-lights';
|
|
6
|
+
export {parseGLTFLights, type ParseGLTFLightsOptions} from './parsers/parse-gltf-lights';
|
|
7
7
|
|
|
8
8
|
// glTF Scenegraph Instantiator
|
|
9
9
|
export {
|