@babylonjs/serializers 7.11.4 → 7.13.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.
@@ -67,6 +67,26 @@ function convertNodeHandedness(node) {
67
67
  node.scale = scale.asArray();
68
68
  }
69
69
  }
70
+ function getBinaryWriterFunc(binaryWriter, attributeComponentKind) {
71
+ switch (attributeComponentKind) {
72
+ case 5121 /* AccessorComponentType.UNSIGNED_BYTE */: {
73
+ return binaryWriter.setUInt8.bind(binaryWriter);
74
+ }
75
+ case 5123 /* AccessorComponentType.UNSIGNED_SHORT */: {
76
+ return binaryWriter.setUInt16.bind(binaryWriter);
77
+ }
78
+ case 5125 /* AccessorComponentType.UNSIGNED_INT */: {
79
+ return binaryWriter.setUInt32.bind(binaryWriter);
80
+ }
81
+ case 5126 /* AccessorComponentType.FLOAT */: {
82
+ return binaryWriter.setFloat32.bind(binaryWriter);
83
+ }
84
+ default: {
85
+ Tools.Warn("Unsupported Attribute Component kind: " + attributeComponentKind);
86
+ return null;
87
+ }
88
+ }
89
+ }
70
90
  /**
71
91
  * Converts Babylon Scene into glTF 2.0.
72
92
  * @internal
@@ -600,122 +620,98 @@ export class _Exporter {
600
620
  vertexAttributes = [];
601
621
  }
602
622
  }
603
- let writeBinaryFunc;
604
- switch (attributeComponentKind) {
605
- case 5121 /* AccessorComponentType.UNSIGNED_BYTE */: {
606
- writeBinaryFunc = binaryWriter.setUInt8.bind(binaryWriter);
607
- break;
608
- }
609
- case 5123 /* AccessorComponentType.UNSIGNED_SHORT */: {
610
- writeBinaryFunc = binaryWriter.setUInt16.bind(binaryWriter);
611
- break;
612
- }
613
- case 5125 /* AccessorComponentType.UNSIGNED_INT */: {
614
- writeBinaryFunc = binaryWriter.setUInt32.bind(binaryWriter);
615
- break;
616
- }
617
- case 5126 /* AccessorComponentType.FLOAT */: {
618
- writeBinaryFunc = binaryWriter.setFloat32.bind(binaryWriter);
619
- break;
620
- }
621
- default: {
622
- Tools.Warn("Unsupported Attribute Component kind: " + attributeComponentKind);
623
- return;
624
- }
625
- }
626
- for (const vertexAttribute of vertexAttributes) {
627
- for (const component of vertexAttribute) {
628
- writeBinaryFunc(component);
623
+ const writeBinaryFunc = getBinaryWriterFunc(binaryWriter, attributeComponentKind);
624
+ if (writeBinaryFunc) {
625
+ for (const vertexAttribute of vertexAttributes) {
626
+ for (const component of vertexAttribute) {
627
+ writeBinaryFunc(component);
628
+ }
629
629
  }
630
630
  }
631
631
  }
632
- /**
633
- * Writes mesh attribute data to a data buffer
634
- * Returns the bytelength of the data
635
- * @param vertexBufferKind Indicates what kind of vertex data is being passed in
636
- * @param attributeComponentKind attribute component type
637
- * @param meshPrimitive the mesh primitive
638
- * @param meshAttributeArray Array containing the attribute data
639
- * @param morphTargetAttributeArray
640
- * @param stride Specifies the space between data
641
- * @param binaryWriter The buffer to write the binary data to
642
- * @param minMax
643
- */
644
- writeMorphTargetAttributeData(vertexBufferKind, attributeComponentKind, meshPrimitive, meshAttributeArray, morphTargetAttributeArray, stride, binaryWriter, minMax) {
645
- let vertexAttributes = [];
646
- let index;
647
- let difference = new Vector3();
648
- let difference4 = new Vector4(0, 0, 0, 0);
632
+ _createMorphTargetBufferViewKind(vertexBufferKind, accessorType, attributeComponentKind, mesh, morphTarget, binaryWriter, byteStride) {
633
+ let vertexCount;
634
+ let minMax;
635
+ const morphData = [];
636
+ const difference = TmpVectors.Vector3[0];
649
637
  switch (vertexBufferKind) {
650
638
  case VertexBuffer.PositionKind: {
651
- for (let k = meshPrimitive.verticesStart; k < meshPrimitive.verticesCount; ++k) {
652
- index = meshPrimitive.indexStart + k * stride;
653
- const vertexData = Vector3.FromArray(meshAttributeArray, index);
654
- const morphData = Vector3.FromArray(morphTargetAttributeArray, index);
655
- difference = morphData.subtractToRef(vertexData, difference);
656
- if (minMax) {
657
- minMax.min.copyFromFloats(Math.min(difference.x, minMax.min.x), Math.min(difference.y, minMax.min.y), Math.min(difference.z, minMax.min.z));
658
- minMax.max.copyFromFloats(Math.max(difference.x, minMax.max.x), Math.max(difference.y, minMax.max.y), Math.max(difference.z, minMax.max.z));
659
- }
660
- vertexAttributes.push(difference.asArray());
639
+ const morphPositions = morphTarget.getPositions();
640
+ if (!morphPositions) {
641
+ return null;
642
+ }
643
+ const originalPositions = mesh.getVerticesData(VertexBuffer.PositionKind, undefined, undefined, true);
644
+ const vertexStart = 0;
645
+ const min = new Vector3(Infinity, Infinity, Infinity);
646
+ const max = new Vector3(-Infinity, -Infinity, -Infinity);
647
+ vertexCount = originalPositions.length / 3;
648
+ for (let i = vertexStart; i < vertexCount; ++i) {
649
+ const originalPosition = Vector3.FromArray(originalPositions, i * 3);
650
+ const morphPosition = Vector3.FromArray(morphPositions, i * 3);
651
+ morphPosition.subtractToRef(originalPosition, difference);
652
+ min.copyFromFloats(Math.min(difference.x, min.x), Math.min(difference.y, min.y), Math.min(difference.z, min.z));
653
+ max.copyFromFloats(Math.max(difference.x, max.x), Math.max(difference.y, max.y), Math.max(difference.z, max.z));
654
+ morphData.push(difference.x, difference.y, difference.z);
661
655
  }
656
+ minMax = { min, max };
662
657
  break;
663
658
  }
664
659
  case VertexBuffer.NormalKind: {
665
- for (let k = meshPrimitive.verticesStart; k < meshPrimitive.verticesCount; ++k) {
666
- index = meshPrimitive.indexStart + k * stride;
667
- const vertexData = Vector3.FromArray(meshAttributeArray, index).normalize();
668
- const morphData = Vector3.FromArray(morphTargetAttributeArray, index).normalize();
669
- difference = morphData.subtractToRef(vertexData, difference);
670
- vertexAttributes.push(difference.asArray());
660
+ const morphNormals = morphTarget.getNormals();
661
+ if (!morphNormals) {
662
+ return null;
663
+ }
664
+ const originalNormals = mesh.getVerticesData(VertexBuffer.NormalKind, undefined, undefined, true);
665
+ const vertexStart = 0;
666
+ vertexCount = originalNormals.length / 3;
667
+ for (let i = vertexStart; i < vertexCount; ++i) {
668
+ const originalNormal = Vector3.FromArray(originalNormals, i * 3).normalize();
669
+ const morphNormal = Vector3.FromArray(morphNormals, i * 3).normalize();
670
+ morphNormal.subtractToRef(originalNormal, difference);
671
+ morphData.push(difference.x, difference.y, difference.z);
671
672
  }
672
673
  break;
673
674
  }
674
675
  case VertexBuffer.TangentKind: {
675
- for (let k = meshPrimitive.verticesStart; k < meshPrimitive.verticesCount; ++k) {
676
- index = meshPrimitive.indexStart + k * (stride + 1);
677
- const vertexData = Vector4.FromArray(meshAttributeArray, index);
678
- _GLTFUtilities._NormalizeTangentFromRef(vertexData);
679
- const morphData = Vector4.FromArray(morphTargetAttributeArray, index);
680
- _GLTFUtilities._NormalizeTangentFromRef(morphData);
681
- difference4 = morphData.subtractToRef(vertexData, difference4);
682
- vertexAttributes.push([difference4.x, difference4.y, difference4.z]);
676
+ const morphTangents = morphTarget.getTangents();
677
+ if (!morphTangents) {
678
+ return null;
679
+ }
680
+ // Handedness cannot be displaced, so morph target tangents omit the w component
681
+ accessorType = "VEC3" /* AccessorType.VEC3 */;
682
+ byteStride = 12; // 3 components (x/y/z) * 4 bytes (float32)
683
+ const originalTangents = mesh.getVerticesData(VertexBuffer.TangentKind, undefined, undefined, true);
684
+ const vertexStart = 0;
685
+ vertexCount = originalTangents.length / 4;
686
+ for (let i = vertexStart; i < vertexCount; ++i) {
687
+ // Only read the x, y, z components and ignore w
688
+ const originalTangent = Vector3.FromArray(originalTangents, i * 4);
689
+ _GLTFUtilities._NormalizeTangentFromRef(originalTangent);
690
+ // Morph target tangents omit the w component so it won't be present in the data
691
+ const morphTangent = Vector3.FromArray(morphTangents, i * 3);
692
+ _GLTFUtilities._NormalizeTangentFromRef(morphTangent);
693
+ morphTangent.subtractToRef(originalTangent, difference);
694
+ morphData.push(difference.x, difference.y, difference.z);
683
695
  }
684
696
  break;
685
697
  }
686
698
  default: {
687
- Tools.Warn("Unsupported Vertex Buffer Type: " + vertexBufferKind);
688
- vertexAttributes = [];
699
+ return null;
689
700
  }
690
701
  }
691
- let writeBinaryFunc;
692
- switch (attributeComponentKind) {
693
- case 5121 /* AccessorComponentType.UNSIGNED_BYTE */: {
694
- writeBinaryFunc = binaryWriter.setUInt8.bind(binaryWriter);
695
- break;
696
- }
697
- case 5123 /* AccessorComponentType.UNSIGNED_SHORT */: {
698
- writeBinaryFunc = binaryWriter.setUInt16.bind(binaryWriter);
699
- break;
700
- }
701
- case 5125 /* AccessorComponentType.UNSIGNED_INT */: {
702
- writeBinaryFunc = binaryWriter.setUInt32.bind(binaryWriter);
703
- break;
704
- }
705
- case 5126 /* AccessorComponentType.FLOAT */: {
706
- writeBinaryFunc = binaryWriter.setFloat32.bind(binaryWriter);
707
- break;
708
- }
709
- default: {
710
- Tools.Warn("Unsupported Attribute Component kind: " + attributeComponentKind);
711
- return;
712
- }
702
+ const binaryWriterFunc = getBinaryWriterFunc(binaryWriter, attributeComponentKind);
703
+ if (!binaryWriterFunc) {
704
+ return null;
713
705
  }
714
- for (const vertexAttribute of vertexAttributes) {
715
- for (const component of vertexAttribute) {
716
- writeBinaryFunc(component);
717
- }
706
+ const typeByteLength = VertexBuffer.GetTypeByteLength(attributeComponentKind);
707
+ const byteLength = morphData.length * typeByteLength;
708
+ const bufferView = _GLTFUtilities._CreateBufferView(0, binaryWriter.getByteOffset(), byteLength, byteStride, `${vertexBufferKind} - ${morphTarget.name} (Morph Target)`);
709
+ this._bufferViews.push(bufferView);
710
+ const bufferViewIndex = this._bufferViews.length - 1;
711
+ for (const value of morphData) {
712
+ binaryWriterFunc(value);
718
713
  }
714
+ return { bufferViewIndex, vertexCount, accessorType, minMax };
719
715
  }
720
716
  /**
721
717
  * Generates glTF json data
@@ -1018,68 +1014,6 @@ export class _Exporter {
1018
1014
  }
1019
1015
  }
1020
1016
  }
1021
- /**
1022
- * Creates a bufferview based on the vertices type for the Babylon mesh
1023
- * @param babylonSubMesh The Babylon submesh that the morph target is applied to
1024
- * @param meshPrimitive
1025
- * @param babylonMorphTarget the morph target to be exported
1026
- * @param binaryWriter The buffer to write the bufferview data to
1027
- */
1028
- _setMorphTargetAttributes(babylonSubMesh, meshPrimitive, babylonMorphTarget, binaryWriter) {
1029
- if (babylonMorphTarget) {
1030
- if (!meshPrimitive.targets) {
1031
- meshPrimitive.targets = [];
1032
- }
1033
- const target = {};
1034
- const mesh = babylonSubMesh.getMesh();
1035
- if (babylonMorphTarget.hasNormals) {
1036
- const vertexNormals = mesh.getVerticesData(VertexBuffer.NormalKind, undefined, undefined, true);
1037
- const morphNormals = babylonMorphTarget.getNormals();
1038
- const count = babylonSubMesh.verticesCount;
1039
- const byteStride = 12; // 3 x 4 byte floats
1040
- const byteLength = count * byteStride;
1041
- const bufferView = _GLTFUtilities._CreateBufferView(0, binaryWriter.getByteOffset(), byteLength, byteStride, babylonMorphTarget.name + "_NORMAL");
1042
- this._bufferViews.push(bufferView);
1043
- const bufferViewIndex = this._bufferViews.length - 1;
1044
- const accessor = _GLTFUtilities._CreateAccessor(bufferViewIndex, babylonMorphTarget.name + " - " + "NORMAL", "VEC3" /* AccessorType.VEC3 */, 5126 /* AccessorComponentType.FLOAT */, count, 0, null, null);
1045
- this._accessors.push(accessor);
1046
- target.NORMAL = this._accessors.length - 1;
1047
- this.writeMorphTargetAttributeData(VertexBuffer.NormalKind, 5126 /* AccessorComponentType.FLOAT */, babylonSubMesh, vertexNormals, morphNormals, byteStride / 4, binaryWriter);
1048
- }
1049
- if (babylonMorphTarget.hasPositions) {
1050
- const vertexPositions = mesh.getVerticesData(VertexBuffer.PositionKind, undefined, undefined, true);
1051
- const morphPositions = babylonMorphTarget.getPositions();
1052
- const count = babylonSubMesh.verticesCount;
1053
- const byteStride = 12; // 3 x 4 byte floats
1054
- const byteLength = count * byteStride;
1055
- const bufferView = _GLTFUtilities._CreateBufferView(0, binaryWriter.getByteOffset(), byteLength, byteStride, babylonMorphTarget.name + "_POSITION");
1056
- this._bufferViews.push(bufferView);
1057
- const bufferViewIndex = this._bufferViews.length - 1;
1058
- const minMax = { min: new Vector3(Infinity, Infinity, Infinity), max: new Vector3(-Infinity, -Infinity, -Infinity) };
1059
- const accessor = _GLTFUtilities._CreateAccessor(bufferViewIndex, babylonMorphTarget.name + " - " + "POSITION", "VEC3" /* AccessorType.VEC3 */, 5126 /* AccessorComponentType.FLOAT */, count, 0, null, null);
1060
- this._accessors.push(accessor);
1061
- target.POSITION = this._accessors.length - 1;
1062
- this.writeMorphTargetAttributeData(VertexBuffer.PositionKind, 5126 /* AccessorComponentType.FLOAT */, babylonSubMesh, vertexPositions, morphPositions, byteStride / 4, binaryWriter, minMax);
1063
- accessor.min = minMax.min.asArray();
1064
- accessor.max = minMax.max.asArray();
1065
- }
1066
- if (babylonMorphTarget.hasTangents) {
1067
- const vertexTangents = mesh.getVerticesData(VertexBuffer.TangentKind, undefined, undefined, true);
1068
- const morphTangents = babylonMorphTarget.getTangents();
1069
- const count = babylonSubMesh.verticesCount;
1070
- const byteStride = 12; // 3 x 4 byte floats
1071
- const byteLength = count * byteStride;
1072
- const bufferView = _GLTFUtilities._CreateBufferView(0, binaryWriter.getByteOffset(), byteLength, byteStride, babylonMorphTarget.name + "_NORMAL");
1073
- this._bufferViews.push(bufferView);
1074
- const bufferViewIndex = this._bufferViews.length - 1;
1075
- const accessor = _GLTFUtilities._CreateAccessor(bufferViewIndex, babylonMorphTarget.name + " - " + "TANGENT", "VEC3" /* AccessorType.VEC3 */, 5126 /* AccessorComponentType.FLOAT */, count, 0, null, null);
1076
- this._accessors.push(accessor);
1077
- target.TANGENT = this._accessors.length - 1;
1078
- this.writeMorphTargetAttributeData(VertexBuffer.TangentKind, 5126 /* AccessorComponentType.FLOAT */, babylonSubMesh, vertexTangents, morphTangents, byteStride / 4, binaryWriter);
1079
- }
1080
- meshPrimitive.targets.push(target);
1081
- }
1082
- }
1083
1017
  /**
1084
1018
  * The primitive mode of the Babylon mesh
1085
1019
  * @param babylonMesh The BabylonJS mesh
@@ -1143,46 +1077,46 @@ export class _Exporter {
1143
1077
  * @param meshPrimitive glTF mesh primitive
1144
1078
  * @param attributeKind vertex attribute
1145
1079
  */
1146
- _setAttributeKind(meshPrimitive, attributeKind) {
1080
+ _setAttributeKind(attributes, attributeKind) {
1147
1081
  switch (attributeKind) {
1148
1082
  case VertexBuffer.PositionKind: {
1149
- meshPrimitive.attributes.POSITION = this._accessors.length - 1;
1083
+ attributes.POSITION = this._accessors.length - 1;
1150
1084
  break;
1151
1085
  }
1152
1086
  case VertexBuffer.NormalKind: {
1153
- meshPrimitive.attributes.NORMAL = this._accessors.length - 1;
1087
+ attributes.NORMAL = this._accessors.length - 1;
1154
1088
  break;
1155
1089
  }
1156
1090
  case VertexBuffer.ColorKind: {
1157
- meshPrimitive.attributes.COLOR_0 = this._accessors.length - 1;
1091
+ attributes.COLOR_0 = this._accessors.length - 1;
1158
1092
  break;
1159
1093
  }
1160
1094
  case VertexBuffer.TangentKind: {
1161
- meshPrimitive.attributes.TANGENT = this._accessors.length - 1;
1095
+ attributes.TANGENT = this._accessors.length - 1;
1162
1096
  break;
1163
1097
  }
1164
1098
  case VertexBuffer.UVKind: {
1165
- meshPrimitive.attributes.TEXCOORD_0 = this._accessors.length - 1;
1099
+ attributes.TEXCOORD_0 = this._accessors.length - 1;
1166
1100
  break;
1167
1101
  }
1168
1102
  case VertexBuffer.UV2Kind: {
1169
- meshPrimitive.attributes.TEXCOORD_1 = this._accessors.length - 1;
1103
+ attributes.TEXCOORD_1 = this._accessors.length - 1;
1170
1104
  break;
1171
1105
  }
1172
1106
  case VertexBuffer.MatricesIndicesKind: {
1173
- meshPrimitive.attributes.JOINTS_0 = this._accessors.length - 1;
1107
+ attributes.JOINTS_0 = this._accessors.length - 1;
1174
1108
  break;
1175
1109
  }
1176
1110
  case VertexBuffer.MatricesIndicesExtraKind: {
1177
- meshPrimitive.attributes.JOINTS_1 = this._accessors.length - 1;
1111
+ attributes.JOINTS_1 = this._accessors.length - 1;
1178
1112
  break;
1179
1113
  }
1180
1114
  case VertexBuffer.MatricesWeightsKind: {
1181
- meshPrimitive.attributes.WEIGHTS_0 = this._accessors.length - 1;
1115
+ attributes.WEIGHTS_0 = this._accessors.length - 1;
1182
1116
  break;
1183
1117
  }
1184
1118
  case VertexBuffer.MatricesWeightsExtraKind: {
1185
- meshPrimitive.attributes.WEIGHTS_1 = this._accessors.length - 1;
1119
+ attributes.WEIGHTS_1 = this._accessors.length - 1;
1186
1120
  break;
1187
1121
  }
1188
1122
  default: {
@@ -1240,6 +1174,20 @@ export class _Exporter {
1240
1174
  this._createBufferViewKind(attributeKind, attributeComponentKind, babylonTransformNode, binaryWriter, attribute.byteStride);
1241
1175
  attribute.bufferViewIndex = this._bufferViews.length - 1;
1242
1176
  vertexAttributeBufferViews[attributeKind] = attribute.bufferViewIndex;
1177
+ // Write any morph target data to the buffer and create an associated buffer view
1178
+ if (morphTargetManager) {
1179
+ for (let i = 0; i < morphTargetManager.numTargets; ++i) {
1180
+ const morphTarget = morphTargetManager.getTarget(i);
1181
+ const morphTargetInfo = this._createMorphTargetBufferViewKind(attributeKind, attribute.accessorType, attributeComponentKind, bufferMesh, morphTarget, binaryWriter, attribute.byteStride);
1182
+ // Store info about the morph target that will be needed later when creating per-submesh accessors
1183
+ if (morphTargetInfo) {
1184
+ if (!attribute.morphTargetInfo) {
1185
+ attribute.morphTargetInfo = [];
1186
+ }
1187
+ attribute.morphTargetInfo[i] = morphTargetInfo;
1188
+ }
1189
+ }
1190
+ }
1243
1191
  }
1244
1192
  }
1245
1193
  if (bufferMesh.getTotalIndices()) {
@@ -1308,7 +1256,7 @@ export class _Exporter {
1308
1256
  }
1309
1257
  const accessor = _GLTFUtilities._CreateAccessor(bufferViewIndex, attributeKind + " - " + babylonTransformNode.name, attribute.accessorType, attribute.accessorComponentType, vertexData.length / stride, 0, minMax.min, minMax.max);
1310
1258
  this._accessors.push(accessor);
1311
- this._setAttributeKind(meshPrimitive, attributeKind);
1259
+ this._setAttributeKind(meshPrimitive.attributes, attributeKind);
1312
1260
  }
1313
1261
  }
1314
1262
  }
@@ -1347,6 +1295,7 @@ export class _Exporter {
1347
1295
  meshPrimitive.material = materialIndex;
1348
1296
  }
1349
1297
  }
1298
+ // If there are morph targets, write out targets and associated accessors
1350
1299
  if (morphTargetManager) {
1351
1300
  // By convention, morph target names are stored in the mesh extras.
1352
1301
  if (!mesh.extras) {
@@ -1354,9 +1303,25 @@ export class _Exporter {
1354
1303
  }
1355
1304
  mesh.extras.targetNames = [];
1356
1305
  for (let i = 0; i < morphTargetManager.numTargets; ++i) {
1357
- const target = morphTargetManager.getTarget(i);
1358
- this._setMorphTargetAttributes(submesh, meshPrimitive, target, binaryWriter);
1359
- mesh.extras.targetNames.push(target.name);
1306
+ const morphTarget = morphTargetManager.getTarget(i);
1307
+ mesh.extras.targetNames.push(morphTarget.name);
1308
+ for (const attribute of attributeData) {
1309
+ const morphTargetInfo = attribute.morphTargetInfo?.[i];
1310
+ if (morphTargetInfo) {
1311
+ // Write the accessor
1312
+ const byteOffset = 0;
1313
+ const accessor = _GLTFUtilities._CreateAccessor(morphTargetInfo.bufferViewIndex, `${attribute.kind} - ${morphTarget.name} (Morph Target)`, morphTargetInfo.accessorType, attribute.accessorComponentType, morphTargetInfo.vertexCount, byteOffset, morphTargetInfo.minMax?.min?.asArray() ?? null, morphTargetInfo.minMax?.max?.asArray() ?? null);
1314
+ this._accessors.push(accessor);
1315
+ // Create a target that references the new accessor
1316
+ if (!meshPrimitive.targets) {
1317
+ meshPrimitive.targets = [];
1318
+ }
1319
+ if (!meshPrimitive.targets[i]) {
1320
+ meshPrimitive.targets[i] = {};
1321
+ }
1322
+ this._setAttributeKind(meshPrimitive.targets[i], attribute.kind);
1323
+ }
1324
+ }
1360
1325
  }
1361
1326
  }
1362
1327
  mesh.primitives.push(meshPrimitive);