Skip to content

Commit 1bf7a27

Browse files
authored
Update root bone animation matrix (#1027)
Update root bone animation matrix according the on set into the bone
1 parent fb062fa commit 1bf7a27

File tree

5 files changed

+56
-19
lines changed

5 files changed

+56
-19
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Linq;
6+
using Utilities;
67

78
namespace Max2Babylon
89
{

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

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,24 @@
22
using System.Collections.Generic;
33
using Autodesk.Max;
44
using BabylonExport.Entities;
5+
using Utilities;
6+
57

68
namespace Max2Babylon
79
{
10+
using BoneSearchResult = Tuple<List<IIGameNode>, RootBoneTransformationType>;
11+
12+
internal enum RootBoneTransformationType
13+
{
14+
unknown, local,world
15+
}
16+
17+
18+
819
partial class BabylonExporter
920
{
21+
internal static readonly BoneSearchResult EmptyBoneSearchResult = new BoneSearchResult(new List<IIGameNode>(), RootBoneTransformationType.unknown);
22+
1023
readonly List<IIGameSkin> skins = new List<IIGameSkin>();
1124

1225
private bool IsSkinEqualTo(IIGameSkin skin1, IIGameSkin skin2)
@@ -50,13 +63,13 @@ private List<IIGameNode> GetBones(IIGameSkin skin)
5063
/// <returns>
5164
/// All nodes needed for the skeleton hierarchy
5265
/// </returns>
53-
private Dictionary<IIGameSkin, Tuple<List<IIGameNode>, float[]>> relevantNodesBySkin = new Dictionary<IIGameSkin, Tuple<List<IIGameNode>, float[]>>();
54-
private Tuple<List<IIGameNode>, float[]> GetSkinnedBones(IIGameSkin skin)
66+
private Dictionary<IIGameSkin, BoneSearchResult> relevantNodesBySkin = new Dictionary<IIGameSkin, BoneSearchResult>();
67+
private Tuple<List<IIGameNode>, RootBoneTransformationType> GetSkinnedBones(IIGameSkin skin)
5568
{
5669

5770
if (skin == null)
5871
{
59-
return new Tuple<List<IIGameNode>, float[]>(new List<IIGameNode>(),null);
72+
return EmptyBoneSearchResult;
6073
}
6174

6275
int logRank = 2;
@@ -72,14 +85,14 @@ private Tuple<List<IIGameNode>, float[]> GetSkinnedBones(IIGameSkin skin)
7285
if (bones.Count == 0)
7386
{
7487
RaiseWarning("Skin has no bones.", logRank);
75-
return new Tuple<List<IIGameNode>, float[]>(new List<IIGameNode>(), null);
88+
return EmptyBoneSearchResult;
7689
}
7790

7891
if (bones.Contains(null))
7992
{
8093
RaiseError("Skin has bones that are outside of the exported hierarchy.", logRank);
8194
RaiseError("The skin cannot be exported", logRank);
82-
return new Tuple<List<IIGameNode>, float[]>(new List<IIGameNode>(), null);
95+
return EmptyBoneSearchResult;
8396
}
8497

8598
List<IIGameNode> allHierarchyNodes = null;
@@ -90,12 +103,12 @@ private Tuple<List<IIGameNode>, float[]> GetSkinnedBones(IIGameSkin skin)
90103
RaiseError($"More than one root node for the skin. The skeleton bones need to be part of the same hierarchy.", logRank);
91104
RaiseError($"The skin cannot be exported", logRank);
92105

93-
return new Tuple<List<IIGameNode>, float[]>(new List<IIGameNode>(), null);
106+
return EmptyBoneSearchResult;
94107
}
95108

96109
allHierarchyNodes.Add(lowestCommonAncestor);
97110

98-
float[] rootTransformation = null;
111+
RootBoneTransformationType tt = RootBoneTransformationType.world;
99112

100113
// Babylon format assumes skeleton root is at origin, add any additional node parents from the lowest common ancestor to the scene root to the skeleton hierarchy.
101114
if (lowestCommonAncestor.NodeParent != null)
@@ -106,16 +119,14 @@ private Tuple<List<IIGameNode>, float[]> GetSkinnedBones(IIGameSkin skin)
106119
// in this case, we stop to stack commonAncestor and we set the root transformation Matrix as Local.
107120
if(HasSkinAsChild(lowestCommonAncestor.NodeParent, skin))
108121
{
109-
rootTransformation = lowestCommonAncestor.GetLocalTM(0).ToArray();
122+
tt = RootBoneTransformationType.local;
110123
break;
111124
}
112125
lowestCommonAncestor = lowestCommonAncestor.NodeParent;
113126
allHierarchyNodes.Add(lowestCommonAncestor);
114127
} while (lowestCommonAncestor.NodeParent != null);
115128
}
116129

117-
rootTransformation = rootTransformation ?? lowestCommonAncestor.GetWorldTM(0).ToArray();
118-
119130
// starting from the root, sort the nodes by depth first (add the children before the siblings)
120131
List<IIGameNode> sorted = new List<IIGameNode>();
121132
Stack<IIGameNode> siblings = new Stack<IIGameNode>(); // keep the siblings in a LIFO list to add them after the children
@@ -146,7 +157,7 @@ private Tuple<List<IIGameNode>, float[]> GetSkinnedBones(IIGameSkin skin)
146157
}
147158
}
148159
}
149-
var result = new Tuple<List<IIGameNode>, float[]>(sorted, rootTransformation);
160+
var result = new BoneSearchResult(sorted, tt);
150161

