Skip to content
This repository was archived by the owner on Mar 30, 2019. It is now read-only.

Commit c411598

Browse files
committed
[Toolkit.Compiler] Revert to using offset matrices, as "improvised" bind poses didn't achieve the actual intent to
1. Effortlessly support additive animations 2. Share skinning matrices between multiple models Conflicts: Source/Toolkit/SharpDX.Toolkit/Graphics/ModelData.cs
1 parent 4fcd95c commit c411598

8 files changed

Lines changed: 34 additions & 156 deletions

File tree

Source/Toolkit/SharpDX.Toolkit.Compiler/Model/ModelCompiler.cs

Lines changed: 7 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,6 @@ private void ProcessScene()
198198
// Collect bones from mesh
199199
CollectSkinnedBones();
200200

201-
CalculateMeshOffsets();
202-
203201
registeredMeshParts = new List<ModelData.MeshPart>[scene.MeshCount];
204202

205203
CollectEmbeddedTextures(scene.Textures);
@@ -522,85 +520,6 @@ private void LinearKeyFrameReduction(LinkedList<ModelData.KeyFrame> keyFrames)
522520
}
523521
}
524522

525-
private Dictionary<Tuple<Mesh, Mesh>, Matrix> meshOffsets = new Dictionary<Tuple<Mesh, Mesh>, Matrix>();
526-
private Dictionary<Node, Mesh> referenceMeshes = new Dictionary<Node, Mesh>();
527-
528-
private void CalculateMeshOffsets()
529-
{
530-
// For each pair of meshes, get the difference of their offset transforms, based on one of their shared bones (if any)
531-
foreach (var mesh in scene.Meshes)
532-
{
533-
foreach (var otherMesh in scene.Meshes)
534-
{
535-
if (mesh == otherMesh)
536-
break;
537-
538-
if (mesh.HasBones && otherMesh.HasBones)
539-
{
540-
foreach (var bone in mesh.Bones)
541-
{
542-
foreach (var otherBone in otherMesh.Bones)
543-
{
544-
if (bone.Name == otherBone.Name)
545-
{
546-
var offset = ConvertMatrix(bone.OffsetMatrix) * Matrix.Invert(ConvertMatrix(otherBone.OffsetMatrix));
547-
meshOffsets[Tuple.Create(mesh, otherMesh)] = offset;
548-
meshOffsets[Tuple.Create(otherMesh, mesh)] = Matrix.Invert(offset);
549-
break;
550-
}
551-
}
552-
}
553-
}
554-
}
555-
}
556-
557-
// For each pair of meshes, get the difference of their offset transforms (if they are connected by a chain of offset transforms)
558-
foreach (var start in scene.Meshes)
559-
{
560-
foreach (var mid in scene.Meshes)
561-
{
562-
foreach (var end in scene.Meshes)
563-
{
564-
if (start == end || start == mid || mid == end)
565-
continue;
566-
567-
var startToEnd = Tuple.Create(start, end);
568-
var startToMid = Tuple.Create(start, mid);
569-
var midToEnd = Tuple.Create(mid, end);
570-
571-
if (meshOffsets.ContainsKey(startToEnd) ||
572-
!meshOffsets.ContainsKey(startToMid) ||
573-
!meshOffsets.ContainsKey(midToEnd))
574-
continue;
575-
576-
var offset = meshOffsets[startToMid] * meshOffsets[midToEnd];
577-
meshOffsets[startToEnd] = offset;
578-
meshOffsets[Tuple.Create(end, start)] = Matrix.Invert(offset);
579-
}
580-
}
581-
}
582-
583-
// Associate each bones with the first mesh that is connected to it by a chain of offset transforms
584-
foreach (var mesh in scene.Meshes)
585-
{
586-
foreach (var otherMesh in scene.Meshes)
587-
{
588-
if (otherMesh != mesh && !meshOffsets.ContainsKey(Tuple.Create(mesh, otherMesh)))
589-
continue;
590-
591-
if (otherMesh.HasBones)
592-
{
593-
foreach (var bone in otherMesh.Bones)
594-
{
595-
var boneNode = scene.RootNode.FindNode(bone.Name);
596-
if (!referenceMeshes.ContainsKey(boneNode))
597-
referenceMeshes.Add(boneNode, mesh);
598-
}
599-
}
600-
}
601-
}
602-
}
603-
604523
private void CollectSkinnedBones()
605524
{
606525
foreach (var mesh in scene.Meshes)
@@ -851,47 +770,29 @@ private ModelData.MeshPart Process(ModelData.Mesh mesh, Assimp.Mesh assimpMesh,
851770
var skinningIndices = new Int4[assimpMesh.VertexCount];
852771
var skinningWeights = new Vector4[assimpMesh.VertexCount];
853772

854-
Matrix meshBindTransform = Matrix.Identity;
855773
if (assimpMesh.HasBones)
856774
{
857775
for (int i = 0; i < assimpMesh.Bones.Length; i++)
858776
{
859777
var bone = assimpMesh.Bones[i];
860778
var boneNode = scene.RootNode.FindNode(bone.Name);
861779

862-
// If a bone is used by multiple meshes, their offset matrices may still be different, as the meshes could have additional
863-
// transformations in bind pose. We choose one mesh's bind pose as reference, and bake the difference into the current mesh's vertices.
864-
Mesh boneMesh = referenceMeshes[boneNode];
865-
if (boneMesh != assimpMesh)
866-
{
867-
meshBindTransform = meshOffsets[Tuple.Create(assimpMesh, boneMesh)];
868-
}
869-
870-
// Register each bone only once
871-
int boneIndex;
872-
if (!skinnedBones.TryGetValue(boneNode, out boneIndex))
780+
if (bone.HasVertexWeights)
873781
{
874-
boneIndex = model.SkinnedBones.Count;
875-
skinnedBones[boneNode] = boneIndex;
782+
var skinnedBoneIndex = meshPart.SkinnedBones.Count;
876783

877-
model.SkinnedBones.Add(new ModelData.SkinnedBone
784+
meshPart.SkinnedBones.Add(new ModelData.SkinnedBone
878785
{
879786
BoneIndex = skeletonNodes[boneNode],
880-
InverseBindTransform = Matrix.Invert(meshBindTransform) * ConvertMatrix(bone.OffsetMatrix)
787+
InverseBindTransform = ConvertMatrix(bone.OffsetMatrix)
881788
});
882-
}
883-
884-
// Add the bone index to the mesh part's local bone list
885-
meshPart.SkinnedBones.Add(boneIndex);
886789

887-
if (bone.HasVertexWeights)
888-
{
889790
for (int j = 0; j < bone.VertexWeightCount; j++)
890791
{
891792
var weights = bone.VertexWeights[j];
892793
var vertexSkinningCount = skinningCount[weights.VertexID];
893794

894-
skinningIndices[weights.VertexID][vertexSkinningCount] = i;
795+
skinningIndices[weights.VertexID][vertexSkinningCount] = skinnedBoneIndex;
895796

896797
skinningWeights[weights.VertexID][vertexSkinningCount] = weights.Weight;
897798

@@ -926,18 +827,16 @@ private ModelData.MeshPart Process(ModelData.Mesh mesh, Assimp.Mesh assimpMesh,
926827
var vertexStream = DataStream.Create(vertexBuffer.Buffer, true, true);
927828
for (int i = 0; i < assimpMesh.VertexCount; i++)
928829
{
929-
Vector3 defaultPosition = ConvertVector(assimpMesh.Vertices[i]);
930-
Vector3 position = Vector3.TransformCoordinate(defaultPosition, meshBindTransform);
830+
Vector3 position = ConvertVector(assimpMesh.Vertices[i]);
931831
vertexStream.Write(position);
932832

933833
// Store bounding points for BoundingSphere pre-calculation
934-
boundingPoints[currentBoundingPointIndex++] = assimpMesh.HasBones ? defaultPosition : position;
834+
boundingPoints[currentBoundingPointIndex++] = position;
935835

936836
// Add normals
937837
if (assimpMesh.HasNormals)
938838
{
939839
var normal = ConvertVector(assimpMesh.Normals[i]);
940-
Vector3.TransformNormal(ref normal, ref meshBindTransform, out normal);
941840
vertexStream.Write(normal);
942841
}
943842

@@ -981,10 +880,6 @@ private ModelData.MeshPart Process(ModelData.Mesh mesh, Assimp.Mesh assimpMesh,
981880
{
982881
var tangent = ConvertVector(assimpMesh.Normals[i]);
983882
var bitangent = ConvertVector(assimpMesh.Normals[i]);
984-
985-
Vector3.TransformNormal(ref tangent, ref meshBindTransform, out tangent);
986-
Vector3.TransformNormal(ref bitangent, ref meshBindTransform, out bitangent);
987-
988883
vertexStream.Write(tangent);
989884
vertexStream.Write(bitangent);
990885
}

Source/Toolkit/SharpDX.Toolkit.Graphics/Model.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ namespace SharpDX.Toolkit.Graphics
3030
[ContentReader(typeof(ModelContentReader))]
3131
public class Model : Component
3232
{
33+
private static Matrix[] sharedDrawBones;
34+
3335
public MaterialCollection Materials;
3436

3537
public ModelBoneCollection Bones;
3638

37-
public ModelSkinnedBoneCollection SkinnedBones;
38-
3939
public ModelMeshCollection Meshes;
4040

4141
public ModelAnimationCollection Animations;
@@ -161,17 +161,14 @@ public unsafe void Draw(GraphicsDevice context, Matrix world, Matrix view, Matri
161161
{
162162
int count = Meshes.Count;
163163
int boneCount = Bones.Count;
164-
Matrix* localSharedDrawBoneMatrices = stackalloc Matrix[boneCount]; // TODO use a global cache as BoneCount could generate a StackOverflow
165164

166-
CopyAbsoluteBoneTransformsTo(new IntPtr(localSharedDrawBoneMatrices));
167-
168-
var skinningTransforms = new Matrix[SkinnedBones.Count];
169-
for (int i = 0; i < SkinnedBones.Count; i++)
165+
if (sharedDrawBones == null || sharedDrawBones.Length < boneCount)
170166
{
171-
int boneIndex = SkinnedBones[i].Bone.Index;
172-
Matrix.Multiply(ref SkinnedBones[i].InverseBindTransform, ref localSharedDrawBoneMatrices[boneIndex], out skinningTransforms[i]);
167+
sharedDrawBones = new Matrix[boneCount];
173168
}
174169

170+
CopyAbsoluteBoneTransformsTo(sharedDrawBones);
171+
175172
var defaultParametersContext = default(EffectDefaultParametersContext);
176173

177174
for (int i = 0; i < count; i++)
@@ -189,7 +186,7 @@ public unsafe void Draw(GraphicsDevice context, Matrix world, Matrix view, Matri
189186
else
190187
{
191188
Matrix worldTranformed;
192-
Matrix.Multiply(ref localSharedDrawBoneMatrices[index], ref world, out worldTranformed);
189+
Matrix.Multiply(ref sharedDrawBones[index], ref world, out worldTranformed);
193190
effectOverride.DefaultParameters.Apply(ref defaultParametersContext, ref worldTranformed, ref view, ref projection);
194191
}
195192
}
@@ -204,7 +201,7 @@ public unsafe void Draw(GraphicsDevice context, Matrix world, Matrix view, Matri
204201
}
205202

206203
Matrix worldTranformed;
207-
Matrix.Multiply(ref localSharedDrawBoneMatrices[index], ref world, out worldTranformed);
204+
Matrix.Multiply(ref sharedDrawBones[index], ref world, out worldTranformed);
208205

209206
var matrices = effect as IEffectMatrices;
210207
if (matrices == null)
@@ -220,11 +217,10 @@ public unsafe void Draw(GraphicsDevice context, Matrix world, Matrix view, Matri
220217
}
221218
}
222219

223-
mesh.Draw(context, skinningTransforms, effectOverride);
220+
mesh.Draw(context, sharedDrawBones, effectOverride);
224221
}
225222
}
226223

227-
228224
/// <summary>
229225
/// Calculates the bounds of this model.
230226
/// </summary>
@@ -243,16 +239,20 @@ public unsafe BoundingSphere CalculateBounds(Matrix world)
243239
{
244240
int count = Meshes.Count;
245241
int boneCount = Bones.Count;
246-
Matrix* localSharedDrawBoneMatrices = stackalloc Matrix[boneCount]; // TODO use a global cache as BoneCount could generate a StackOverflow
247242

248-
CopyAbsoluteBoneTransformsTo(new IntPtr(localSharedDrawBoneMatrices));
243+
if (sharedDrawBones == null || sharedDrawBones.Length < boneCount)
244+
{
245+
sharedDrawBones = new Matrix[boneCount];
246+
}
247+
248+
CopyAbsoluteBoneTransformsTo(sharedDrawBones);
249249
var defaultSphere = new BoundingSphere(Vector3.Zero, 0.0f);
250250
for (int i = 0; i < count; i++)
251251
{
252252
var mesh = Meshes[i];
253253
int index = mesh.ParentBone.Index;
254254
Matrix result;
255-
Matrix.Multiply(ref localSharedDrawBoneMatrices[index], ref world, out result);
255+
Matrix.Multiply(ref sharedDrawBones[index], ref world, out result);
256256

257257
var meshSphere = mesh.BoundingSphere;
258258
Vector3.TransformCoordinate(ref meshSphere.Center, ref result, out meshSphere.Center);

Source/Toolkit/SharpDX.Toolkit.Graphics/ModelMesh.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ public void Draw(GraphicsDevice context, Matrix[] boneTransforms, Effect effectO
8282
var transforms = new Matrix[boneCount];
8383
for (int j = 0; j < boneCount; j++)
8484
{
85-
transforms[j] = boneTransforms[part.SkinnedBones[j]];
85+
var skinnedBone = part.SkinnedBones[j];
86+
Matrix.Multiply(ref skinnedBone.OffsetMatrix, ref boneTransforms[skinnedBone.Bone.Index], out transforms[j]);
8687
}
8788

8889
skinnedEffect.SetBoneTransforms(transforms);

Source/Toolkit/SharpDX.Toolkit.Graphics/ModelMeshPart.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ public class ModelMeshPart : ComponentBase
5858
public PropertyCollection Properties;
5959

6060
/// <summary>
61-
/// Indices of the models skinned bones that are affecting this part.
61+
/// The skinned bones that are affecting this mesh part.
6262
/// </summary>
63-
public List<int> SkinnedBones;
63+
public ModelSkinnedBoneCollection SkinnedBones;
6464

6565
/// <summary>
6666
/// Gets a value indicating whether this instance contains skinning information.

Source/Toolkit/SharpDX.Toolkit.Graphics/ModelReader.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,6 @@ protected virtual void ReadModel(ref Model model)
228228
ReadBones(ref model.Bones);
229229
EndChunk();
230230

231-
// Skinned Bones section
232-
BeginChunk("SKIN");
233-
ReadSkinnedBones(ref model.SkinnedBones);
234-
EndChunk();
235-
236231
// Mesh section
237232
BeginChunk("MESH");
238233
ReadMeshes(ref model.Meshes);
@@ -465,7 +460,7 @@ protected virtual void ReadSkinnedBone(ref ModelSkinnedBone skinnedBone)
465460
}
466461
skinnedBone.Bone = Model.Bones[boneIndex];
467462

468-
Serialize(ref skinnedBone.InverseBindTransform);
463+
Serialize(ref skinnedBone.OffsetMatrix);
469464
}
470465

471466
protected virtual void ReadMesh(ref ModelMesh mesh)
@@ -508,7 +503,7 @@ protected virtual void ReadMeshPart(ref ModelMeshPart meshPart)
508503
meshPart.VertexBuffer = GetFromList(vertexBufferRange, CurrentMesh.VertexBuffers);
509504

510505
// Skinned bones
511-
Serialize(ref meshPart.SkinnedBones, Serialize);
506+
ReadSkinnedBones(ref meshPart.SkinnedBones);
512507

513508
// Properties
514509
ReadProperties(ref meshPart.Properties);

Source/Toolkit/SharpDX.Toolkit.Graphics/ModelSkinnedBone.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,8 @@ namespace SharpDX.Toolkit.Graphics
2222
{
2323
public class ModelSkinnedBone : ComponentBase
2424
{
25-
public int Index;
26-
2725
public ModelBone Bone;
2826

29-
public Matrix InverseBindTransform;
27+
public Matrix OffsetMatrix;
3028
}
3129
}

Source/Toolkit/SharpDX.Toolkit/Graphics/ModelData.MeshPart.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public sealed class MeshPart : CommonData, IDataSerializable
3535
public MeshPart()
3636
{
3737
Properties = new PropertyCollection();
38-
SkinnedBones = new List<int>();
38+
SkinnedBones = new List<SkinnedBone>();
3939
}
4040

4141
/// <summary>
@@ -54,9 +54,9 @@ public MeshPart()
5454
public BufferRange VertexBufferRange;
5555

5656
/// <summary>
57-
/// Gets the index of the models skinned bones for each bone weight
57+
/// Gets the skinned bones.
5858
/// </summary>
59-
public List<int> SkinnedBones;
59+
public List<SkinnedBone> SkinnedBones;
6060

6161
/// <summary>
6262
/// The attributes attached to this mesh part.
@@ -68,7 +68,7 @@ void IDataSerializable.Serialize(BinarySerializer serializer)
6868
serializer.Serialize(ref MaterialIndex);
6969
serializer.Serialize(ref IndexBufferRange);
7070
serializer.Serialize(ref VertexBufferRange);
71-
serializer.Serialize(ref SkinnedBones, serializer.Serialize);
71+
serializer.Serialize(ref SkinnedBones);
7272
serializer.Serialize(ref Properties);
7373
}
7474
}

Source/Toolkit/SharpDX.Toolkit/Graphics/ModelData.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public ModelData()
4444
Textures = new List<byte[]>();
4545
Materials = new List<Material>();
4646
Bones = new List<Bone>();
47-
SkinnedBones = new List<SkinnedBone>();
4847
Meshes = new List<Mesh>();
4948
Animations = new List<Animation>();
5049
Attributes = new PropertyCollection();
@@ -70,11 +69,6 @@ public ModelData()
7069
/// </summary>
7170
public List<Bone> Bones;
7271

73-
/// <summary>
74-
/// Gets the bones used to perform skinning animation with this model.
75-
/// </summary>
76-
public List<SkinnedBone> SkinnedBones;
77-
7872
/// <summary>
7973
/// Gets the mesh of this model.
8074
/// </summary>
@@ -226,11 +220,6 @@ void IDataSerializable.Serialize(BinarySerializer serializer)
226220
serializer.Serialize(ref Bones);
227221
serializer.EndChunk();
228222

229-
// Skinned Bones section
230-
serializer.BeginChunk("SKIN");
231-
serializer.Serialize(ref SkinnedBones);
232-
serializer.EndChunk();
233-
234223
// Mesh section
235224
serializer.BeginChunk("MESH");
236225
serializer.Serialize(ref Meshes);

0 commit comments

Comments
 (0)