Skip to content

Commit ed830af

Browse files
Added support for 16bit bone indexes (#1137)
Fixed code to support full 16bit range on joint indexes in GLTF. Added support for large joint counts on babylon file as well. --------- Co-authored-by: Gary Hsu <bghgary@users.noreply.github.com>
1 parent 70503ab commit ed830af

File tree

12 files changed

+206
-60
lines changed

12 files changed

+206
-60
lines changed

3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ private bool IsMeshExportable(IIGameNode meshNode)
2828
bool initialized = gameMesh.InitializeData; // needed, the property is in fact a method initializing the exporter that has wrongly been auto
2929
// translated into a property because it has no parameters
3030
}
31-
catch (Exception e)
31+
catch (Exception)
3232
{
3333
RaiseWarning($"Mesh {meshNode.Name} failed to initialize.", 2);
3434
}
@@ -148,7 +148,7 @@ private BabylonNode ExportMasterMesh(IIGameScene scene, IIGameNode meshNode, Bab
148148
bool initialized = gameMesh.InitializeData; // needed, the property is in fact a method initializing the exporter that has wrongly been auto
149149
// translated into a property because it has no parameters
150150
}
151-
catch (Exception e)
151+
catch (Exception)
152152
{
153153
RaiseWarning($"Mesh {meshNode.Name} failed to initialize. Mesh is exported as dummy.", 2);
154154
return ExportDummy(scene, meshNode, babylonScene);
@@ -494,13 +494,14 @@ private BabylonNode ExportMasterMesh(IIGameScene scene, IIGameNode meshNode, Bab
494494
if (skin != null)
495495
{
496496
babylonMesh.matricesWeights = vertices.SelectMany(v => v.Weights.ToArray()).ToArray();
497-
babylonMesh.matricesIndices = vertices.Select(v => v.BonesIndices).ToArray();
497+
babylonMesh.matricesIndices = vertices.SelectMany(v => v.BonesIndices.Select(a => (uint)a)).ToArray();
498498

499499
babylonMesh.numBoneInfluencers = maxNbBones;
500+
500501
if (maxNbBones > 4)
501502
{
502503
babylonMesh.matricesWeightsExtra = vertices.SelectMany(v => v.WeightsExtra != null ? v.WeightsExtra.ToArray() : new[] { 0.0f, 0.0f, 0.0f, 0.0f }).ToArray();
503-
babylonMesh.matricesIndicesExtra = vertices.Select(v => v.BonesIndicesExtra).ToArray();
504+
babylonMesh.matricesIndicesExtra = vertices.SelectMany(v => v.BonesIndicesExtra != null ? v.BonesIndicesExtra.Select(a => (uint)a) : new uint[] { 0, 0, 0, 0}).ToArray();
504505
}
505506
}
506507

@@ -775,7 +776,7 @@ private void ExportUserData(IIGameNode meshNode, BabylonAbstractMesh babylonMesh
775776
}
776777
RaiseMessage(d.Count + " User defined properties", 2);
777778
}
778-
catch (Exception e)
779+
catch (Exception)
779780
{
780781
RaiseWarning("Failed to parse user defined properties: " + userProp, 2);
781782
}
@@ -1329,7 +1330,7 @@ int CreateGlobalVertex(IIGameMesh mesh, BabylonAbstractMesh babylonAbstractMesh,
13291330
if (skin != null)
13301331
{
13311332
float[] weight = new float[4] { 0, 0, 0, 0 };
1332-
int[] bone = new int[4] { 0, 0, 0, 0 };
1333+
ushort[] bone = new ushort[4] { 0, 0, 0, 0 };
13331334
var nbBones = skin.GetNumberOfBones(vertexIndex);
13341335
// Babylon, nor GLTF do not support single bone skeleton, we may add a root node with no transform.
13351336
// this is echoing the process into BabylonExporter.Skeleton ExportBones(Skin)
@@ -1345,7 +1346,7 @@ int CreateGlobalVertex(IIGameMesh mesh, BabylonAbstractMesh babylonAbstractMesh,
13451346
if (boneWeight <= 0)
13461347
continue;
13471348

1348-
bone[currentVtxBone] = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, currentSkinBone).NodeID) + offset; // add optional offset
1349+
bone[currentVtxBone] = (ushort)(boneIds.IndexOf(skin.GetIGameBone(vertexIndex, currentSkinBone).NodeID) + offset); // add optional offset
13491350
weight[currentVtxBone] = skin.GetWeight(vertexIndex, currentSkinBone);
13501351
++currentVtxBone;
13511352
}
@@ -1358,12 +1359,12 @@ int CreateGlobalVertex(IIGameMesh mesh, BabylonAbstractMesh babylonAbstractMesh,
13581359
}
13591360

13601361
vertex.Weights = Loader.Global.Point4.Create(weight);
1361-
vertex.BonesIndices = (bone[3] << 24) | (bone[2] << 16) | (bone[1] << 8) | bone[0];
1362+
vertex.BonesIndices = bone;
13621363

13631364
if (currentVtxBone >= 4 && currentSkinBone < nbBones)
13641365
{
13651366
weight = new float[4] { 0, 0, 0, 0 };
1366-
bone = new int[4] { 0, 0, 0, 0 };
1367+
bone = new ushort[4] { 0, 0, 0, 0 };
13671368

13681369
// process remaining skin bones until we have a total of 8 bones for this vertex or we run out of skin bones
13691370
for (; currentSkinBone < nbBones && currentVtxBone < 8; ++currentSkinBone)
@@ -1378,7 +1379,7 @@ int CreateGlobalVertex(IIGameMesh mesh, BabylonAbstractMesh babylonAbstractMesh,
13781379
break;
13791380
}
13801381

1381-
bone[currentVtxBone - 4] = boneIds.IndexOf(skin.GetIGameBone(vertexIndex, currentSkinBone).NodeID) + offset; // add optional offset
1382+
bone[currentVtxBone - 4] = (ushort)(boneIds.IndexOf(skin.GetIGameBone(vertexIndex, currentSkinBone).NodeID) + offset); // add optional offset
13821383
weight[currentVtxBone - 4] = skin.GetWeight(vertexIndex, currentSkinBone);
13831384
++currentVtxBone;
13841385
}
@@ -1387,7 +1388,7 @@ int CreateGlobalVertex(IIGameMesh mesh, BabylonAbstractMesh babylonAbstractMesh,
13871388
if (currentVtxBone > 4)
13881389
{
13891390
vertex.WeightsExtra = Loader.Global.Point4.Create(weight);
1390-
vertex.BonesIndicesExtra = (bone[3] << 24) | (bone[2] << 16) | (bone[1] << 8) | bone[0];
1391+
vertex.BonesIndicesExtra = bone;
13911392

13921393
if (currentSkinBone < nbBones)
13931394
{

3ds Max/Max2Babylon/Exporter/BabylonExporter.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,11 @@ public void Export(MaxExportParameters exportParameters)
767767
babylonScene.Prepare(false, false);
768768
if (isBabylonExported)
769769
{
770+
if (!babylonScene.TryPackIndexArrays())
771+
{
772+
RaiseWarning("Model has too many skeleton joints. The .babylon file will store joint indices using expanded form, this will only load properly using Babylon.js >= 8.5.0.");
773+
}
774+
770775
RaiseMessage("Saving to output file");
771776

772777
var outputFile = Path.Combine(outputBabylonDirectory, outputFileName);

3ds Max/Max2Babylon/Exporter/GlobalVertex.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ public struct GlobalVertex
1919
public IPoint2 UV6 { get; set; }
2020
public IPoint2 UV7 { get; set; }
2121
public IPoint2 UV8 { get; set; }
22-
public int BonesIndices { get; set; }
22+
public ushort[] BonesIndices { get; set; }
2323
public IPoint4 Weights { get; set; }
24-
public int BonesIndicesExtra { get; set; }
24+
public ushort[] BonesIndicesExtra { get; set; }
2525
public IPoint4 WeightsExtra { get; set; }
2626
public float[] Color { get; set; }
2727

3ds Max/Max2Babylon/Forms/ExporterForm.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,15 +449,15 @@ private async Task<bool> DoExport(ExportItem exportItem, bool multiExport = fals
449449
{
450450
scaleFactorParsed = float.Parse(txtScaleFactor.Text);
451451
}
452-
catch (Exception e)
452+
catch (Exception)
453453
{
454454
throw new InvalidDataException(String.Format("Invalid Scale Factor value: {0}", txtScaleFactor.Text));
455455
}
456456
try
457457
{
458458
textureQualityParsed = long.Parse(txtQuality.Text);
459459
}
460-
catch (Exception e)
460+
catch (Exception)
461461
{
462462
throw new InvalidDataException(String.Format("Invalid Texture Quality value: {0}", txtScaleFactor.Text));
463463
}

Maya/Exporter/BabylonExporter.Mesh.cs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ internal partial class BabylonExporter
1616
private MDoubleArray allMayaInfluenceWeights; // the joint weights for the vertex (0 weight included)
1717
private Dictionary<string, int> indexByNodeName = new Dictionary<string, int>(); // contains the node (joint and parents of the current skin) fullPathName and its index
1818

19+
1920
/// <summary>
2021
///
2122
/// </summary>
@@ -560,13 +561,13 @@ private BabylonNode ExportMesh(MDagPath mDagPath, BabylonScene babylonScene)
560561
if (mFnSkinCluster != null)
561562
{
562563
babylonMesh.matricesWeights = vertices.SelectMany(v => v.Weights.ToArray()).ToArray();
563-
babylonMesh.matricesIndices = vertices.Select(v => v.BonesIndices).ToArray();
564+
babylonMesh.matricesIndices = vertices.SelectMany(v => v.BonesIndices.Select(a => (uint)a)).ToArray();
564565

565566
babylonMesh.numBoneInfluencers = maxNbBones;
566567
if (maxNbBones > 4)
567568
{
568569
babylonMesh.matricesWeightsExtra = vertices.SelectMany(v => v.WeightsExtra != null ? v.WeightsExtra.ToArray() : new[] { 0.0f, 0.0f, 0.0f, 0.0f }).ToArray();
569-
babylonMesh.matricesIndicesExtra = vertices.Select(v => v.BonesIndicesExtra).ToArray();
570+
babylonMesh.matricesIndicesExtra = vertices.SelectMany(v => v.BonesIndicesExtra != null ? v.BonesIndicesExtra.Select(a => (uint)a) : new uint[] { 0, 0, 0, 0 }).ToArray();
570571
}
571572
}
572573

@@ -1023,36 +1024,36 @@ private GlobalVertex ExtractVertex(MFnMesh mFnMesh, int polygonId, int vertexInd
10231024
float weight1 = 0;
10241025
float weight2 = 0;
10251026
float weight3 = 0;
1026-
int bone0 = 0;
1027-
int bone1 = 0;
1028-
int bone2 = 0;
1029-
int bone3 = 0;
1027+
ushort bone0 = 0;
1028+
ushort bone1 = 0;
1029+
ushort bone2 = 0;
1030+
ushort bone3 = 0;
10301031
int nbBones = weightByInfluenceIndex.Count; // number of bones/influences for this vertex
10311032

10321033
if (nbBones == 0)
10331034
{
10341035
weight0 = 1.0f;
1035-
bone0 = bonesCount;
1036+
bone0 = (ushort)bonesCount;
10361037
}
10371038

10381039
if (nbBones > 0)
10391040
{
1040-
bone0 = weightByInfluenceIndex.ElementAt(0).Key;
1041+
bone0 = (ushort)weightByInfluenceIndex.ElementAt(0).Key;
10411042
weight0 = (float)weightByInfluenceIndex.ElementAt(0).Value;
10421043

10431044
if (nbBones > 1)
10441045
{
1045-
bone1 = weightByInfluenceIndex.ElementAt(1).Key;
1046+
bone1 = (ushort)weightByInfluenceIndex.ElementAt(1).Key;
10461047
weight1 = (float)weightByInfluenceIndex.ElementAt(1).Value;
10471048

10481049
if (nbBones > 2)
10491050
{
1050-
bone2 = weightByInfluenceIndex.ElementAt(2).Key;
1051+
bone2 = (ushort)weightByInfluenceIndex.ElementAt(2).Key;
10511052
weight2 = (float)weightByInfluenceIndex.ElementAt(2).Value;
10521053

10531054
if (nbBones > 3)
10541055
{
1055-
bone3 = weightByInfluenceIndex.ElementAt(3).Key;
1056+
bone3 = (ushort)weightByInfluenceIndex.ElementAt(3).Key;
10561057
weight3 = (float)weightByInfluenceIndex.ElementAt(3).Value;
10571058
}
10581059
}
@@ -1061,37 +1062,39 @@ private GlobalVertex ExtractVertex(MFnMesh mFnMesh, int polygonId, int vertexInd
10611062

10621063
float[] weights = { weight0, weight1, weight2, weight3 };
10631064
vertex.Weights = weights;
1064-
vertex.BonesIndices = (bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0;
1065+
ushort[] boneIndexes = { bone0, bone1, bone2, bone3 };
1066+
vertex.BonesIndices = boneIndexes;
10651067

10661068
if (nbBones > 4)
10671069
{
1068-
bone0 = weightByInfluenceIndex.ElementAt(4).Key;
1070+
bone0 = (ushort)weightByInfluenceIndex.ElementAt(4).Key;
10691071
weight0 = (float)weightByInfluenceIndex.ElementAt(4).Value;
10701072
weight1 = 0;
10711073
weight2 = 0;
10721074
weight3 = 0;
10731075

10741076
if (nbBones > 5)
10751077
{
1076-
bone1 = weightByInfluenceIndex.ElementAt(5).Key;
1078+
bone1 = (ushort)weightByInfluenceIndex.ElementAt(5).Key;
10771079
weight1 = (float)weightByInfluenceIndex.ElementAt(4).Value;
10781080

10791081
if (nbBones > 6)
10801082
{
1081-
bone2 = weightByInfluenceIndex.ElementAt(6).Key;
1083+
bone2 = (ushort)weightByInfluenceIndex.ElementAt(6).Key;
10821084
weight2 = (float)weightByInfluenceIndex.ElementAt(4).Value;
10831085

10841086
if (nbBones > 7)
10851087
{
1086-
bone3 = weightByInfluenceIndex.ElementAt(7).Key;
1088+
bone3 = (ushort)weightByInfluenceIndex.ElementAt(7).Key;
10871089
weight3 = (float)weightByInfluenceIndex.ElementAt(7).Value;
10881090
}
10891091
}
10901092
}
10911093

10921094
float[] weightsExtra = { weight0, weight1, weight2, weight3 };
10931095
vertex.WeightsExtra = weightsExtra;
1094-
vertex.BonesIndicesExtra = (bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0;
1096+
ushort[] boneIndexesExtra = { bone0, bone1, bone2, bone3 };
1097+
vertex.BonesIndicesExtra = boneIndexesExtra;
10951098
}
10961099
}
10971100
return vertex;

Maya/Exporter/BabylonExporter.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,11 @@ public void Export(ExportParameters exportParameters)
513513

514514
if (isBabylonExported)
515515
{
516+
if (!babylonScene.TryPackIndexArrays())
517+
{
518+
RaiseWarning("Model has too many skeleton joints. The .babylon file will store joint indicies using expandanded form, this will only load properly using Babylon.js >= 8.5.0.");
519+
}
520+
516521
Write(babylonScene, outputBabylonDirectory, outputFileName, exportParameters.outputFormat, exportParameters.generateManifest);
517522
}
518523

Maya/Exporter/GlobalVertex.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Maya2Babylon;
2+
using System;
23

34
namespace MayaBabylon
45
{
@@ -17,9 +18,9 @@ public struct GlobalVertex
1718
public float[] UV6 { get; set; } // Vec2
1819
public float[] UV7 { get; set; } // Vec2
1920
public float[] UV8 { get; set; } // Vec2
20-
public int BonesIndices { get; set; }
21+
public ushort[] BonesIndices { get; set; }
2122
public float[] Weights { get; set; } // Vec4
22-
public int BonesIndicesExtra { get; set; }
23+
public ushort[] BonesIndicesExtra { get; set; }
2324
public float[] WeightsExtra { get; set; } // Vec4
2425
public float[] Color { get; set; } // Vec4
2526

Maya/Maya2Babylon.sln

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
4-
VisualStudioVersion = 17.13.35919.96 d17.13
4+
VisualStudioVersion = 17.13.35919.96
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maya2Babylon2017", "Maya2Babylon2017.csproj", "{50780553-6248-463B-A0F3-F82C6CCEC703}"
77
EndProject
@@ -69,7 +69,17 @@ Global
6969
..\SharedProjects\BabylonFileConverter\BabylonFileConverter.projitems*{074cced5-52d1-4cb3-94d8-b8b117d452e1}*SharedItemsImports = 4
7070
..\SharedProjects\GltfExport.Entities\GltfExport.Entities.projitems*{074cced5-52d1-4cb3-94d8-b8b117d452e1}*SharedItemsImports = 4
7171
..\SharedProjects\Utilities\Extensions.projitems*{074cced5-52d1-4cb3-94d8-b8b117d452e1}*SharedItemsImports = 4
72+
..\SharedProjects\Babylon2GLTF\Babylon2GLTF.projitems*{0ac46a8e-8c0d-4ebe-b64a-4cc274e0ff38}*SharedItemsImports = 4
73+
..\SharedProjects\BabylonExport.Entities\BabylonExport.Entities.projitems*{0ac46a8e-8c0d-4ebe-b64a-4cc274e0ff38}*SharedItemsImports = 4
74+
..\SharedProjects\BabylonFileConverter\BabylonFileConverter.projitems*{0ac46a8e-8c0d-4ebe-b64a-4cc274e0ff38}*SharedItemsImports = 4
75+
..\SharedProjects\GltfExport.Entities\GltfExport.Entities.projitems*{0ac46a8e-8c0d-4ebe-b64a-4cc274e0ff38}*SharedItemsImports = 4
76+
..\SharedProjects\Utilities\Extensions.projitems*{0ac46a8e-8c0d-4ebe-b64a-4cc274e0ff38}*SharedItemsImports = 4
7277
..\SharedProjects\BabylonExport.Entities\BabylonExport.Entities.projitems*{2a678a75-f8c2-41ba-814a-53e611f5eb96}*SharedItemsImports = 13
78+
..\SharedProjects\Babylon2GLTF\Babylon2GLTF.projitems*{50780553-6248-463b-a0f3-f82c6ccec703}*SharedItemsImports = 4
79+
..\SharedProjects\BabylonExport.Entities\BabylonExport.Entities.projitems*{50780553-6248-463b-a0f3-f82c6ccec703}*SharedItemsImports = 4
80+
..\SharedProjects\BabylonFileConverter\BabylonFileConverter.projitems*{50780553-6248-463b-a0f3-f82c6ccec703}*SharedItemsImports = 4
81+
..\SharedProjects\GltfExport.Entities\GltfExport.Entities.projitems*{50780553-6248-463b-a0f3-f82c6ccec703}*SharedItemsImports = 4
82+
..\SharedProjects\Utilities\Extensions.projitems*{50780553-6248-463b-a0f3-f82c6ccec703}*SharedItemsImports = 4
7383
..\SharedProjects\Babylon2GLTF\Babylon2GLTF.projitems*{63ff7f8b-1802-4990-a252-6caf3d7c406d}*SharedItemsImports = 4
7484
..\SharedProjects\BabylonExport.Entities\BabylonExport.Entities.projitems*{63ff7f8b-1802-4990-a252-6caf3d7c406d}*SharedItemsImports = 4
7585
..\SharedProjects\BabylonFileConverter\BabylonFileConverter.projitems*{63ff7f8b-1802-4990-a252-6caf3d7c406d}*SharedItemsImports = 4

0 commit comments

Comments
 (0)