@luma.gl/gltf 9.0.0-alpha.43
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/LICENSE +34 -0
- package/README.md +3 -0
- package/dist/dist.dev.js +15822 -0
- package/dist/gltf/create-gltf-model.d.ts +13 -0
- package/dist/gltf/create-gltf-model.d.ts.map +1 -0
- package/dist/gltf/create-gltf-model.js +105 -0
- package/dist/gltf/create-gltf-model.js.map +1 -0
- package/dist/gltf/create-gltf-objects.d.ts +9 -0
- package/dist/gltf/create-gltf-objects.d.ts.map +1 -0
- package/dist/gltf/create-gltf-objects.js +11 -0
- package/dist/gltf/create-gltf-objects.js.map +1 -0
- package/dist/gltf/gltf-animator.d.ts +35 -0
- package/dist/gltf/gltf-animator.d.ts.map +1 -0
- package/dist/gltf/gltf-animator.js +223 -0
- package/dist/gltf/gltf-animator.js.map +1 -0
- package/dist/gltf/gltf-instantiator.d.ts +45 -0
- package/dist/gltf/gltf-instantiator.d.ts.map +1 -0
- package/dist/gltf/gltf-instantiator.js +180 -0
- package/dist/gltf/gltf-instantiator.js.map +1 -0
- package/dist/index.cjs +635 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/pbr/parse-pbr-material.d.ts +26 -0
- package/dist/pbr/parse-pbr-material.d.ts.map +1 -0
- package/dist/pbr/parse-pbr-material.js +137 -0
- package/dist/pbr/parse-pbr-material.js.map +1 -0
- package/dist/pbr/pbr-environment.d.ts +18 -0
- package/dist/pbr/pbr-environment.d.ts.map +1 -0
- package/dist/pbr/pbr-environment.js +64 -0
- package/dist/pbr/pbr-environment.js.map +1 -0
- package/dist.min.js +1253 -0
- package/package.json +53 -0
- package/src/gltf/create-gltf-model.ts +120 -0
- package/src/gltf/create-gltf-objects.ts +18 -0
- package/src/gltf/gltf-animator.ts +223 -0
- package/src/gltf/gltf-instantiator.ts +225 -0
- package/src/index.ts +10 -0
- package/src/pbr/parse-pbr-material.ts +398 -0
- package/src/pbr/pbr-environment.ts +88 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
22
|
+
};
|
|
23
|
+
var __copyProps = (to, from, except, desc) => {
|
|
24
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
25
|
+
for (let key of __getOwnPropNames(from))
|
|
26
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
27
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
28
|
+
}
|
|
29
|
+
return to;
|
|
30
|
+
};
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// src/index.ts
|
|
34
|
+
var src_exports = {};
|
|
35
|
+
__export(src_exports, {
|
|
36
|
+
GLTFAnimator: () => GLTFAnimator,
|
|
37
|
+
createScenegraphsFromGLTF: () => createScenegraphsFromGLTF,
|
|
38
|
+
parsePBRMaterial: () => parsePBRMaterial
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(src_exports);
|
|
41
|
+
|
|
42
|
+
// src/pbr/parse-pbr-material.ts
|
|
43
|
+
var import_core = require("@luma.gl/core");
|
|
44
|
+
var import_constants = require("@luma.gl/constants");
|
|
45
|
+
function parsePBRMaterial(device, material, attributes, options) {
|
|
46
|
+
const parsedMaterial = {
|
|
47
|
+
defines: {
|
|
48
|
+
// TODO: Use EXT_sRGB if available (Standard in WebGL 2.0)
|
|
49
|
+
MANUAL_SRGB: 1,
|
|
50
|
+
SRGB_FAST_APPROXIMATION: 1
|
|
51
|
+
},
|
|
52
|
+
bindings: {},
|
|
53
|
+
uniforms: {
|
|
54
|
+
// TODO: find better values?
|
|
55
|
+
u_Camera: [0, 0, 0],
|
|
56
|
+
// Model should override
|
|
57
|
+
u_MetallicRoughnessValues: [1, 1]
|
|
58
|
+
// Default is 1 and 1
|
|
59
|
+
},
|
|
60
|
+
parameters: {},
|
|
61
|
+
glParameters: {},
|
|
62
|
+
generatedTextures: []
|
|
63
|
+
};
|
|
64
|
+
if (device.features.has("glsl-texture-lod")) {
|
|
65
|
+
parsedMaterial.defines.USE_TEX_LOD = 1;
|
|
66
|
+
}
|
|
67
|
+
const { imageBasedLightingEnvironment } = options;
|
|
68
|
+
if (imageBasedLightingEnvironment) {
|
|
69
|
+
parsedMaterial.bindings.u_DiffuseEnvSampler = imageBasedLightingEnvironment.diffuseEnvSampler;
|
|
70
|
+
parsedMaterial.bindings.u_SpecularEnvSampler = imageBasedLightingEnvironment.specularEnvSampler;
|
|
71
|
+
parsedMaterial.bindings.u_brdfLUT = imageBasedLightingEnvironment.brdfLutTexture;
|
|
72
|
+
parsedMaterial.uniforms.u_ScaleIBLAmbient = [1, 1];
|
|
73
|
+
}
|
|
74
|
+
if (options == null ? void 0 : options.pbrDebug) {
|
|
75
|
+
parsedMaterial.defines.PBR_DEBUG = 1;
|
|
76
|
+
parsedMaterial.uniforms.u_ScaleDiffBaseMR = [0, 0, 0, 0];
|
|
77
|
+
parsedMaterial.uniforms.u_ScaleFGDSpec = [0, 0, 0, 0];
|
|
78
|
+
}
|
|
79
|
+
if (attributes.NORMAL)
|
|
80
|
+
parsedMaterial.defines.HAS_NORMALS = 1;
|
|
81
|
+
if (attributes.TANGENT && (options == null ? void 0 : options.useTangents))
|
|
82
|
+
parsedMaterial.defines.HAS_TANGENTS = 1;
|
|
83
|
+
if (attributes.TEXCOORD_0)
|
|
84
|
+
parsedMaterial.defines.HAS_UV = 1;
|
|
85
|
+
if (options == null ? void 0 : options.imageBasedLightingEnvironment)
|
|
86
|
+
parsedMaterial.defines.USE_IBL = 1;
|
|
87
|
+
if (options == null ? void 0 : options.lights)
|
|
88
|
+
parsedMaterial.defines.USE_LIGHTS = 1;
|
|
89
|
+
if (material) {
|
|
90
|
+
parseMaterial(device, material, parsedMaterial);
|
|
91
|
+
}
|
|
92
|
+
return parsedMaterial;
|
|
93
|
+
}
|
|
94
|
+
function parseMaterial(device, material, parsedMaterial) {
|
|
95
|
+
parsedMaterial.uniforms.pbr_uUnlit = Boolean(material.unlit);
|
|
96
|
+
if (material.pbrMetallicRoughness) {
|
|
97
|
+
parsePbrMetallicRoughness(device, material.pbrMetallicRoughness, parsedMaterial);
|
|
98
|
+
}
|
|
99
|
+
if (material.normalTexture) {
|
|
100
|
+
addTexture(device, material.normalTexture, "u_NormalSampler", "HAS_NORMALMAP", parsedMaterial);
|
|
101
|
+
const { scale = 1 } = material.normalTexture;
|
|
102
|
+
parsedMaterial.uniforms.u_NormalScale = scale;
|
|
103
|
+
}
|
|
104
|
+
if (material.occlusionTexture) {
|
|
105
|
+
addTexture(
|
|
106
|
+
device,
|
|
107
|
+
material.occlusionTexture,
|
|
108
|
+
"u_OcclusionSampler",
|
|
109
|
+
"HAS_OCCLUSIONMAP",
|
|
110
|
+
parsedMaterial
|
|
111
|
+
);
|
|
112
|
+
const { strength = 1 } = material.occlusionTexture;
|
|
113
|
+
parsedMaterial.uniforms.u_OcclusionStrength = strength;
|
|
114
|
+
}
|
|
115
|
+
if (material.emissiveTexture) {
|
|
116
|
+
addTexture(
|
|
117
|
+
device,
|
|
118
|
+
material.emissiveTexture,
|
|
119
|
+
"u_EmissiveSampler",
|
|
120
|
+
"HAS_EMISSIVEMAP",
|
|
121
|
+
parsedMaterial
|
|
122
|
+
);
|
|
123
|
+
parsedMaterial.uniforms.u_EmissiveFactor = material.emissiveFactor || [0, 0, 0];
|
|
124
|
+
}
|
|
125
|
+
switch (material.alphaMode) {
|
|
126
|
+
case "MASK":
|
|
127
|
+
const { alphaCutoff = 0.5 } = material;
|
|
128
|
+
parsedMaterial.defines.ALPHA_CUTOFF = 1;
|
|
129
|
+
parsedMaterial.uniforms.u_AlphaCutoff = alphaCutoff;
|
|
130
|
+
break;
|
|
131
|
+
case "BLEND":
|
|
132
|
+
import_core.log.warn("glTF BLEND alphaMode might not work well because it requires mesh sorting")();
|
|
133
|
+
parsedMaterial.parameters.blendColorOperation = "add";
|
|
134
|
+
parsedMaterial.parameters.blendColorSrcFactor = "src-alpha";
|
|
135
|
+
parsedMaterial.parameters.blendColorDstFactor = "one-minus-src-alpha";
|
|
136
|
+
parsedMaterial.parameters.blendAlphaOperation = "add";
|
|
137
|
+
parsedMaterial.parameters.blendAlphaSrcFactor = "one";
|
|
138
|
+
parsedMaterial.parameters.blendAlphaDstFactor = "one-minus-src-alpha";
|
|
139
|
+
parsedMaterial.glParameters.blend = true;
|
|
140
|
+
parsedMaterial.glParameters.blendEquation = import_constants.GL.FUNC_ADD;
|
|
141
|
+
parsedMaterial.glParameters.blendFunc = [import_constants.GL.SRC_ALPHA, import_constants.GL.ONE_MINUS_SRC_ALPHA, import_constants.GL.ONE, import_constants.GL.ONE_MINUS_SRC_ALPHA];
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function parsePbrMetallicRoughness(device, pbrMetallicRoughness, parsedMaterial) {
|
|
146
|
+
if (pbrMetallicRoughness.baseColorTexture) {
|
|
147
|
+
addTexture(
|
|
148
|
+
device,
|
|
149
|
+
pbrMetallicRoughness.baseColorTexture,
|
|
150
|
+
"u_BaseColorSampler",
|
|
151
|
+
"HAS_BASECOLORMAP",
|
|
152
|
+
parsedMaterial
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
parsedMaterial.uniforms.u_BaseColorFactor = pbrMetallicRoughness.baseColorFactor || [1, 1, 1, 1];
|
|
156
|
+
if (pbrMetallicRoughness.metallicRoughnessTexture) {
|
|
157
|
+
addTexture(
|
|
158
|
+
device,
|
|
159
|
+
pbrMetallicRoughness.metallicRoughnessTexture,
|
|
160
|
+
"u_MetallicRoughnessSampler",
|
|
161
|
+
"HAS_METALROUGHNESSMAP",
|
|
162
|
+
parsedMaterial
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
const { metallicFactor = 1, roughnessFactor = 1 } = pbrMetallicRoughness;
|
|
166
|
+
parsedMaterial.uniforms.u_MetallicRoughnessValues = [metallicFactor, roughnessFactor];
|
|
167
|
+
}
|
|
168
|
+
function addTexture(device, gltfTexture, uniformName, define = null, parsedMaterial) {
|
|
169
|
+
var _a, _b;
|
|
170
|
+
const parameters = ((_b = (_a = gltfTexture == null ? void 0 : gltfTexture.texture) == null ? void 0 : _a.sampler) == null ? void 0 : _b.parameters) || {};
|
|
171
|
+
const image = gltfTexture.texture.source.image;
|
|
172
|
+
let textureOptions;
|
|
173
|
+
let specialTextureParameters = {};
|
|
174
|
+
if (image.compressed) {
|
|
175
|
+
textureOptions = image;
|
|
176
|
+
specialTextureParameters = {
|
|
177
|
+
[import_constants.GL.TEXTURE_MIN_FILTER]: image.data.length > 1 ? import_constants.GL.LINEAR_MIPMAP_NEAREST : import_constants.GL.LINEAR
|
|
178
|
+
};
|
|
179
|
+
} else {
|
|
180
|
+
textureOptions = { data: image };
|
|
181
|
+
}
|
|
182
|
+
const texture = device.createTexture(__spreadValues({
|
|
183
|
+
id: gltfTexture.uniformName || gltfTexture.id,
|
|
184
|
+
parameters: __spreadValues(__spreadValues({}, parameters), specialTextureParameters),
|
|
185
|
+
pixelStore: {
|
|
186
|
+
[import_constants.GL.UNPACK_FLIP_Y_WEBGL]: false
|
|
187
|
+
}
|
|
188
|
+
}, textureOptions));
|
|
189
|
+
parsedMaterial.bindings[uniformName] = texture;
|
|
190
|
+
if (define)
|
|
191
|
+
parsedMaterial.defines[define] = 1;
|
|
192
|
+
parsedMaterial.generatedTextures.push(texture);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/gltf/gltf-instantiator.ts
|
|
196
|
+
var import_engine2 = require("@luma.gl/engine");
|
|
197
|
+
var import_webgl = require("@luma.gl/webgl");
|
|
198
|
+
var import_core5 = require("@math.gl/core");
|
|
199
|
+
|
|
200
|
+
// src/gltf/gltf-animator.ts
|
|
201
|
+
var import_core2 = require("@luma.gl/core");
|
|
202
|
+
var import_core3 = require("@math.gl/core");
|
|
203
|
+
var ATTRIBUTE_TYPE_TO_COMPONENTS = {
|
|
204
|
+
SCALAR: 1,
|
|
205
|
+
VEC2: 2,
|
|
206
|
+
VEC3: 3,
|
|
207
|
+
VEC4: 4,
|
|
208
|
+
MAT2: 4,
|
|
209
|
+
MAT3: 9,
|
|
210
|
+
MAT4: 16
|
|
211
|
+
};
|
|
212
|
+
var ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY = {
|
|
213
|
+
5120: Int8Array,
|
|
214
|
+
5121: Uint8Array,
|
|
215
|
+
5122: Int16Array,
|
|
216
|
+
5123: Uint16Array,
|
|
217
|
+
5125: Uint32Array,
|
|
218
|
+
5126: Float32Array
|
|
219
|
+
};
|
|
220
|
+
var GLTFAnimation = class {
|
|
221
|
+
constructor(props) {
|
|
222
|
+
this.startTime = 0;
|
|
223
|
+
this.playing = true;
|
|
224
|
+
this.speed = 1;
|
|
225
|
+
this.channels = [];
|
|
226
|
+
Object.assign(this, props);
|
|
227
|
+
}
|
|
228
|
+
animate(timeMs) {
|
|
229
|
+
if (!this.playing) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const absTime = timeMs / 1e3;
|
|
233
|
+
const time = (absTime - this.startTime) * this.speed;
|
|
234
|
+
this.channels.forEach(({ sampler, target, path }) => {
|
|
235
|
+
interpolate(time, sampler, target, path);
|
|
236
|
+
applyTranslationRotationScale(target, target._node);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
var GLTFAnimator = class {
|
|
241
|
+
constructor(gltf) {
|
|
242
|
+
this.animations = gltf.animations.map((animation, index) => {
|
|
243
|
+
const name = animation.name || `Animation-${index}`;
|
|
244
|
+
const samplers = animation.samplers.map(({ input, interpolation = "LINEAR", output }) => ({
|
|
245
|
+
input: accessorToJsArray(gltf.accessors[input]),
|
|
246
|
+
interpolation,
|
|
247
|
+
output: accessorToJsArray(gltf.accessors[output])
|
|
248
|
+
}));
|
|
249
|
+
const channels = animation.channels.map(({ sampler, target }) => ({
|
|
250
|
+
sampler: samplers[sampler],
|
|
251
|
+
target: gltf.nodes[target.node],
|
|
252
|
+
path: target.path
|
|
253
|
+
}));
|
|
254
|
+
return new GLTFAnimation({ name, channels });
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/** @deprecated Use .setTime(). Will be removed (deck.gl is using this) */
|
|
258
|
+
animate(time) {
|
|
259
|
+
this.setTime(time);
|
|
260
|
+
}
|
|
261
|
+
setTime(time) {
|
|
262
|
+
this.animations.forEach((animation) => animation.animate(time));
|
|
263
|
+
}
|
|
264
|
+
getAnimations() {
|
|
265
|
+
return this.animations;
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
function accessorToJsArray(accessor) {
|
|
269
|
+
if (!accessor._animation) {
|
|
270
|
+
const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[accessor.componentType];
|
|
271
|
+
const components = ATTRIBUTE_TYPE_TO_COMPONENTS[accessor.type];
|
|
272
|
+
const length = components * accessor.count;
|
|
273
|
+
const { buffer, byteOffset } = accessor.bufferView.data;
|
|
274
|
+
const array = new ArrayType(buffer, byteOffset + (accessor.byteOffset || 0), length);
|
|
275
|
+
if (components === 1) {
|
|
276
|
+
accessor._animation = Array.from(array);
|
|
277
|
+
} else {
|
|
278
|
+
const slicedArray = [];
|
|
279
|
+
for (let i = 0; i < array.length; i += components) {
|
|
280
|
+
slicedArray.push(Array.from(array.slice(i, i + components)));
|
|
281
|
+
}
|
|
282
|
+
accessor._animation = slicedArray;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return accessor._animation;
|
|
286
|
+
}
|
|
287
|
+
var helperMatrix = new import_core3.Matrix4();
|
|
288
|
+
function applyTranslationRotationScale(gltfNode, node) {
|
|
289
|
+
node.matrix.identity();
|
|
290
|
+
if (gltfNode.translation) {
|
|
291
|
+
node.matrix.translate(gltfNode.translation);
|
|
292
|
+
}
|
|
293
|
+
if (gltfNode.rotation) {
|
|
294
|
+
const rotationMatrix = helperMatrix.fromQuaternion(gltfNode.rotation);
|
|
295
|
+
node.matrix.multiplyRight(rotationMatrix);
|
|
296
|
+
}
|
|
297
|
+
if (gltfNode.scale) {
|
|
298
|
+
node.matrix.scale(gltfNode.scale);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
var quaternion = new import_core3.Quaternion();
|
|
302
|
+
function linearInterpolate(target, path, start, stop, ratio) {
|
|
303
|
+
if (path === "rotation") {
|
|
304
|
+
quaternion.slerp({ start, target: stop, ratio });
|
|
305
|
+
for (let i = 0; i < quaternion.length; i++) {
|
|
306
|
+
target[path][i] = quaternion[i];
|
|
307
|
+
}
|
|
308
|
+
} else {
|
|
309
|
+
for (let i = 0; i < start.length; i++) {
|
|
310
|
+
target[path][i] = ratio * stop[i] + (1 - ratio) * start[i];
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function cubicsplineInterpolate(target, path, { p0, outTangent0, inTangent1, p1, tDiff, ratio: t }) {
|
|
315
|
+
for (let i = 0; i < target[path].length; i++) {
|
|
316
|
+
const m0 = outTangent0[i] * tDiff;
|
|
317
|
+
const m1 = inTangent1[i] * tDiff;
|
|
318
|
+
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;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function stepInterpolate(target, path, value) {
|
|
322
|
+
for (let i = 0; i < value.length; i++) {
|
|
323
|
+
target[path][i] = value[i];
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
function interpolate(time, { input, interpolation, output }, target, path) {
|
|
327
|
+
const maxTime = input[input.length - 1];
|
|
328
|
+
const animationTime = time % maxTime;
|
|
329
|
+
const nextIndex = input.findIndex((t) => t >= animationTime);
|
|
330
|
+
const previousIndex = Math.max(0, nextIndex - 1);
|
|
331
|
+
if (!Array.isArray(target[path])) {
|
|
332
|
+
switch (path) {
|
|
333
|
+
case "translation":
|
|
334
|
+
target[path] = [0, 0, 0];
|
|
335
|
+
break;
|
|
336
|
+
case "rotation":
|
|
337
|
+
target[path] = [0, 0, 0, 1];
|
|
338
|
+
break;
|
|
339
|
+
case "scale":
|
|
340
|
+
target[path] = [1, 1, 1];
|
|
341
|
+
break;
|
|
342
|
+
default:
|
|
343
|
+
import_core2.log.warn(`Bad animation path ${path}`)();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
(0, import_core2.assert)(target[path].length === output[previousIndex].length);
|
|
347
|
+
const previousTime = input[previousIndex];
|
|
348
|
+
const nextTime = input[nextIndex];
|
|
349
|
+
switch (interpolation) {
|
|
350
|
+
case "STEP":
|
|
351
|
+
stepInterpolate(target, path, output[previousIndex]);
|
|
352
|
+
break;
|
|
353
|
+
case "LINEAR":
|
|
354
|
+
if (nextTime > previousTime) {
|
|
355
|
+
const ratio = (animationTime - previousTime) / (nextTime - previousTime);
|
|
356
|
+
linearInterpolate(target, path, output[previousIndex], output[nextIndex], ratio);
|
|
357
|
+
}
|
|
358
|
+
break;
|
|
359
|
+
case "CUBICSPLINE":
|
|
360
|
+
if (nextTime > previousTime) {
|
|
361
|
+
const ratio = (animationTime - previousTime) / (nextTime - previousTime);
|
|
362
|
+
const tDiff = nextTime - previousTime;
|
|
363
|
+
const p0 = output[3 * previousIndex + 1];
|
|
364
|
+
const outTangent0 = output[3 * previousIndex + 2];
|
|
365
|
+
const inTangent1 = output[3 * nextIndex + 0];
|
|
366
|
+
const p1 = output[3 * nextIndex + 1];
|
|
367
|
+
cubicsplineInterpolate(target, path, { p0, outTangent0, inTangent1, p1, tDiff, ratio });
|
|
368
|
+
}
|
|
369
|
+
break;
|
|
370
|
+
default:
|
|
371
|
+
import_core2.log.warn(`Interpolation ${interpolation} not supported`)();
|
|
372
|
+
break;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// src/gltf/create-gltf-model.ts
|
|
377
|
+
var import_core4 = require("@luma.gl/core");
|
|
378
|
+
var import_shadertools = require("@luma.gl/shadertools");
|
|
379
|
+
var import_engine = require("@luma.gl/engine");
|
|
380
|
+
var vs = `
|
|
381
|
+
#pragma vscode_glsllint_stage: vert
|
|
382
|
+
#if (__VERSION__ < 300)
|
|
383
|
+
#define _attr attribute
|
|
384
|
+
#else
|
|
385
|
+
#define _attr in
|
|
386
|
+
#endif
|
|
387
|
+
|
|
388
|
+
// _attr vec4 POSITION;
|
|
389
|
+
_attr vec4 positions;
|
|
390
|
+
|
|
391
|
+
#ifdef HAS_NORMALS
|
|
392
|
+
// _attr vec4 NORMAL;
|
|
393
|
+
_attr vec4 normals;
|
|
394
|
+
#endif
|
|
395
|
+
|
|
396
|
+
#ifdef HAS_TANGENTS
|
|
397
|
+
_attr vec4 TANGENT;
|
|
398
|
+
#endif
|
|
399
|
+
|
|
400
|
+
#ifdef HAS_UV
|
|
401
|
+
// _attr vec2 TEXCOORD_0;
|
|
402
|
+
_attr vec2 texCoords;
|
|
403
|
+
#endif
|
|
404
|
+
|
|
405
|
+
void main(void) {
|
|
406
|
+
vec4 _NORMAL = vec4(0.);
|
|
407
|
+
vec4 _TANGENT = vec4(0.);
|
|
408
|
+
vec2 _TEXCOORD_0 = vec2(0.);
|
|
409
|
+
|
|
410
|
+
#ifdef HAS_NORMALS
|
|
411
|
+
_NORMAL = normals;
|
|
412
|
+
#endif
|
|
413
|
+
|
|
414
|
+
#ifdef HAS_TANGENTS
|
|
415
|
+
_TANGENT = TANGENT;
|
|
416
|
+
#endif
|
|
417
|
+
|
|
418
|
+
#ifdef HAS_UV
|
|
419
|
+
_TEXCOORD_0 = texCoords;
|
|
420
|
+
#endif
|
|
421
|
+
|
|
422
|
+
pbr_setPositionNormalTangentUV(positions, _NORMAL, _TANGENT, _TEXCOORD_0);
|
|
423
|
+
gl_Position = u_MVPMatrix * positions;
|
|
424
|
+
}
|
|
425
|
+
`;
|
|
426
|
+
var fs = `
|
|
427
|
+
#pragma vscode_glsllint_stage: frag
|
|
428
|
+
#if (__VERSION__ < 300)
|
|
429
|
+
#define fragmentColor gl_FragColor
|
|
430
|
+
#else
|
|
431
|
+
out vec4 fragmentColor;
|
|
432
|
+
#endif
|
|
433
|
+
|
|
434
|
+
void main(void) {
|
|
435
|
+
vec3 pos = pbr_vPosition;
|
|
436
|
+
fragmentColor = pbr_filterColor(vec4(1.0));
|
|
437
|
+
}
|
|
438
|
+
`;
|
|
439
|
+
function createGLTFModel(device, options) {
|
|
440
|
+
const { id, geometry, material, vertexCount, materialOptions, modelOptions } = options;
|
|
441
|
+
const parsedMaterial = parsePBRMaterial(device, material, geometry.attributes, materialOptions);
|
|
442
|
+
import_core4.log.info(4, "createGLTFModel defines: ", parsedMaterial.defines)();
|
|
443
|
+
const managedResources = [];
|
|
444
|
+
const parameters = {
|
|
445
|
+
depthWriteEnabled: true,
|
|
446
|
+
depthCompare: "less",
|
|
447
|
+
depthFormat: "depth24plus",
|
|
448
|
+
cullMode: "back"
|
|
449
|
+
};
|
|
450
|
+
const modelProps = __spreadValues({
|
|
451
|
+
id,
|
|
452
|
+
geometry,
|
|
453
|
+
topology: geometry.topology,
|
|
454
|
+
vertexCount,
|
|
455
|
+
modules: [import_shadertools.pbr],
|
|
456
|
+
defines: parsedMaterial.defines,
|
|
457
|
+
// parameters: parsedMaterial.parameters,
|
|
458
|
+
parameters,
|
|
459
|
+
// TODO use/merge parsedMaterial
|
|
460
|
+
vs: addVersionToShader(device, vs),
|
|
461
|
+
fs: addVersionToShader(device, fs),
|
|
462
|
+
bindings: parsedMaterial.bindings,
|
|
463
|
+
uniforms: parsedMaterial.uniforms
|
|
464
|
+
}, modelOptions);
|
|
465
|
+
const model = new import_engine.Model(device, modelProps);
|
|
466
|
+
return new import_engine.ModelNode({ managedResources, model });
|
|
467
|
+
}
|
|
468
|
+
function addVersionToShader(device, source) {
|
|
469
|
+
return device.info.type === "webgl2" ? `#version 300 es
|
|
470
|
+
${source}` : source;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/gltf/gltf-instantiator.ts
|
|
474
|
+
var DEFAULT_OPTIONS = {
|
|
475
|
+
modelOptions: {},
|
|
476
|
+
pbrDebug: false,
|
|
477
|
+
imageBasedLightingEnvironment: null,
|
|
478
|
+
lights: true,
|
|
479
|
+
useTangents: false
|
|
480
|
+
};
|
|
481
|
+
var GLTFInstantiator = class {
|
|
482
|
+
constructor(device, options = {}) {
|
|
483
|
+
this.device = import_webgl.WebGLDevice.attach(device);
|
|
484
|
+
this.options = __spreadValues(__spreadValues({}, DEFAULT_OPTIONS), options);
|
|
485
|
+
}
|
|
486
|
+
instantiate(gltf) {
|
|
487
|
+
this.gltf = gltf;
|
|
488
|
+
const scenes = (gltf.scenes || []).map((scene) => this.createScene(scene));
|
|
489
|
+
return scenes;
|
|
490
|
+
}
|
|
491
|
+
createAnimator() {
|
|
492
|
+
if (Array.isArray(this.gltf.animations)) {
|
|
493
|
+
return new GLTFAnimator(this.gltf);
|
|
494
|
+
}
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
createScene(gltfScene) {
|
|
498
|
+
const gltfNodes = gltfScene.nodes || [];
|
|
499
|
+
const nodes = gltfNodes.map((node) => this.createNode(node));
|
|
500
|
+
const scene = new import_engine2.GroupNode({
|
|
501
|
+
id: gltfScene.name || gltfScene.id,
|
|
502
|
+
children: nodes
|
|
503
|
+
});
|
|
504
|
+
return scene;
|
|
505
|
+
}
|
|
506
|
+
createNode(gltfNode) {
|
|
507
|
+
if (!gltfNode._node) {
|
|
508
|
+
const gltfChildren = gltfNode.children || [];
|
|
509
|
+
const children = gltfChildren.map((child) => this.createNode(child));
|
|
510
|
+
if (gltfNode.mesh) {
|
|
511
|
+
children.push(this.createMesh(gltfNode.mesh));
|
|
512
|
+
}
|
|
513
|
+
const node = new import_engine2.GroupNode({
|
|
514
|
+
id: gltfNode.name || gltfNode.id,
|
|
515
|
+
children
|
|
516
|
+
});
|
|
517
|
+
if (gltfNode.matrix) {
|
|
518
|
+
node.setMatrix(gltfNode.matrix);
|
|
519
|
+
} else {
|
|
520
|
+
node.matrix.identity();
|
|
521
|
+
if (gltfNode.translation) {
|
|
522
|
+
node.matrix.translate(gltfNode.translation);
|
|
523
|
+
}
|
|
524
|
+
if (gltfNode.rotation) {
|
|
525
|
+
const rotationMatrix = new import_core5.Matrix4().fromQuaternion(gltfNode.rotation);
|
|
526
|
+
node.matrix.multiplyRight(rotationMatrix);
|
|
527
|
+
}
|
|
528
|
+
if (gltfNode.scale) {
|
|
529
|
+
node.matrix.scale(gltfNode.scale);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
gltfNode._node = node;
|
|
533
|
+
}
|
|
534
|
+
return gltfNode._node;
|
|
535
|
+
}
|
|
536
|
+
createMesh(gltfMesh) {
|
|
537
|
+
if (!gltfMesh._mesh) {
|
|
538
|
+
const gltfPrimitives = gltfMesh.primitives || [];
|
|
539
|
+
const primitives = gltfPrimitives.map(
|
|
540
|
+
(gltfPrimitive, i) => this.createPrimitive(gltfPrimitive, i, gltfMesh)
|
|
541
|
+
);
|
|
542
|
+
const mesh = new import_engine2.GroupNode({
|
|
543
|
+
id: gltfMesh.name || gltfMesh.id,
|
|
544
|
+
children: primitives
|
|
545
|
+
});
|
|
546
|
+
gltfMesh._mesh = mesh;
|
|
547
|
+
}
|
|
548
|
+
return gltfMesh._mesh;
|
|
549
|
+
}
|
|
550
|
+
createPrimitive(gltfPrimitive, i, gltfMesh) {
|
|
551
|
+
const id = gltfPrimitive.name || `${gltfMesh.name || gltfMesh.id}-primitive-${i}`;
|
|
552
|
+
const topology = convertGLDrawModeToTopology(gltfPrimitive.mode || 4);
|
|
553
|
+
const vertexCount = gltfPrimitive.indices ? gltfPrimitive.indices.count : this.getVertexCount(gltfPrimitive.attributes);
|
|
554
|
+
const modelNode = createGLTFModel(this.device, {
|
|
555
|
+
id,
|
|
556
|
+
geometry: this.createGeometry(id, gltfPrimitive, topology),
|
|
557
|
+
material: gltfPrimitive.material,
|
|
558
|
+
materialOptions: this.options,
|
|
559
|
+
modelOptions: this.options.modelOptions,
|
|
560
|
+
vertexCount
|
|
561
|
+
});
|
|
562
|
+
modelNode.bounds = [gltfPrimitive.attributes.POSITION.min, gltfPrimitive.attributes.POSITION.max];
|
|
563
|
+
return modelNode;
|
|
564
|
+
}
|
|
565
|
+
getVertexCount(attributes) {
|
|
566
|
+
throw new Error("getVertexCount not implemented");
|
|
567
|
+
}
|
|
568
|
+
createGeometry(id, gltfPrimitive, topology) {
|
|
569
|
+
const attributes = {};
|
|
570
|
+
for (const [attributeName, attribute] of Object.entries(gltfPrimitive.attributes)) {
|
|
571
|
+
const { components: size, value } = attribute;
|
|
572
|
+
attributes[attributeName] = { size, value };
|
|
573
|
+
}
|
|
574
|
+
;
|
|
575
|
+
return new import_engine2.Geometry({
|
|
576
|
+
id,
|
|
577
|
+
topology,
|
|
578
|
+
indices: gltfPrimitive.indices.value,
|
|
579
|
+
attributes
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
createBuffer(attribute, usage) {
|
|
583
|
+
if (!attribute.bufferView) {
|
|
584
|
+
attribute.bufferView = {};
|
|
585
|
+
}
|
|
586
|
+
const { bufferView } = attribute;
|
|
587
|
+
if (!bufferView.lumaBuffers) {
|
|
588
|
+
bufferView.lumaBuffers = {};
|
|
589
|
+
}
|
|
590
|
+
if (!bufferView.lumaBuffers[usage]) {
|
|
591
|
+
bufferView.lumaBuffers[usage] = this.device.createBuffer({
|
|
592
|
+
id: `from-${bufferView.id}`,
|
|
593
|
+
// Draco decoded files have attribute.value
|
|
594
|
+
data: bufferView.data || attribute.value
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
return bufferView.lumaBuffers[usage];
|
|
598
|
+
}
|
|
599
|
+
// TODO - create sampler in WebGL2
|
|
600
|
+
createSampler(gltfSampler) {
|
|
601
|
+
return gltfSampler;
|
|
602
|
+
}
|
|
603
|
+
// Helper methods (move to GLTFLoader.resolve...?)
|
|
604
|
+
needsPOT() {
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
function convertGLDrawModeToTopology(drawMode) {
|
|
609
|
+
switch (drawMode) {
|
|
610
|
+
case 0 /* POINTS */:
|
|
611
|
+
return "point-list";
|
|
612
|
+
case 1 /* LINES */:
|
|
613
|
+
return "line-list";
|
|
614
|
+
case 3 /* LINE_STRIP */:
|
|
615
|
+
return "line-strip";
|
|
616
|
+
case 2 /* LINE_LOOP */:
|
|
617
|
+
return "line-loop-webgl";
|
|
618
|
+
case 4 /* TRIANGLES */:
|
|
619
|
+
return "triangle-list";
|
|
620
|
+
case 5 /* TRIANGLE_STRIP */:
|
|
621
|
+
return "triangle-strip";
|
|
622
|
+
case 6 /* TRIANGLE_FAN */:
|
|
623
|
+
return "triangle-fan-webgl";
|
|
624
|
+
default:
|
|
625
|
+
throw new Error(drawMode);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// src/gltf/create-gltf-objects.ts
|
|
630
|
+
function createScenegraphsFromGLTF(device, gltf, options) {
|
|
631
|
+
const instantiator = new GLTFInstantiator(device, options);
|
|
632
|
+
const scenes = instantiator.instantiate(gltf);
|
|
633
|
+
const animator = instantiator.createAnimator();
|
|
634
|
+
return { scenes, animator };
|
|
635
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { PBREnvironment } from './pbr/pbr-environment';
|
|
2
|
+
export type { ParsePBRMaterialOptions, ParsedPBRMaterial } from './pbr/parse-pbr-material';
|
|
3
|
+
export { parsePBRMaterial } from './pbr/parse-pbr-material';
|
|
4
|
+
export { createScenegraphsFromGLTF } from './gltf/create-gltf-objects';
|
|
5
|
+
export { GLTFAnimator } from './gltf/gltf-animator';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EAAC,uBAAuB,EAAE,iBAAiB,EAAC,MAAM,0BAA0B,CAAC;AACzF,OAAO,EAAC,gBAAgB,EAAC,MAAM,0BAA0B,CAAC;AAG1D,OAAO,EAAC,yBAAyB,EAAC,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["parsePBRMaterial","createScenegraphsFromGLTF","GLTFAnimator"],"sources":["../src/index.ts"],"sourcesContent":["// luma.gl, MIT license\n\nexport type {PBREnvironment} from './pbr/pbr-environment';\nexport type {ParsePBRMaterialOptions, ParsedPBRMaterial} from './pbr/parse-pbr-material';\nexport {parsePBRMaterial} from './pbr/parse-pbr-material';\n\n// glTF Scenegraph Instantiator\nexport {createScenegraphsFromGLTF} from './gltf/create-gltf-objects';\nexport {GLTFAnimator} from './gltf/gltf-animator';\n\n"],"mappings":"SAIQA,gBAAgB;AAAA,SAGhBC,yBAAyB;AAAA,SACzBC,YAAY"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Device, Texture, Binding, Parameters } from '@luma.gl/core';
|
|
2
|
+
import { PBREnvironment } from './pbr-environment';
|
|
3
|
+
export type ParsePBRMaterialOptions = {
|
|
4
|
+
/** Debug PBR shader */
|
|
5
|
+
pbrDebug?: boolean;
|
|
6
|
+
/** Enable lights */
|
|
7
|
+
lights?: any;
|
|
8
|
+
/** Use tangents */
|
|
9
|
+
useTangents?: boolean;
|
|
10
|
+
/** provide an image based (texture cube) lighting environment */
|
|
11
|
+
imageBasedLightingEnvironment?: PBREnvironment;
|
|
12
|
+
};
|
|
13
|
+
export type ParsedPBRMaterial = {
|
|
14
|
+
readonly defines: Record<string, number | boolean>;
|
|
15
|
+
readonly bindings: Record<string, Binding>;
|
|
16
|
+
readonly uniforms: Record<string, any>;
|
|
17
|
+
readonly parameters: Parameters;
|
|
18
|
+
readonly glParameters: Record<string, any>;
|
|
19
|
+
/** List of all generated textures, makes it easy to destroy them later */
|
|
20
|
+
readonly generatedTextures: Texture[];
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Parses a GLTF material definition into uniforms and parameters for the PBR shader module
|
|
24
|
+
*/
|
|
25
|
+
export declare function parsePBRMaterial(device: Device, material: any, attributes: Record<string, any>, options: ParsePBRMaterialOptions): ParsedPBRMaterial;
|
|
26
|
+
//# sourceMappingURL=parse-pbr-material.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-pbr-material.d.ts","sourceRoot":"","sources":["../../src/pbr/parse-pbr-material.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAC,MAAM,eAAe,CAAC;AAGxE,OAAO,EAAC,cAAc,EAAC,MAAM,mBAAmB,CAAC;AAIjD,MAAM,MAAM,uBAAuB,GAAG;IACpC,uBAAuB;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oBAAoB;IACpB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,mBAAmB;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iEAAiE;IACjE,6BAA6B,CAAC,EAAE,cAAc,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3C,0EAA0E;IAC1E,QAAQ,CAAC,iBAAiB,EAAE,OAAO,EAAE,CAAC;CACvC,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,QAAQ,KAAA,EACR,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC/B,OAAO,EAAE,uBAAuB,GAC/B,iBAAiB,CAoDnB"}
|