private void WriteBone(XmlWriter file, SBBone bone) { file.WriteStartElement("SBBone"); file.WriteAttributeString("Name", bone.Name); file.WriteAttributeString("TranslateX", "" + bone.Translation.X); file.WriteAttributeString("TranslateY", "" + bone.Translation.Y); file.WriteAttributeString("TranslateZ", "" + bone.Translation.Z); file.WriteAttributeString("RotationEulerX", "" + bone.RotationEuler.X); file.WriteAttributeString("RotationEulerY", "" + bone.RotationEuler.Y); file.WriteAttributeString("RotationEulerZ", "" + bone.RotationEuler.Z); if ("" + bone.Scale.X != "1") { file.WriteAttributeString("ScaleX", "" + bone.Scale.X); } if ("" + bone.Scale.Y != "1") { file.WriteAttributeString("ScaleY", "" + bone.Scale.Y); } if ("" + bone.Scale.Z != "1") { file.WriteAttributeString("ScaleZ", "" + bone.Scale.Z); } foreach (var child in bone.Children) { WriteBone(file, child); } file.WriteEndElement(); }
private bool HandleAttribute(XmlReader reader, SBBone bone, string attribute, bool required = true) { string value = reader.GetAttribute(attribute); float val; if (value == null) { if (required) { SBConsole.WriteLine("Expected attribute \"" + attribute + "\""); } return(false); } else if (!float.TryParse(value, out val)) { SBConsole.WriteLine("Failed to parse attribute \"" + attribute + "\""); return(false); } if (!WriteValue(bone, attribute, val)) { return(false); } return(true); }
/// <summary> /// /// </summary> /// <param name="limb"></param> /// <param name="parent"></param> /// <returns></returns> private static SBBone ConvertLimbToSBBone(FbxLimbNode limb, SBBone parent = null) { SBBone bone = new SBBone(); bone.Name = limb.Name; bone.Transform = Matrix4.Identity; //who needs precision anyways bone.Translation = new Vector3((float)limb.LclTranslation.X, (float)limb.LclTranslation.Y, (float)limb.LclTranslation.Z); bone.RotationEuler = new Vector3((float)limb.LclRotation.X * DegToRag, (float)limb.LclRotation.Y * DegToRag, (float)limb.LclRotation.Z * DegToRag); bone.Scale = new Vector3((float)limb.LclScaling.X, (float)limb.LclScaling.Y, (float)limb.LclScaling.Z); if (bone.Scale == new Vector3(100)) { bone.Scale /= 100; } if (parent != null) { bone.Parent = parent; } //process children foreach (var child in limb.Children) { ConvertLimbToSBBone(child, bone); } return(bone); }
public static void QueueBones(SBBone b, Queue <SBBone> q, SBSkeleton Skeleton) { q.Enqueue(b); foreach (SBBone c in b.Children) { QueueBones(c, q, Skeleton); } }
private void UpdateSBSkeleton(SBSkeleton skeleton, Dictionary <String, SBTransformAnimation> transformNodes, int frame) { foreach (var nodeName in transformNodes.Keys) { SBTransformAnimation a = transformNodes[nodeName]; SBBone bone = skeleton[nodeName]; bone.AnimatedTransform = a.GetTransformAt(frame, bone); } }
public void BindBone(SBBone Bone) { NameLabel.Text = Bone.Name; X.Bind(Bone, "X"); Y.Bind(Bone, "Y"); Z.Bind(Bone, "Z"); RX.Bind(Bone, "RX"); RY.Bind(Bone, "RY"); RZ.Bind(Bone, "RZ"); SX.Bind(Bone, "SX"); SY.Bind(Bone, "SY"); SZ.Bind(Bone, "SZ"); }
public void SetBone(SBBone Bone) { BoneName.Text = Bone.Name; X.BindValue(Bone, "X"); Y.BindValue(Bone, "Y"); Z.BindValue(Bone, "Z"); RX.BindValue(Bone, "RX"); RY.BindValue(Bone, "RY"); RZ.BindValue(Bone, "RZ"); SX.BindValue(Bone, "SX"); SY.BindValue(Bone, "SY"); SZ.BindValue(Bone, "SZ"); }
private void UpdateBone(SBSkeleton skeleton, SBBone bone) { skeleton[bone.Name].X = bone.X; skeleton[bone.Name].Y = bone.Y; skeleton[bone.Name].Z = bone.Z; skeleton[bone.Name].RX = bone.RX; skeleton[bone.Name].RY = bone.RY; skeleton[bone.Name].RZ = bone.RZ; foreach (var child in bone.Children) { UpdateBone(skeleton, child); } }
private void ReadTransformAnimations(Anim animFile, AnimGroup animGroup, SBAnimation animation) { var decoder = new SsbhAnimTrackDecoder(animFile); foreach (AnimNode animNode in animGroup.Nodes) { SBTransformAnimation tfrmAnim = new SBTransformAnimation() { Name = animNode.Name }; SBTransformTrack X = new SBTransformTrack(SBTrackType.TranslateX); SBTransformTrack Y = new SBTransformTrack(SBTrackType.TranslateY); SBTransformTrack Z = new SBTransformTrack(SBTrackType.TranslateZ); SBTransformTrack RX = new SBTransformTrack(SBTrackType.RotateX); SBTransformTrack RY = new SBTransformTrack(SBTrackType.RotateY); SBTransformTrack RZ = new SBTransformTrack(SBTrackType.RotateZ); SBTransformTrack SX = new SBTransformTrack(SBTrackType.ScaleX); SBTransformTrack SY = new SBTransformTrack(SBTrackType.ScaleY); SBTransformTrack SZ = new SBTransformTrack(SBTrackType.ScaleZ); SBTransformTrack CompensateScale = new SBTransformTrack(SBTrackType.CompensateScale); tfrmAnim.Tracks.AddRange(new SBTransformTrack[] { X, Y, Z, RX, RY, RZ, SX, SY, SZ, CompensateScale }); foreach (AnimTrack track in animNode.Tracks) { object[] Transform = decoder.ReadTrack(track); if (track.Name.Equals("Transform")) { for (int i = 0; i < Transform.Length; i++) { AnimTrackTransform t = (AnimTrackTransform)Transform[i]; SBBone transform = new SBBone(); transform.Transform = GetMatrix((AnimTrackTransform)Transform[i]); X.AddKey(i, transform.X); Y.AddKey(i, transform.Y); Z.AddKey(i, transform.Z); RX.AddKey(i, transform.RX); RY.AddKey(i, transform.RY); RZ.AddKey(i, transform.RZ); SX.AddKey(i, transform.SX); SY.AddKey(i, transform.SY); SZ.AddKey(i, transform.SZ); CompensateScale.AddKey(i, t.CompensateScale); } } } animation.TransformNodes.Add(tfrmAnim); } }
public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton) { SMD file = new SMD(); var bonelist = new List <SBBone>(skeleton.Bones); foreach (var bone in bonelist) { file.nodes.Add(new SMDNode() { Name = bone.Name, ID = bonelist.IndexOf(bone), ParentID = bonelist.IndexOf(bone.Parent) }); } for (int i = 0; i < animation.FrameCount; i++) { var group = new SMDSkeletonFrame(); group.time = i; file.skeleton.Add(group); foreach (var bone in bonelist) { bool found = false; foreach (var animbone in animation.TransformNodes) { if (animbone.Name.Equals(bone.Name)) { var tempBone = new SBBone(); tempBone.Transform = animbone.GetTransformAt(i, skeleton); group.skeletons.Add(new SMDSkeleton() { BoneID = bonelist.IndexOf(bone), Position = tempBone.Translation, Rotation = tempBone.RotationEuler }); found = true; break; } } if (!found) { group.skeletons.Add(new SMDSkeleton() { BoneID = bonelist.IndexOf(bone), Position = bone.Translation, Rotation = bone.RotationEuler }); } } } file.Save(FileName); }
private List <Bone> CreateChildBones(SBBone head, Bone parent) { List <Bone> bones = new List <Bone>(); foreach (var tail in head.Children) { Bone bone = new Bone(); bone.parent = parent; bone.head = head; bone.tail = tail; bone.children = CreateChildBones(tail, bone); bones.Add(bone); } return(bones); }
private SBBone ReadBone(XmlReader reader, SBBone bone) { SBBone newBone = new SBBone(); newBone.Transform = Matrix4.Identity; if (!reader.ReadToFollowing("SBBone") || reader.NodeType != XmlNodeType.Element || reader.Name != "SBBone") { SBConsole.WriteLine("Expected bone element"); return(null); } string name = reader.GetAttribute("Name"); if (name != bone.Name) { SBConsole.WriteLine("Expected bone definition for " + bone.Name + ", received \"" + name + "\""); return(null); } newBone.Name = bone.Name; if (!HandleAttribute(reader, newBone, "TranslateX") || !HandleAttribute(reader, newBone, "TranslateY") || !HandleAttribute(reader, newBone, "TranslateZ") || !HandleAttribute(reader, newBone, "RotationEulerX") || !HandleAttribute(reader, newBone, "RotationEulerY") || !HandleAttribute(reader, newBone, "RotationEulerZ")) { return(null); } // Optional attributes HandleAttribute(reader, newBone, "ScaleX", false); HandleAttribute(reader, newBone, "ScaleY", false); HandleAttribute(reader, newBone, "ScaleZ", false); foreach (var child in bone.Children) { SBBone newChild = ReadBone(reader, child); if (newChild == null) { return(null); } newBone.AddChild(newChild); } return(newBone); }
/// <summary> /// Gets matrix4 transform for model node /// </summary> /// <param name="model"></param> /// <returns></returns> private static Matrix4 GetModelTransform(FbxModel model) { SBBone bone = new SBBone(); bone.Transform = Matrix4.Identity; bone.Scale = new Vector3((float)model.LclScaling.X, (float)model.LclScaling.Y, (float)model.LclScaling.Z); bone.RotationEuler = new Vector3((float)model.LclRotation.X * DegToRag, (float)model.LclRotation.Y * DegToRag, (float)model.LclRotation.Z * DegToRag); bone.Translation = new Vector3((float)model.LclTranslation.X, (float)-model.LclTranslation.Z, (float)model.LclTranslation.Y); if (bone.Scale == new Vector3(100)) { bone.Scale /= 100; } return(Matrix4.CreateScale(bone.Scale) * Matrix4.CreateFromQuaternion(bone.RotationQuaternion) * Matrix4.CreateTranslation(bone.Translation)); }
private void Read(XmlReader reader, SBSkeleton skeleton) { List <SBBone> roots = new List <SBBone>(); foreach (var bone in skeleton.Roots) { SBBone newBone = ReadBone(reader, bone); if (newBone == null) { SBConsole.WriteLine("Failed to read XML skeleton."); return; } roots.Add(newBone); } UpdateSkeleton(skeleton, roots); }
private bool WriteValue(SBBone bone, string attribute, float value) { if (attribute.Equals("TranslateX")) { bone.X = value; } else if (attribute.Equals("TranslateY")) { bone.Y = value; } else if (attribute.Equals("TranslateZ")) { bone.Z = value; } else if (attribute.Equals("RotationEulerX")) { bone.RX = value; } else if (attribute.Equals("RotationEulerY")) { bone.RY = value; } else if (attribute.Equals("RotationEulerZ")) { bone.RZ = value; } else if (attribute.Equals("ScaleX")) { bone.SX = value; } else if (attribute.Equals("ScaleY")) { bone.SY = value; } else if (attribute.Equals("ScaleZ")) { bone.SZ = value; } else { SBConsole.WriteLine("Internal failure"); return(false); } return(true); }
private static float GetValue(Matrix4 transform, ControlType ctype, TrackType ttype) { SBBone temp = new SBBone(); temp.Transform = transform; switch (ctype) { case ControlType.rotate: return(GetTrackValue(temp.RotationEuler, ttype)); case ControlType.scale: return(GetTrackValue(temp.Scale, ttype)); case ControlType.translate: return(GetTrackValue(temp.Translation, ttype)); } return(0); }
/// <summary> /// /// </summary> /// <param name="FileName"></param> /// <param name="animation"></param> /// <param name="skeleton"></param> public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton) { SEAnim seOut = new SEAnim(); //init new SEAnim foreach (var node in animation.TransformNodes) //iterate through each node { for (int i = 0; i < animation.FrameCount; i++) { SBBone temp = new SBBone(); temp.Transform = node.GetTransformAt(i, skeleton); seOut.AddTranslationKey(node.Name, i, temp.X, temp.Y, temp.Z); seOut.AddRotationKey(node.Name, i, temp.RotationQuaternion.X, temp.RotationQuaternion.Y, temp.RotationQuaternion.Z, temp.RotationQuaternion.W); seOut.AddScaleKey(node.Name, i, temp.SX, temp.SY, temp.SZ); } } seOut.Write(FileName); //write it! }
private static float GetValue(Matrix4 transform, ControlType ctype, TrackType ttype) { SBBone temp = new SBBone(); temp.Transform = transform; float rotationTransform = (float)(MayaSettings.UseRadians ? 1 : (180 / Math.PI)); switch (ctype) { case ControlType.rotate: return(GetTrackValue(temp.RotationEuler, ttype) * rotationTransform); case ControlType.scale: return(GetTrackValue(temp.Scale, ttype)); case ControlType.translate: return(GetTrackValue(temp.Translation, ttype)); } return(0); }
private void CreateMesh() { Mesh.Clear(); if (RootJOBJ == null) { return; } var dobjs = GetDOBJS(); var jobjs = RootJOBJ.BreathFirstList;// GetAllOfType<HSD_JOBJ>(RootJOBJ); foreach (var dobj in dobjs) { //SBConsole.WriteLine(dobj + " " + dobj.List.Count); SBBone parent = null; if (Skeleton.Bones.Length > 0) { parent = Skeleton.Bones[0]; } foreach (var b in Skeleton.Bones) { if (b is SBHsdBone bone) { if (bone.GetJOBJ().Dobj != null) { if (bone.GetJOBJ().Dobj.List.Contains(dobj)) { parent = b; break; } } } } var mesh = new SBHsdMesh(dobj, parent); mesh.Name = $"DOBJ_{Mesh.Count}"; Mesh.Add(mesh); } }
/// <summary> /// /// </summary> public void ConvertRotationToEuler(int FrameCount) { if (!UseQuat) { return; } var xtrack = Tracks.Find(e => e.Type == SBTrackType.RotateX); var ytrack = Tracks.Find(e => e.Type == SBTrackType.RotateY); var ztrack = Tracks.Find(e => e.Type == SBTrackType.RotateZ); var wtrack = Tracks.Find(e => e.Type == SBTrackType.RotateW); SBTransformTrack eulX = new SBTransformTrack(SBTrackType.RotateX); SBTransformTrack eulY = new SBTransformTrack(SBTrackType.RotateY); SBTransformTrack eulZ = new SBTransformTrack(SBTrackType.RotateZ); var dummyBone = new SBBone(); dummyBone.Transform = Matrix4.Identity; for (int i = 0; i < FrameCount; i++) { var key = GetTransformAt(i, dummyBone); var eul = Tools.CrossMath.ToEulerAngles(key.ExtractRotation().Inverted()); eulX.AddKey(i, eul.X); eulY.AddKey(i, eul.Y); eulZ.AddKey(i, eul.Z); } Tracks.Remove(xtrack); Tracks.Remove(ytrack); Tracks.Remove(ztrack); Tracks.Remove(wtrack); Tracks.Add(eulX); Tracks.Add(eulY); Tracks.Add(eulZ); }
private static AnimTrackTransform MatrixToTransform(Matrix4 matrix) { SBBone temp = new SBBone(); temp.Transform = matrix; var t = new AnimTrackTransform() { X = temp.X, Y = temp.Y, Z = temp.Z, Rx = temp.RotationQuaternion.X, Ry = temp.RotationQuaternion.Y, Rz = temp.RotationQuaternion.Z, Rw = temp.RotationQuaternion.W, Sx = temp.SX, Sy = temp.SY, Sz = temp.SZ }; return(t); }
public static SBSkeleton Open(string FileName, SBScene Scene) { SsbhFile File; if (Ssbh.TryParseSsbhFile(FileName, out File)) { if (File is Skel skel) { var Skeleton = new SBSkeleton(); Scene.Skeleton = Skeleton; Dictionary <int, SBBone> idToBone = new Dictionary <int, SBBone>(); Dictionary <SBBone, int> needParent = new Dictionary <SBBone, int>(); foreach (var b in skel.BoneEntries) { SBBone bone = new SBBone(); bone.Name = b.Name; bone.Type = b.Type; bone.Transform = Skel_to_TKMatrix(skel.Transform[b.Id]); idToBone.Add(b.Id, bone); if (b.ParentId == -1) { Skeleton.AddRoot(bone); } else { needParent.Add(bone, b.ParentId); } } foreach (var v in needParent) { v.Key.Parent = idToBone[v.Value]; } return(Skeleton); } } return(null); }
public void ExportSBAnimation(string FileName, SBAnimation animation, SBSkeleton skeleton) { SEAnim seOut = new SEAnim(); //init new SEAnim foreach (var node in animation.TransformNodes) //iterate through each node { for (int i = 0; i < animation.FrameCount; i++) { SBBone temp = new SBBone(); temp.Transform = node.Transform.GetValue(i); OpenTK.Vector3 pos = temp.Translation; OpenTK.Quaternion rot = temp.RotationQuaternion; OpenTK.Vector3 sca = temp.Scale; seOut.AddTranslationKey(node.Name, i, pos.X, pos.Y, pos.Z); seOut.AddRotationKey(node.Name, i, rot.X, rot.Y, rot.Z, rot.W); seOut.AddScaleKey(node.Name, i, sca.X, sca.Y, sca.Z); } } seOut.Write(FileName); //write it! }
public static void Open(string FileName, SBScene Scene) { ISSBH_File File; if (SSBH.TryParseSSBHFile(FileName, out File)) { if (File is SKEL skel) { var Skeleton = new SBSkeleton(); Scene.Skeleton = Skeleton; Dictionary <int, SBBone> idToBone = new Dictionary <int, SBBone>(); Dictionary <SBBone, int> needParent = new Dictionary <SBBone, int>(); foreach (var b in skel.BoneEntries) { SBBone bone = new SBBone(); bone.Name = b.Name; bone.Type = b.Type; bone.Transform = Skel_to_TKMatrix(skel.Transform[b.ID]); idToBone.Add(b.ID, bone); if (b.ParentID == -1) { Skeleton.AddRoot(bone); } else { needParent.Add(bone, b.ParentID); } } foreach (var v in needParent) { v.Key.Parent = idToBone[v.Value]; } } } }
/// <summary> /// /// </summary> /// <param name="bone"></param> /// <param name="joint"></param> /// <param name="animation"></param> private void EncodeAnimJoint(SBBone bone, HSD_AnimJoint joint, SBAnimation animation) { var node = animation.TransformNodes.Find(e => e.Name == bone.Name); if (node != null) { // encode tracks joint.Flags = 1; joint.AOBJ = new HSD_AOBJ(); joint.AOBJ.EndFrame = animation.FrameCount; joint.AOBJ.Flags = AOBJ_Flags.ANIM_LOOP; if (!HSDSettings.LoopAnimation) { joint.AOBJ.Flags = AOBJ_Flags.FIRST_PLAY; } if (node.Tracks.Count == 0) { joint.AOBJ.Flags = AOBJ_Flags.NO_ANIM; } var prev = new HSD_FOBJDesc(); foreach (var track in node.Tracks) { var fobjdesc = new HSD_FOBJDesc(); fobjdesc.FromFOBJ(EncodeFOBJ(track)); fobjdesc.DataLength = fobjdesc.ToFOBJ().Buffer.Length; if (joint.AOBJ.FObjDesc == null) { joint.AOBJ.FObjDesc = fobjdesc; } else { prev.Next = fobjdesc; } prev = fobjdesc; } } // continue adding children var prevChild = new HSD_AnimJoint(); foreach (var c in bone.Children) { HSD_AnimJoint child = new HSD_AnimJoint(); EncodeAnimJoint(c, child, animation); if (joint.Child == null) { joint.Child = child; } else { prevChild.Next = child; } prevChild = child; } }
/// <summary> /// Selects a bone and display the bone tool strip /// </summary> /// <param name="bone"></param> public void SelectBone(SBBone bone) { ResetControls(); BoneEditor.BindBone(bone); BoneEditor.Visible = true; }
public IOModel ImportIOModel(string FileName) { IOModel model = new IOModel(); SBSkeleton skeleton = new SBSkeleton(); Dictionary <int, SBBone> indexToBone = new Dictionary <int, SBBone>(); Dictionary <string, IOMesh> materialToMesh = new Dictionary <string, IOMesh>(); List <SBBone> PostProcessBones = new List <SBBone>(); List <int> boneParents = new List <int>(); string[] lines = File.ReadAllLines(FileName); string CurrentSection = ""; for (int i = 0; i < lines.Length; i++) { string[] args = Regex.Replace(lines[i].Trim(), @"\s+", " ").Split(' '); if (args[0].Equals("end")) { CurrentSection = ""; } else if (args[0].Equals("time")) { } else if (args[0].Equals("nodes")) { CurrentSection = args[0]; } else if (args[0].Equals("skeleton")) { CurrentSection = args[0]; } else if (args[0].Equals("triangles")) { CurrentSection = args[0]; } else { switch (CurrentSection) { case "nodes": var bone = new SBBone(); bone.Name = args[1].Replace("\"", ""); Console.WriteLine(bone.Name + " " + args[2]); boneParents.Add(int.Parse(args[2])); PostProcessBones.Add(bone); indexToBone.Add(int.Parse(args[0]), bone); break; case "skeleton": var skel = PostProcessBones[int.Parse(args[0])]; skel.Transform = Matrix4.Identity; skel.X = float.Parse(args[1]); skel.Y = float.Parse(args[2]); skel.Z = float.Parse(args[3]); skel.RX = float.Parse(args[4]); skel.RY = float.Parse(args[5]); skel.RZ = float.Parse(args[6]); break; case "triangles": string material = args[0]; if (!materialToMesh.ContainsKey(material)) { var iomesh = new IOMesh(); iomesh.HasPositions = true; iomesh.HasNormals = true; iomesh.HasUV0 = true; iomesh.HasBoneWeights = true; iomesh.Name = material; materialToMesh.Add(material, iomesh); } var mesh = materialToMesh[material]; mesh.Vertices.Add(ReadVertex(Regex.Replace(lines[i + 1].Trim(), @"\s+", " ").Split(' '))); mesh.Vertices.Add(ReadVertex(Regex.Replace(lines[i + 2].Trim(), @"\s+", " ").Split(' '))); mesh.Vertices.Add(ReadVertex(Regex.Replace(lines[i + 3].Trim(), @"\s+", " ").Split(' '))); i += 3; break; } } } //PostProcessBones int boneIndex = 0; foreach (var bone in PostProcessBones) { if (boneParents[boneIndex] == -1) { skeleton.AddRoot(bone); } else { bone.Parent = indexToBone[boneParents[boneIndex]]; } boneIndex++; } model.Skeleton = skeleton; // finalize meshes foreach (var pair in materialToMesh) { model.Meshes.Add(pair.Value); pair.Value.Optimize(); SBConsole.WriteLine($"Imported {pair.Key} from SMD"); //finalize rigging for (int i = 0; i < pair.Value.Vertices.Count; i++) { var vertex = pair.Value.Vertices[i]; vertex.BoneIndices.X = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.X]); vertex.BoneIndices.Y = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.Y]); vertex.BoneIndices.Z = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.Z]); vertex.BoneIndices.W = model.Skeleton.IndexOfBone(indexToBone[(int)vertex.BoneIndices.W]); pair.Value.Vertices[i] = vertex; } } return(model); }
/// <summary> /// /// </summary> /// <param name="Frame"></param> /// <param name="bone"></param> /// <returns></returns> public Matrix4 GetTransformAt(float Frame, SBBone bone) { if (bone == null) { return(Matrix4.Identity); } // temp for less matrix calculations Vector3 newPos = new Vector3(bone.X, bone.Y, bone.Z); Vector3 newRot = new Vector3(bone.RX, bone.RY, bone.RZ); Vector3 newSca = bone.Scale; if (bone is SBHsdBone hsdBone) { newRot = new Vector3(hsdBone.RX, hsdBone.RY, hsdBone.RZ); } bool useQuatRotation = false; float f1 = 0; float f2 = 0; var q1 = new Quaternion(); var q2 = new Quaternion(); foreach (var track in Tracks) { switch (track.Type) { case SBTrackType.TranslateX: newPos.X = track.Keys.GetValue(Frame); break; case SBTrackType.TranslateY: newPos.Y = track.Keys.GetValue(Frame); break; case SBTrackType.TranslateZ: newPos.Z = track.Keys.GetValue(Frame); break; case SBTrackType.RotateX: newRot.X = track.Keys.GetValue(Frame); q1.X = track.Keys.GetKey(Frame).Value; q2.X = track.Keys.GetNextKey(Frame).Value; break; case SBTrackType.RotateY: newRot.Y = track.Keys.GetValue(Frame); q1.Y = track.Keys.GetKey(Frame).Value; q2.Y = track.Keys.GetNextKey(Frame).Value; break; case SBTrackType.RotateZ: newRot.Z = track.Keys.GetValue(Frame); q1.Z = track.Keys.GetKey(Frame).Value; q2.Z = track.Keys.GetNextKey(Frame).Value; break; case SBTrackType.ScaleX: newSca.X = track.Keys.GetValue(Frame); break; case SBTrackType.ScaleY: newSca.Y = track.Keys.GetValue(Frame); break; case SBTrackType.ScaleZ: newSca.Z = track.Keys.GetValue(Frame); break; case SBTrackType.RotateW: useQuatRotation = true; q1.W = track.Keys.GetKey(Frame).Value; q2.W = track.Keys.GetNextKey(Frame).Value; f1 = track.Keys.GetKey(Frame).Frame; f2 = track.Keys.GetNextKey(Frame).Frame; break; } } SBBone temp = new SBBone(); temp.Transform = Matrix4.Identity; temp.Scale = newSca; temp.Translation = newPos; if (useQuatRotation) { temp.RotationQuaternion = Quaternion.Slerp(q1, q2, (Frame - f1) / (f2 - f1)); } else { temp.RotationEuler = newRot; } return(temp.Transform); }