@babylonjs/serializers 7.43.0 → 7.44.1
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/USDZ/usdzExporter.d.ts +3 -3
- package/USDZ/usdzExporter.js +3 -3
- package/USDZ/usdzExporter.js.map +1 -1
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.d.ts +3 -3
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.js +10 -42
- package/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.d.ts +32 -0
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.js +136 -0
- package/glTF/2.0/Extensions/KHR_draco_mesh_compression.js.map +1 -0
- package/glTF/2.0/Extensions/index.d.ts +1 -0
- package/glTF/2.0/Extensions/index.js +1 -0
- package/glTF/2.0/Extensions/index.js.map +1 -1
- package/glTF/2.0/bufferManager.d.ts +68 -0
- package/glTF/2.0/bufferManager.js +152 -0
- package/glTF/2.0/bufferManager.js.map +1 -0
- package/glTF/2.0/dataWriter.d.ts +5 -3
- package/glTF/2.0/dataWriter.js +30 -12
- package/glTF/2.0/dataWriter.js.map +1 -1
- package/glTF/2.0/glTFAnimation.d.ts +7 -7
- package/glTF/2.0/glTFAnimation.js +30 -51
- package/glTF/2.0/glTFAnimation.js.map +1 -1
- package/glTF/2.0/glTFExporter.d.ts +5 -4
- package/glTF/2.0/glTFExporter.js +112 -146
- package/glTF/2.0/glTFExporter.js.map +1 -1
- package/glTF/2.0/glTFExporterExtension.d.ts +14 -10
- package/glTF/2.0/glTFExporterExtension.js.map +1 -1
- package/glTF/2.0/glTFMaterialExporter.js +25 -15
- package/glTF/2.0/glTFMaterialExporter.js.map +1 -1
- package/glTF/2.0/glTFMorphTargetsUtilities.d.ts +2 -2
- package/glTF/2.0/glTFMorphTargetsUtilities.js +23 -25
- package/glTF/2.0/glTFMorphTargetsUtilities.js.map +1 -1
- package/glTF/2.0/glTFSerializer.d.ts +8 -0
- package/glTF/2.0/glTFSerializer.js.map +1 -1
- package/glTF/2.0/glTFUtilities.d.ts +11 -28
- package/glTF/2.0/glTFUtilities.js +16 -57
- package/glTF/2.0/glTFUtilities.js.map +1 -1
- package/package.json +3 -3
@@ -2,7 +2,6 @@ import type { IBufferView, IAccessor, INode, IScene, IMesh, IMaterial, ITexture,
|
|
2
2
|
import { ImageMimeType } from "babylonjs-gltf2interface";
|
3
3
|
import type { Nullable } from "@babylonjs/core/types.js";
|
4
4
|
import type { Node } from "@babylonjs/core/node.js";
|
5
|
-
import type { SubMesh } from "@babylonjs/core/Meshes/subMesh.js";
|
6
5
|
import type { BaseTexture } from "@babylonjs/core/Materials/Textures/baseTexture.js";
|
7
6
|
import type { Texture } from "@babylonjs/core/Materials/Textures/texture.js";
|
8
7
|
import { Material } from "@babylonjs/core/Materials/material.js";
|
@@ -11,6 +10,7 @@ import type { IGLTFExporterExtensionV2 } from "./glTFExporterExtension";
|
|
11
10
|
import { GLTFMaterialExporter } from "./glTFMaterialExporter";
|
12
11
|
import type { IExportOptions } from "./glTFSerializer";
|
13
12
|
import { GLTFData } from "./glTFData";
|
13
|
+
import { BufferManager } from "./bufferManager";
|
14
14
|
/** @internal */
|
15
15
|
export declare class GLTFExporter {
|
16
16
|
readonly _glTF: IGLTF;
|
@@ -33,15 +33,15 @@ export declare class GLTFExporter {
|
|
33
33
|
mimeType: ImageMimeType;
|
34
34
|
};
|
35
35
|
};
|
36
|
-
private readonly _orderedImageData;
|
37
36
|
/**
|
38
37
|
* Baked animation sample rate
|
39
38
|
*/
|
40
39
|
private _animationSampleRate;
|
41
40
|
private readonly _options;
|
41
|
+
_shouldUseGlb: boolean;
|
42
42
|
readonly _materialExporter: GLTFMaterialExporter;
|
43
43
|
private readonly _extensions;
|
44
|
-
|
44
|
+
readonly _bufferManager: BufferManager;
|
45
45
|
private readonly _shouldExportNodeMap;
|
46
46
|
private readonly _nodeMap;
|
47
47
|
readonly _materialMap: Map<Material, number>;
|
@@ -55,11 +55,12 @@ export declare class GLTFExporter {
|
|
55
55
|
private _applyExtension;
|
56
56
|
private _applyExtensions;
|
57
57
|
_extensionsPreExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Promise<Nullable<BaseTexture>>;
|
58
|
-
_extensionsPostExportMeshPrimitiveAsync(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh): Promise<Nullable<IMeshPrimitive>>;
|
59
58
|
_extensionsPostExportNodeAsync(context: string, node: INode, babylonNode: Node, nodeMap: Map<Node, number>, convertToRightHanded: boolean): Promise<Nullable<INode>>;
|
60
59
|
_extensionsPostExportMaterialAsync(context: string, material: IMaterial, babylonMaterial: Material): Promise<Nullable<IMaterial>>;
|
61
60
|
_extensionsPostExportMaterialAdditionalTextures(context: string, material: IMaterial, babylonMaterial: Material): BaseTexture[];
|
62
61
|
_extensionsPostExportTextures(context: string, textureInfo: ITextureInfo, babylonTexture: BaseTexture): void;
|
62
|
+
_extensionsPostExportMeshPrimitive(primitive: IMeshPrimitive): void;
|
63
|
+
_extensionsPreGenerateBinaryAsync(): Promise<void>;
|
63
64
|
private _forEachExtensions;
|
64
65
|
private _extensionsOnExporting;
|
65
66
|
private _loadExtensions;
|
package/glTF/2.0/glTFExporter.js
CHANGED
@@ -9,23 +9,24 @@ import { Engine } from "@babylonjs/core/Engines/engine.js";
|
|
9
9
|
import { EngineStore } from "@babylonjs/core/Engines/engineStore.js";
|
10
10
|
import { GLTFMaterialExporter } from "./glTFMaterialExporter.js";
|
11
11
|
import { GLTFData } from "./glTFData.js";
|
12
|
-
import {
|
13
|
-
import {
|
12
|
+
import { ConvertToRightHandedPosition, ConvertToRightHandedRotation, DataArrayToUint8Array, GetAccessorType, GetAttributeType, GetMinMax, GetPrimitiveMode, IsNoopNode, IsTriangleFillMode, IsParentAddedByImporter, ConvertToRightHandedNode, RotateNode180Y, FloatsNeed16BitInteger, IsStandardVertexAttribute, IndicesArrayToTypedArray, } from "./glTFUtilities.js";
|
13
|
+
import { BufferManager } from "./bufferManager.js";
|
14
14
|
import { Camera } from "@babylonjs/core/Cameras/camera.js";
|
15
15
|
import { MultiMaterial } from "@babylonjs/core/Materials/multiMaterial.js";
|
16
16
|
import { PBRMaterial } from "@babylonjs/core/Materials/PBR/pbrMaterial.js";
|
17
17
|
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial.js";
|
18
18
|
import { Logger } from "@babylonjs/core/Misc/logger.js";
|
19
|
-
import { EnumerateFloatValues } from "@babylonjs/core/Buffers/bufferUtils.js";
|
19
|
+
import { EnumerateFloatValues, AreIndices32Bits } from "@babylonjs/core/Buffers/bufferUtils.js";
|
20
20
|
import { _GLTFAnimation } from "./glTFAnimation.js";
|
21
21
|
import { BuildMorphTargetBuffers } from "./glTFMorphTargetsUtilities.js";
|
22
22
|
import { LinesMesh } from "@babylonjs/core/Meshes/linesMesh.js";
|
23
|
+
import { GreasedLineBaseMesh } from "@babylonjs/core/Meshes/GreasedLine/greasedLineBaseMesh.js";
|
23
24
|
import { Color3, Color4 } from "@babylonjs/core/Maths/math.color.js";
|
24
25
|
class ExporterState {
|
25
26
|
constructor(convertToRightHanded, wasAddedByNoopNode) {
|
26
27
|
// Babylon indices array, start, count, offset, flip -> glTF accessor index
|
27
28
|
this._indicesAccessorMap = new Map();
|
28
|
-
// Babylon buffer -> glTF buffer view
|
29
|
+
// Babylon buffer -> glTF buffer view
|
29
30
|
this._vertexBufferViewMap = new Map();
|
30
31
|
// Babylon vertex buffer, start, count -> glTF accessor index
|
31
32
|
this._vertexAccessorMap = new Map();
|
@@ -77,12 +78,12 @@ class ExporterState {
|
|
77
78
|
getVertexBufferView(buffer) {
|
78
79
|
return this._vertexBufferViewMap.get(buffer);
|
79
80
|
}
|
80
|
-
setVertexBufferView(buffer,
|
81
|
-
this._vertexBufferViewMap.set(buffer,
|
81
|
+
setVertexBufferView(buffer, bufferView) {
|
82
|
+
this._vertexBufferViewMap.set(buffer, bufferView);
|
82
83
|
}
|
83
|
-
setRemappedBufferView(buffer, vertexBuffer,
|
84
|
+
setRemappedBufferView(buffer, vertexBuffer, bufferView) {
|
84
85
|
this._remappedBufferView.set(buffer, new Map());
|
85
|
-
this._remappedBufferView.get(buffer).set(vertexBuffer,
|
86
|
+
this._remappedBufferView.get(buffer).set(vertexBuffer, bufferView);
|
86
87
|
}
|
87
88
|
getRemappedBufferView(buffer, vertexBuffer) {
|
88
89
|
return this._remappedBufferView.get(buffer)?.get(vertexBuffer);
|
@@ -148,11 +149,8 @@ export class GLTFExporter {
|
|
148
149
|
_extensionsPreExportTextureAsync(context, babylonTexture, mimeType) {
|
149
150
|
return this._applyExtensions(babylonTexture, (extension, node) => extension.preExportTextureAsync && extension.preExportTextureAsync(context, node, mimeType));
|
150
151
|
}
|
151
|
-
_extensionsPostExportMeshPrimitiveAsync(context, meshPrimitive, babylonSubMesh) {
|
152
|
-
return this._applyExtensions(meshPrimitive, (extension, node) => extension.postExportMeshPrimitiveAsync && extension.postExportMeshPrimitiveAsync(context, node, babylonSubMesh));
|
153
|
-
}
|
154
152
|
_extensionsPostExportNodeAsync(context, node, babylonNode, nodeMap, convertToRightHanded) {
|
155
|
-
return this._applyExtensions(node, (extension, node) => extension.postExportNodeAsync && extension.postExportNodeAsync(context, node, babylonNode, nodeMap, convertToRightHanded, this.
|
153
|
+
return this._applyExtensions(node, (extension, node) => extension.postExportNodeAsync && extension.postExportNodeAsync(context, node, babylonNode, nodeMap, convertToRightHanded, this._bufferManager));
|
156
154
|
}
|
157
155
|
_extensionsPostExportMaterialAsync(context, material, babylonMaterial) {
|
158
156
|
return this._applyExtensions(material, (extension, node) => extension.postExportMaterialAsync && extension.postExportMaterialAsync(context, node, babylonMaterial));
|
@@ -175,6 +173,22 @@ export class GLTFExporter {
|
|
175
173
|
}
|
176
174
|
}
|
177
175
|
}
|
176
|
+
_extensionsPostExportMeshPrimitive(primitive) {
|
177
|
+
for (const name of GLTFExporter._ExtensionNames) {
|
178
|
+
const extension = this._extensions[name];
|
179
|
+
if (extension.postExportMeshPrimitive) {
|
180
|
+
extension.postExportMeshPrimitive(primitive, this._bufferManager, this._accessors);
|
181
|
+
}
|
182
|
+
}
|
183
|
+
}
|
184
|
+
async _extensionsPreGenerateBinaryAsync() {
|
185
|
+
for (const name of GLTFExporter._ExtensionNames) {
|
186
|
+
const extension = this._extensions[name];
|
187
|
+
if (extension.preGenerateBinaryAsync) {
|
188
|
+
await extension.preGenerateBinaryAsync(this._bufferManager);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
}
|
178
192
|
_forEachExtensions(action) {
|
179
193
|
for (const name of GLTFExporter._ExtensionNames) {
|
180
194
|
const extension = this._extensions[name];
|
@@ -227,10 +241,10 @@ export class GLTFExporter {
|
|
227
241
|
this._skins = [];
|
228
242
|
this._textures = [];
|
229
243
|
this._imageData = {};
|
230
|
-
this.
|
244
|
+
this._shouldUseGlb = false;
|
231
245
|
this._materialExporter = new GLTFMaterialExporter(this);
|
232
246
|
this._extensions = {};
|
233
|
-
this.
|
247
|
+
this._bufferManager = new BufferManager();
|
234
248
|
this._shouldExportNodeMap = new Map();
|
235
249
|
// Babylon node -> glTF node index
|
236
250
|
this._nodeMap = new Map();
|
@@ -255,6 +269,7 @@ export class GLTFExporter {
|
|
255
269
|
exportUnusedUVs: false,
|
256
270
|
removeNoopRootNodes: true,
|
257
271
|
includeCoordinateSystemConversionNodes: false,
|
272
|
+
meshCompressionMethod: "None",
|
258
273
|
...options,
|
259
274
|
};
|
260
275
|
this._loadExtensions();
|
@@ -286,12 +301,8 @@ export class GLTFExporter {
|
|
286
301
|
}
|
287
302
|
return true;
|
288
303
|
}
|
289
|
-
_generateJSON(
|
304
|
+
_generateJSON(bufferByteLength, fileName, prettyPrint) {
|
290
305
|
const buffer = { byteLength: bufferByteLength };
|
291
|
-
let imageName;
|
292
|
-
let imageData;
|
293
|
-
let bufferView;
|
294
|
-
let byteOffset = bufferByteLength;
|
295
306
|
if (buffer.byteLength) {
|
296
307
|
this._glTF.buffers = [buffer];
|
297
308
|
}
|
@@ -330,30 +341,9 @@ export class GLTFExporter {
|
|
330
341
|
this._glTF.skins = this._skins;
|
331
342
|
}
|
332
343
|
if (this._images && this._images.length) {
|
333
|
-
|
334
|
-
this._glTF.images = this._images;
|
335
|
-
}
|
336
|
-
else {
|
337
|
-
this._glTF.images = [];
|
338
|
-
this._images.forEach((image) => {
|
339
|
-
if (image.uri) {
|
340
|
-
imageData = this._imageData[image.uri];
|
341
|
-
this._orderedImageData.push(imageData);
|
342
|
-
bufferView = CreateBufferView(0, byteOffset, imageData.data.byteLength, undefined);
|
343
|
-
byteOffset += imageData.data.byteLength;
|
344
|
-
this._bufferViews.push(bufferView);
|
345
|
-
image.bufferView = this._bufferViews.length - 1;
|
346
|
-
image.name = imageName;
|
347
|
-
image.mimeType = imageData.mimeType;
|
348
|
-
image.uri = undefined;
|
349
|
-
this._glTF.images.push(image);
|
350
|
-
}
|
351
|
-
});
|
352
|
-
// Replace uri with bufferview and mime type for glb
|
353
|
-
buffer.byteLength = byteOffset;
|
354
|
-
}
|
344
|
+
this._glTF.images = this._images;
|
355
345
|
}
|
356
|
-
if (!
|
346
|
+
if (!this._shouldUseGlb) {
|
357
347
|
buffer.uri = fileName + ".bin";
|
358
348
|
}
|
359
349
|
return prettyPrint ? JSON.stringify(this._glTF, null, 2) : JSON.stringify(this._glTF);
|
@@ -361,7 +351,7 @@ export class GLTFExporter {
|
|
361
351
|
async generateGLTFAsync(glTFPrefix) {
|
362
352
|
const binaryBuffer = await this._generateBinaryAsync();
|
363
353
|
this._extensionsOnExporting();
|
364
|
-
const jsonText = this._generateJSON(
|
354
|
+
const jsonText = this._generateJSON(binaryBuffer.byteLength, glTFPrefix, true);
|
365
355
|
const bin = new Blob([binaryBuffer], { type: "application/octet-stream" });
|
366
356
|
const glTFFileName = glTFPrefix + ".gltf";
|
367
357
|
const glTFBinFile = glTFPrefix + ".bin";
|
@@ -377,7 +367,8 @@ export class GLTFExporter {
|
|
377
367
|
}
|
378
368
|
async _generateBinaryAsync() {
|
379
369
|
await this._exportSceneAsync();
|
380
|
-
|
370
|
+
await this._extensionsPreGenerateBinaryAsync();
|
371
|
+
return this._bufferManager.generateBinary(this._bufferViews);
|
381
372
|
}
|
382
373
|
/**
|
383
374
|
* Pads the number to a multiple of 4
|
@@ -390,28 +381,24 @@ export class GLTFExporter {
|
|
390
381
|
return padding;
|
391
382
|
}
|
392
383
|
async generateGLBAsync(glTFPrefix) {
|
384
|
+
this._shouldUseGlb = true;
|
393
385
|
const binaryBuffer = await this._generateBinaryAsync();
|
394
386
|
this._extensionsOnExporting();
|
395
|
-
const jsonText = this._generateJSON(
|
387
|
+
const jsonText = this._generateJSON(binaryBuffer.byteLength);
|
396
388
|
const glbFileName = glTFPrefix + ".glb";
|
397
389
|
const headerLength = 12;
|
398
390
|
const chunkLengthPrefix = 8;
|
399
391
|
let jsonLength = jsonText.length;
|
400
392
|
let encodedJsonText;
|
401
|
-
let imageByteLength = 0;
|
402
393
|
// make use of TextEncoder when available
|
403
394
|
if (typeof TextEncoder !== "undefined") {
|
404
395
|
const encoder = new TextEncoder();
|
405
396
|
encodedJsonText = encoder.encode(jsonText);
|
406
397
|
jsonLength = encodedJsonText.length;
|
407
398
|
}
|
408
|
-
for (let i = 0; i < this._orderedImageData.length; ++i) {
|
409
|
-
imageByteLength += this._orderedImageData[i].data.byteLength;
|
410
|
-
}
|
411
399
|
const jsonPadding = this._getPadding(jsonLength);
|
412
400
|
const binPadding = this._getPadding(binaryBuffer.byteLength);
|
413
|
-
const
|
414
|
-
const byteLength = headerLength + 2 * chunkLengthPrefix + jsonLength + jsonPadding + binaryBuffer.byteLength + binPadding + imageByteLength + imagePadding;
|
401
|
+
const byteLength = headerLength + 2 * chunkLengthPrefix + jsonLength + jsonPadding + binaryBuffer.byteLength + binPadding;
|
415
402
|
// header
|
416
403
|
const headerBuffer = new ArrayBuffer(headerLength);
|
417
404
|
const headerBufferView = new DataView(headerBuffer);
|
@@ -450,7 +437,7 @@ export class GLTFExporter {
|
|
450
437
|
// binary chunk
|
451
438
|
const binaryChunkBuffer = new ArrayBuffer(chunkLengthPrefix);
|
452
439
|
const binaryChunkBufferView = new DataView(binaryChunkBuffer);
|
453
|
-
binaryChunkBufferView.setUint32(0, binaryBuffer.byteLength + binPadding
|
440
|
+
binaryChunkBufferView.setUint32(0, binaryBuffer.byteLength + binPadding, true);
|
454
441
|
binaryChunkBufferView.setUint32(4, 0x004e4942, true);
|
455
442
|
// binary padding
|
456
443
|
const binPaddingBuffer = new ArrayBuffer(binPadding);
|
@@ -458,18 +445,7 @@ export class GLTFExporter {
|
|
458
445
|
for (let i = 0; i < binPadding; ++i) {
|
459
446
|
binPaddingView[i] = 0;
|
460
447
|
}
|
461
|
-
const
|
462
|
-
const imagePaddingView = new Uint8Array(imagePaddingBuffer);
|
463
|
-
for (let i = 0; i < imagePadding; ++i) {
|
464
|
-
imagePaddingView[i] = 0;
|
465
|
-
}
|
466
|
-
const glbData = [headerBuffer, jsonChunkBuffer, binaryChunkBuffer, binaryBuffer];
|
467
|
-
// binary data
|
468
|
-
for (let i = 0; i < this._orderedImageData.length; ++i) {
|
469
|
-
glbData.push(this._orderedImageData[i].data);
|
470
|
-
}
|
471
|
-
glbData.push(binPaddingBuffer);
|
472
|
-
glbData.push(imagePaddingBuffer);
|
448
|
+
const glbData = [headerBuffer, jsonChunkBuffer, binaryChunkBuffer, binaryBuffer, binPaddingBuffer];
|
473
449
|
const glbFile = new Blob(glbData, { type: "application/octet-stream" });
|
474
450
|
const container = new GLTFData();
|
475
451
|
container.files[glbFileName] = glbFile;
|
@@ -617,21 +593,16 @@ export class GLTFExporter {
|
|
617
593
|
const skinedNodes = this._nodesSkinMap.get(skin);
|
618
594
|
// Only create skeleton if it has at least one joint and is used by a mesh.
|
619
595
|
if (skin.joints.length > 0 && skinedNodes !== undefined) {
|
620
|
-
//
|
621
|
-
const
|
622
|
-
const
|
623
|
-
|
624
|
-
|
625
|
-
this._bufferViews.push(bufferView);
|
626
|
-
const bufferViewIndex = this._bufferViews.length - 1;
|
627
|
-
const bindMatrixAccessor = CreateAccessor(bufferViewIndex, "MAT4" /* AccessorType.MAT4 */, 5126 /* AccessorComponentType.FLOAT */, inverseBindMatrices.length, null, null);
|
628
|
-
const inverseBindAccessorIndex = this._accessors.push(bindMatrixAccessor) - 1;
|
629
|
-
skin.inverseBindMatrices = inverseBindAccessorIndex;
|
630
|
-
inverseBindMatrices.forEach((mat) => {
|
631
|
-
mat.m.forEach((cell) => {
|
632
|
-
this._dataWriter.writeFloat32(cell);
|
633
|
-
});
|
596
|
+
// Put IBM data into TypedArraybuffer view
|
597
|
+
const byteLength = inverseBindMatrices.length * 64; // Always a 4 x 4 matrix of 32 bit float
|
598
|
+
const inverseBindMatricesData = new Float32Array(byteLength / 4);
|
599
|
+
inverseBindMatrices.forEach((mat, index) => {
|
600
|
+
inverseBindMatricesData.set(mat.m, index * 16);
|
634
601
|
});
|
602
|
+
// Create buffer view and accessor
|
603
|
+
const bufferView = this._bufferManager.createBufferView(inverseBindMatricesData);
|
604
|
+
this._accessors.push(this._bufferManager.createAccessor(bufferView, "MAT4" /* AccessorType.MAT4 */, 5126 /* AccessorComponentType.FLOAT */, inverseBindMatrices.length));
|
605
|
+
skin.inverseBindMatrices = this._accessors.length - 1;
|
635
606
|
this._skins.push(skin);
|
636
607
|
for (const skinedNode of skinedNodes) {
|
637
608
|
skinedNode.skin = this._skins.length - 1;
|
@@ -682,7 +653,7 @@ export class GLTFExporter {
|
|
682
653
|
this._exportAndAssignCameras();
|
683
654
|
this._exportAndAssignSkeletons();
|
684
655
|
if (this._babylonScene.animationGroups.length) {
|
685
|
-
_GLTFAnimation._CreateNodeAndMorphAnimationFromAnimationGroups(this._babylonScene, this._animations, this._nodeMap, this.
|
656
|
+
_GLTFAnimation._CreateNodeAndMorphAnimationFromAnimationGroups(this._babylonScene, this._animations, this._nodeMap, this._bufferManager, this._bufferViews, this._accessors, this._animationSampleRate, stateLH.getNodesSet());
|
686
657
|
}
|
687
658
|
}
|
688
659
|
_shouldExportNode(babylonNode) {
|
@@ -706,6 +677,9 @@ export class GLTFExporter {
|
|
706
677
|
const vertexBuffers = babylonNode.geometry.getVertexBuffers();
|
707
678
|
if (vertexBuffers) {
|
708
679
|
for (const kind in vertexBuffers) {
|
680
|
+
if (!IsStandardVertexAttribute(kind)) {
|
681
|
+
continue;
|
682
|
+
}
|
709
683
|
const vertexBuffer = vertexBuffers[kind];
|
710
684
|
state.setHasVertexColorAlpha(vertexBuffer, babylonNode.hasVertexAlpha);
|
711
685
|
const buffer = vertexBuffer._buffer;
|
@@ -772,10 +746,13 @@ export class GLTFExporter {
|
|
772
746
|
case VertexBuffer.NormalKind:
|
773
747
|
case VertexBuffer.TangentKind: {
|
774
748
|
EnumerateFloatValues(bytes, byteOffset, byteStride, size, type, maxTotalVertices * size, normalized, (values) => {
|
775
|
-
const
|
776
|
-
|
777
|
-
|
778
|
-
|
749
|
+
const length = Math.sqrt(values[0] * values[0] + values[1] * values[1] + values[2] * values[2]);
|
750
|
+
if (length > 0) {
|
751
|
+
const invLength = 1 / length;
|
752
|
+
values[0] *= invLength;
|
753
|
+
values[1] *= invLength;
|
754
|
+
values[2] *= invLength;
|
755
|
+
}
|
779
756
|
});
|
780
757
|
break;
|
781
758
|
}
|
@@ -832,12 +809,11 @@ export class GLTFExporter {
|
|
832
809
|
// Save converted bytes for min/max computation.
|
833
810
|
state.convertedToRightHandedBuffers.set(buffer, bytes);
|
834
811
|
}
|
835
|
-
|
836
|
-
this.
|
837
|
-
|
838
|
-
state.setVertexBufferView(buffer, this._bufferViews.length - 1);
|
812
|
+
// Create buffer view, but defer accessor creation for later. Instead, track it via ExporterState.
|
813
|
+
const bufferView = this._bufferManager.createBufferView(bytes, byteStride);
|
814
|
+
state.setVertexBufferView(buffer, bufferView);
|
839
815
|
const floatMatricesIndices = new Map();
|
840
|
-
// If buffers are of type
|
816
|
+
// If buffers are of type MatricesIndicesKind and have float values, we need to create a new buffer instead.
|
841
817
|
for (const vertexBuffer of vertexBuffers) {
|
842
818
|
switch (vertexBuffer.getKind()) {
|
843
819
|
case VertexBuffer.MatricesIndicesKind:
|
@@ -862,24 +838,13 @@ export class GLTFExporter {
|
|
862
838
|
if (!array) {
|
863
839
|
continue;
|
864
840
|
}
|
865
|
-
const
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
newArray[index] = array[index];
|
870
|
-
}
|
871
|
-
this._dataWriter.writeUint16Array(newArray);
|
872
|
-
this._bufferViews.push(CreateBufferView(0, byteOffset, newArray.byteLength, 4 * 2));
|
873
|
-
}
|
874
|
-
else {
|
875
|
-
const newArray = new Uint8Array(array.length);
|
876
|
-
for (let index = 0; index < array.length; index++) {
|
877
|
-
newArray[index] = array[index];
|
878
|
-
}
|
879
|
-
this._dataWriter.writeUint8Array(newArray);
|
880
|
-
this._bufferViews.push(CreateBufferView(0, byteOffset, newArray.byteLength, 4));
|
841
|
+
const is16Bit = FloatsNeed16BitInteger(array);
|
842
|
+
const newArray = new (is16Bit ? Uint16Array : Uint8Array)(array.length);
|
843
|
+
for (let index = 0; index < array.length; index++) {
|
844
|
+
newArray[index] = array[index];
|
881
845
|
}
|
882
|
-
|
846
|
+
const bufferView = this._bufferManager.createBufferView(newArray, 4 * (is16Bit ? 2 : 1));
|
847
|
+
state.setRemappedBufferView(buffer, vertexBuffer, bufferView);
|
883
848
|
}
|
884
849
|
}
|
885
850
|
const morphTargets = Array.from(morphTagetsMeshesMap.keys());
|
@@ -888,7 +853,7 @@ export class GLTFExporter {
|
|
888
853
|
if (!meshes) {
|
889
854
|
continue;
|
890
855
|
}
|
891
|
-
const glTFMorphTarget = BuildMorphTargetBuffers(morphTarget, meshes[0], this.
|
856
|
+
const glTFMorphTarget = BuildMorphTargetBuffers(morphTarget, meshes[0], this._bufferManager, this._bufferViews, this._accessors, state.convertToRightHanded);
|
892
857
|
for (const mesh of meshes) {
|
893
858
|
state.bindMorphDataToMesh(mesh, glTFMorphTarget);
|
894
859
|
}
|
@@ -922,9 +887,9 @@ export class GLTFExporter {
|
|
922
887
|
};
|
923
888
|
const idleGLTFAnimations = [];
|
924
889
|
if (!this._babylonScene.animationGroups.length) {
|
925
|
-
_GLTFAnimation._CreateMorphTargetAnimationFromMorphTargetAnimations(babylonNode, runtimeGLTFAnimation, idleGLTFAnimations, this._nodeMap, this._nodes, this.
|
890
|
+
_GLTFAnimation._CreateMorphTargetAnimationFromMorphTargetAnimations(babylonNode, runtimeGLTFAnimation, idleGLTFAnimations, this._nodeMap, this._nodes, this._bufferManager, this._bufferViews, this._accessors, this._animationSampleRate, state.convertToRightHanded, this._options.shouldExportAnimation);
|
926
891
|
if (babylonNode.animations.length) {
|
927
|
-
_GLTFAnimation._CreateNodeAnimationFromNodeAnimations(babylonNode, runtimeGLTFAnimation, idleGLTFAnimations, this._nodeMap, this._nodes, this.
|
892
|
+
_GLTFAnimation._CreateNodeAnimationFromNodeAnimations(babylonNode, runtimeGLTFAnimation, idleGLTFAnimations, this._nodeMap, this._nodes, this._bufferManager, this._bufferViews, this._accessors, this._animationSampleRate, state.convertToRightHanded, this._options.shouldExportAnimation);
|
928
893
|
}
|
929
894
|
}
|
930
895
|
if (runtimeGLTFAnimation.channels.length && runtimeGLTFAnimation.samplers.length) {
|
@@ -1047,13 +1012,10 @@ export class GLTFExporter {
|
|
1047
1012
|
if (indicesToExport) {
|
1048
1013
|
let accessorIndex = state.getIndicesAccessor(indices, start, count, offset, flip);
|
1049
1014
|
if (accessorIndex === undefined) {
|
1050
|
-
const
|
1051
|
-
const
|
1052
|
-
this._dataWriter.writeUint8Array(bytes);
|
1053
|
-
this._bufferViews.push(CreateBufferView(0, bufferViewByteOffset, bytes.length));
|
1054
|
-
const bufferViewIndex = this._bufferViews.length - 1;
|
1015
|
+
const bytes = IndicesArrayToTypedArray(indicesToExport, start, count, is32Bits);
|
1016
|
+
const bufferView = this._bufferManager.createBufferView(bytes);
|
1055
1017
|
const componentType = is32Bits ? 5125 /* AccessorComponentType.UNSIGNED_INT */ : 5123 /* AccessorComponentType.UNSIGNED_SHORT */;
|
1056
|
-
this._accessors.push(
|
1018
|
+
this._accessors.push(this._bufferManager.createAccessor(bufferView, "SCALAR" /* AccessorType.SCALAR */, componentType, count, 0));
|
1057
1019
|
accessorIndex = this._accessors.length - 1;
|
1058
1020
|
state.setIndicesAccessor(indices, start, count, offset, flip, accessorIndex);
|
1059
1021
|
}
|
@@ -1074,30 +1036,19 @@ export class GLTFExporter {
|
|
1074
1036
|
if (accessorIndex === undefined) {
|
1075
1037
|
// Get min/max from converted or original data.
|
1076
1038
|
const data = state.convertedToRightHandedBuffers.get(vertexBuffer._buffer) || vertexBuffer._buffer.getData();
|
1077
|
-
const minMax = kind === VertexBuffer.PositionKind ? GetMinMax(data, vertexBuffer, start, count) :
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
const byteOffset = vertexBuffer.byteOffset + start * vertexBuffer.byteStride;
|
1091
|
-
this._accessors.push(CreateAccessor(bufferViewIndex, GetAccessorType(kind, state.hasVertexColorAlpha(vertexBuffer)), vertexBuffer.type, count, byteOffset, minMax, vertexBuffer.normalized // TODO: Find other places where this is needed.
|
1092
|
-
));
|
1093
|
-
accessorIndex = this._accessors.length - 1;
|
1094
|
-
state.setVertexAccessor(vertexBuffer, start, count, accessorIndex);
|
1095
|
-
primitive.attributes[GetAttributeType(kind)] = accessorIndex;
|
1096
|
-
}
|
1097
|
-
}
|
1098
|
-
else {
|
1099
|
-
primitive.attributes[GetAttributeType(kind)] = accessorIndex;
|
1100
|
-
}
|
1039
|
+
const minMax = kind === VertexBuffer.PositionKind ? GetMinMax(data, vertexBuffer, start, count) : undefined;
|
1040
|
+
// For the remapped buffer views we created for float matrices indices, make sure to use their updated information.
|
1041
|
+
const isFloatMatricesIndices = (kind === VertexBuffer.MatricesIndicesKind || kind === VertexBuffer.MatricesIndicesExtraKind) && vertexBuffer.type === VertexBuffer.FLOAT;
|
1042
|
+
const vertexBufferType = isFloatMatricesIndices ? VertexBuffer.UNSIGNED_BYTE : vertexBuffer.type;
|
1043
|
+
const vertexBufferNormalized = isFloatMatricesIndices ? undefined : vertexBuffer.normalized;
|
1044
|
+
const bufferView = isFloatMatricesIndices ? state.getRemappedBufferView(vertexBuffer._buffer, vertexBuffer) : state.getVertexBufferView(vertexBuffer._buffer);
|
1045
|
+
const byteOffset = vertexBuffer.byteOffset + start * vertexBuffer.byteStride;
|
1046
|
+
this._accessors.push(this._bufferManager.createAccessor(bufferView, GetAccessorType(kind, state.hasVertexColorAlpha(vertexBuffer)), vertexBufferType, count, byteOffset, minMax, vertexBufferNormalized // TODO: Find other places where this is needed.
|
1047
|
+
));
|
1048
|
+
accessorIndex = this._accessors.length - 1;
|
1049
|
+
state.setVertexAccessor(vertexBuffer, start, count, accessorIndex);
|
1050
|
+
}
|
1051
|
+
primitive.attributes[GetAttributeType(kind)] = accessorIndex;
|
1101
1052
|
}
|
1102
1053
|
async _exportMaterialAsync(babylonMaterial, vertexBuffers, subMesh, primitive) {
|
1103
1054
|
let materialIndex = this._materialMap.get(babylonMaterial);
|
@@ -1130,17 +1081,31 @@ export class GLTFExporter {
|
|
1130
1081
|
const indices = babylonMesh.isUnIndexed ? null : babylonMesh.getIndices();
|
1131
1082
|
const vertexBuffers = babylonMesh.geometry?.getVertexBuffers();
|
1132
1083
|
const morphTargets = state.getMorphTargetsFromMesh(babylonMesh);
|
1133
|
-
|
1134
|
-
|
1135
|
-
isLinesMesh = true;
|
1136
|
-
}
|
1084
|
+
const isLinesMesh = babylonMesh instanceof LinesMesh;
|
1085
|
+
const isGreasedLineMesh = babylonMesh instanceof GreasedLineBaseMesh;
|
1137
1086
|
const subMeshes = babylonMesh.subMeshes;
|
1138
1087
|
if (vertexBuffers && subMeshes && subMeshes.length > 0) {
|
1139
1088
|
for (const subMesh of subMeshes) {
|
1140
1089
|
const primitive = { attributes: {} };
|
1141
1090
|
const babylonMaterial = subMesh.getMaterial() || this._babylonScene.defaultMaterial;
|
1142
|
-
|
1143
|
-
|
1091
|
+
if (isGreasedLineMesh) {
|
1092
|
+
const material = {
|
1093
|
+
name: babylonMaterial.name,
|
1094
|
+
};
|
1095
|
+
const babylonLinesMesh = babylonMesh;
|
1096
|
+
const colorWhite = Color3.White();
|
1097
|
+
const alpha = babylonLinesMesh.material?.alpha ?? 1;
|
1098
|
+
const color = babylonLinesMesh.greasedLineMaterial?.color ?? colorWhite;
|
1099
|
+
if (!color.equals(colorWhite) || alpha < 1) {
|
1100
|
+
material.pbrMetallicRoughness = {
|
1101
|
+
baseColorFactor: [...color.asArray(), alpha],
|
1102
|
+
};
|
1103
|
+
}
|
1104
|
+
this._materials.push(material);
|
1105
|
+
primitive.material = this._materials.length - 1;
|
1106
|
+
}
|
1107
|
+
else if (isLinesMesh) {
|
1108
|
+
// Special case for LinesMesh
|
1144
1109
|
const material = {
|
1145
1110
|
name: babylonMaterial.name,
|
1146
1111
|
};
|
@@ -1158,20 +1123,21 @@ export class GLTFExporter {
|
|
1158
1123
|
await this._exportMaterialAsync(babylonMaterial, vertexBuffers, subMesh, primitive);
|
1159
1124
|
}
|
1160
1125
|
// Index buffer
|
1161
|
-
const fillMode = isLinesMesh ? Material.LineListDrawMode : (babylonMesh.overrideRenderingFillMode ?? babylonMaterial.fillMode);
|
1126
|
+
const fillMode = isLinesMesh || isGreasedLineMesh ? Material.LineListDrawMode : (babylonMesh.overrideRenderingFillMode ?? babylonMaterial.fillMode);
|
1162
1127
|
const sideOrientation = babylonMaterial._getEffectiveOrientation(babylonMesh);
|
1163
1128
|
this._exportIndices(indices, subMesh.indexStart, subMesh.indexCount, -subMesh.verticesStart, fillMode, sideOrientation, state, primitive);
|
1164
1129
|
// Vertex buffers
|
1165
1130
|
for (const vertexBuffer of Object.values(vertexBuffers)) {
|
1166
1131
|
this._exportVertexBuffer(vertexBuffer, babylonMaterial, subMesh.verticesStart, subMesh.verticesCount, state, primitive);
|
1167
1132
|
}
|
1168
|
-
mesh.primitives.push(primitive);
|
1169
1133
|
if (morphTargets) {
|
1170
1134
|
primitive.targets = [];
|
1171
1135
|
for (const gltfMorphTarget of morphTargets) {
|
1172
1136
|
primitive.targets.push(gltfMorphTarget.attributes);
|
1173
1137
|
}
|
1174
1138
|
}
|
1139
|
+
mesh.primitives.push(primitive);
|
1140
|
+
this._extensionsPostExportMeshPrimitive(primitive);
|
1175
1141
|
}
|
1176
1142
|
}
|
1177
1143
|
if (morphTargets) {
|