@babylonjs/serializers 7.12.0 → 7.13.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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);