151162
relevantNodesBySkin.Add(skin, result); // Stock the result for optimization
152163

@@ -356,7 +367,7 @@ private BabylonBone[] ExportBones(IIGameSkin skin)
356367
{
357368
List<BabylonBone> bones = new List<BabylonBone>();
358369
List<int> nodeIndices = GetNodeIndices(skin);
359-
Tuple<List<IIGameNode>,float[]> revelantNodes = GetSkinnedBones(skin);
370+
BoneSearchResult revelantNodes = GetSkinnedBones(skin);
360371

361372
var rootMatrix = revelantNodes.Item2;
362373

@@ -365,15 +376,19 @@ private BabylonBone[] ExportBones(IIGameSkin skin)
365376
int parentIndex = (node.NodeParent == null) ? -1 : nodeIndices.IndexOf(node.NodeParent.NodeID);
366377

367378
string boneId = node.MaxNode.GetGuid().ToString();
379+
380+
// this function is select the correct matrix depending hierarchy case
381+
Func<int, float[]> getMatrix = (i) => parentIndex == -1 ? (revelantNodes.Item2 == RootBoneTransformationType.world ? node.GetWorldTM(i).ToArray() : node.GetLocalTM(i).ToArray()) : node.GetLocalTM(i).ToArray();
382+
368383
// create the bone
369384
BabylonBone bone = new BabylonBone()
370385
{
371-
id = (isGltfExported)?boneId:boneId + "-bone",// the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs
372-
parentNodeId = (parentIndex!=-1)?node.NodeParent.MaxNode.GetGuid().ToString():null,
386+
id = (isGltfExported) ? boneId : boneId + "-bone",// the suffix "-bone" is added in babylon export format to assure the uniqueness of IDs
387+
parentNodeId = (parentIndex != -1) ? node.NodeParent.MaxNode.GetGuid().ToString() : null,
373388
name = node.Name,
374389
index = nodeIndices.IndexOf(node.NodeID),
375390
parentBoneIndex = parentIndex,
376-
matrix = (parentIndex == -1) ? rootMatrix : node.GetLocalTM(0).ToArray()
391+
matrix = MathUtilities.CleanEpsilon(getMatrix(0))
377392
};
378393

379394
// Apply unit conversion factor to meter
@@ -387,9 +402,7 @@ private BabylonBone[] ExportBones(IIGameSkin skin)
387402
// export its animation
388403
var babylonAnimation = ExportMatrixAnimation("_matrix", key =>
389404
{
390-
IGMatrix mat = node.GetLocalTM(key);
391-
392-
float[] matrix = mat.ToArray();
405+
float[] matrix = MathUtilities.CleanEpsilon(getMatrix(key));
393406

394407
// Apply unit conversion factor to meter
395408
// Affect translation only

SharedProjects/BabylonExport.Entities/BabylonAnimationKey.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,23 @@ namespace BabylonExport.Entities
99
public class BabylonAnimationKey : IComparable<BabylonAnimationKey>, ICloneable
1010
{
1111
private float _f;
12+
private float[] _values;
1213

1314
[DataMember]
1415
// guard for negative value.
1516
public float frame { get => _f; set => _f = value < 0 ? 0 : value; }
1617

1718
[DataMember]
18-
public float[] values { get; set; }
19+
public float[] values {
20+
get
21+
{
22+
return _values;
23+
}
24+
set
25+
{
26+
_values = MathUtilities.CleanEpsilon(value);
27+
}
28+
}
1929

2030
public object Clone()
2131
{

SharedProjects/BabylonExport.Entities/BabylonMatrix.cs

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

34
namespace BabylonExport.Entities
45
{
@@ -358,5 +359,6 @@ public BabylonVector3 TransformCoordinatesFromFloatsToRef(float x, float y, floa
358359
result.Z = rz;
359360
return result;
360361
}
362+
361363
}
362364
}

SharedProjects/Utilities/MathUtilities.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,16 @@ public static BabylonMatrix ComputeTextureTransformMatrix(BabylonVector3 pivotCe
9191
.multiply(BabylonMatrix.Translation(pivotCenter));
9292
return transformMatrix;
9393
}
94+
95+
96+
public static float[] CleanEpsilon(float[] data)
97+
{
98+
for (int i = 0; i != data.Length; i++)
99+
{
100+
data[i] = Math.Abs(data[i]) <= MathUtilities.Epsilon ? 0 : data[i];
101+
data[i] = Math.Abs(1.0 - data[i]) <= MathUtilities.Epsilon ? 1 : data[i];
102+
}
103+
return data;
104+
}
94105
}
95106
}

0 commit comments

Comments
 (0)