protected override void Awake() { base.Awake(); Transform[] leftHandTransforms = leftHandObject.GetComponentsInChildren <Transform>(); for (int i = 0; i < leftJointMaps.Length; i++) { JointMap jm = leftJointMaps[i]; foreach (Transform tr in leftHandTransforms) { if (tr.name == jm.Name) { jm.Transform = tr; break; } } leftJointMaps[i] = jm; } Transform[] rightHandTransforms = rightHandObject.GetComponentsInChildren <Transform>(); for (int i = 0; i < rightJointMaps.Length; i++) { JointMap jm = rightJointMaps[i]; foreach (Transform tr in rightHandTransforms) { if (tr.name == jm.Name) { jm.Transform = tr; break; } } rightJointMaps[i] = jm; } }
bool ProcessJointMap(JointMap jm, double startTime, bool loop) { var joint = constructs.Find(jm.ChildName); double t = totalTime - startTime; //looping? if (jm.Channel.Interval == -1) { if (!loop && t >= jm.Channel.Duration) { return(true); } else { t = t % jm.Channel.Duration; } } float angle = 0; if (jm.Channel.HasAngle) { angle = jm.Channel.AngleAtTime((float)t); } var quat = Quaternion.Identity; if (jm.Channel.HasOrientation) { quat = jm.Channel.QuaternionAtTime((float)t); } joint.Update(angle, quat); return(false); }
private JointMapView(LUtfNode node) { unique = uniqueCount--; name = node.Name; scriptName = node.Parent.Name; map = new JointMap(EditableUtf.NodeToEngine(node)); }
bool ProcessJointMap(JointMap jm, double startTime, bool loop) { var joint = constructs.Find(jm.ChildName); double t = totalTime - startTime; //looping? if (jm.Channel.Interval == -1) { var duration = jm.Channel.Frames[jm.Channel.FrameCount - 1].Time.Value; if (!loop && t >= duration) { return(true); } else { t = t % duration; } } float t1 = 0; for (int i = 0; i < jm.Channel.Frames.Length - 1; i++) { var t0 = jm.Channel.Frames[i].Time ?? (jm.Channel.Interval * i); t1 = jm.Channel.Frames[i + 1].Time ?? (jm.Channel.Interval * (i + 1)); var v1 = jm.Channel.Frames[i].JointValue; var v2 = jm.Channel.Frames[i + 1].JointValue; if (t >= t0 && t <= t1) { var dist = Math.Abs(v2 - v1); if (Math.Abs(t1 - t0) < 0.5f && dist > 1f) { //Deal with the horrible rotation scripts //Disable interpolation between e.g. 3.137246 to -3.13287 //Don't remove this or things go crazy ~ Callum joint.Update((float)v2); } else { var x = (t - t0) / (t1 - t0); var val = v1 + (v2 - v1) * x; joint.Update((float)val); } } } return(false); }
void ProcessJointMap(JointMap jm) { if (!boneInstances.ContainsKey(jm.ChildName)) { return; } var joint = boneInstances[jm.ChildName]; var t = (float)totalTime; if (jm.Channel.HasOrientation) { joint.Rotation = jm.Channel.QuaternionAtTime(t); } if (jm.Channel.HasPosition) { joint.Translation = jm.Channel.PositionAtTime(t); } }
/// <summary> /// /// </summary> /// <param name="_jointMap"></param> /// <param name="filePath"></param> /// <returns></returns> public static JointAnimManager LoadJointAnimFromFile(JointMap _jointMap, string filePath = null) { if (filePath == null) { filePath = Tools.FileIO.OpenFile(SupportedImportAnimFilter); } if (filePath != null) { if (Path.GetExtension(filePath).ToLower().Equals(".chr0")) { return(CHR0Converter.LoadCHR0(filePath, _jointMap)); } else if (Path.GetExtension(filePath).ToLower().Equals(".anim")) { return(ConvMayaAnim.ImportFromMayaAnim(filePath, _jointMap)); } else if (Path.GetExtension(filePath).ToLower().Equals(".dat")) { var dat = new HSDRaw.HSDRawFile(filePath); if (dat.Roots.Count > 0 && dat.Roots[0].Data is HSD_FigaTree tree) { return(new JointAnimManager(tree)); } if (dat.Roots.Count > 0 && dat.Roots[0].Data is HSD_AnimJoint joint) { return(new JointAnimManager(joint)); } } } return(null); }
protected void BuildCharacter() // NOTE: In indra, this is virtual { //------------------------------------------------------------------------- // remove all references to our existing skeleton // so we can rebuild it //------------------------------------------------------------------------- // FlushAllMotions(); // TODO: Should this be in the Character that this AvatarAppearance is connected to? Or will be... //------------------------------------------------------------------------- // remove all of mRoot's children //------------------------------------------------------------------------- Root.RemoveAllChildren(); JointMap.Clear(); IsBuilt = false; //------------------------------------------------------------------------- // clear mesh data //------------------------------------------------------------------------- foreach (AvatarJoint avatarJoint in MeshLod) { foreach (AvatarJointMesh avatarJointMesh in avatarJoint.MeshParts) { avatarJointMesh.SetMesh(null); } } //------------------------------------------------------------------------- // (re)load our skeleton and meshes //------------------------------------------------------------------------- bool status = LoadAvatar(); // TODO: Indra times this and logs the time it took to load the avatar Logger.LogDebug("AvatarAppearance.BuildCharacter", "Avatar loaded."); if (status == false) { if (IsSelf) { Logger.LogError("AvatarAppearance.BuildCharacter", "Unable to load user's avatar"); } else { Logger.LogWarning("AvatarAppearance.BuildCharacter", "Unable to load other's avatar"); } return; } //------------------------------------------------------------------------- // initialize "well known" joint pointers //------------------------------------------------------------------------- Pelvis = Root.FindJoint("mPelvis"); Torso = Root.FindJoint("mTorso"); Chest = Root.FindJoint("mChest"); Neck = Root.FindJoint("mNeck"); Head = Root.FindJoint("mHead"); Skull = Root.FindJoint("mSkull"); HipLeft = Root.FindJoint("mHipLeft"); HipRight = Root.FindJoint("mHipRight"); KneeLeft = Root.FindJoint("mKneeLeft"); KneeRight = Root.FindJoint("mKneeRight"); AnkleLeft = Root.FindJoint("mAnkleLeft"); AnkleRight = Root.FindJoint("mAnkleRight"); FootLeft = Root.FindJoint("mFootLeft"); FootRight = Root.FindJoint("mFootRight"); WristLeft = Root.FindJoint("mWristLeft"); WristRight = Root.FindJoint("mWristRight"); EyeLeft = Root.FindJoint("mEyeLeft"); EyeRight = Root.FindJoint("mEyeRight"); //------------------------------------------------------------------------- // Make sure "well known" pointers exist //------------------------------------------------------------------------- if (!(Pelvis != null && Torso != null && Chest != null && Neck != null && Head != null && Skull != null && HipLeft != null && HipRight != null && KneeLeft != null && KneeRight != null && AnkleLeft != null && AnkleRight != null && FootLeft != null && FootRight != null && WristLeft != null && WristRight != null && EyeLeft != null && EyeRight != null)) { Logger.LogError("AvatarAppearance.BuildCharacter", "Failed to create avatar."); return; } //------------------------------------------------------------------------- // Initialise the pelvis //------------------------------------------------------------------------- // SL-315 Pelvis.SetPosition(new Vector3(0.0f, 0.0f, 0.0f)); IsBuilt = true; }
public ResolvedJoint(BoneInstance bone, JointMap jm) { Bone = bone; JointMap = jm; }
public static HSD_FigaTree RemapFigatree(RemapSettings settings, HSD_FigaTree from, int newBoneCount, JointMap mapFrom, JointMap mapTo) { var sourceNodes = from.Nodes; var targetNodes = new List <FigaTreeNode>(); for (int i = 0; i < newBoneCount; i++) { FigaTreeNode node = new FigaTreeNode(); targetNodes.Add(node); var remapIndex = mapFrom.IndexOf(mapTo[i]); if (remapIndex != -1) { // port tracks node.Tracks.AddRange(sourceNodes[remapIndex].Tracks); if (settings.IgnoreTranslation) { node.Tracks.RemoveAll( e => e.JointTrackType == JointTrackType.HSD_A_J_TRAX || e.JointTrackType == JointTrackType.HSD_A_J_TRAY || e.JointTrackType == JointTrackType.HSD_A_J_TRAZ); } } } var newft = new HSD_FigaTree(); newft.Type = 1; newft.FrameCount = from.FrameCount; newft.Nodes = targetNodes; return(newft); }
/// <summary> /// /// </summary> /// <param name="filePath"></param> /// <returns></returns> public static JointAnimManager LoadCHR0(string filePath, JointMap jointMap) { JointAnimManager anim = new JointAnimManager(); for (int i = 0; i < jointMap.Count; i++) { anim.Nodes.Add(new AnimNode()); } using (BinaryReaderExt r = new BinaryReaderExt(new FileStream(filePath, FileMode.Open))) { r.BigEndian = true; if (r.BaseStream.Length < 4 || new string(r.ReadChars(4)) != "CHR0") { throw new InvalidDataException("CHR0 file is not valid"); } r.Skip(4); int versionNum = r.ReadInt32(); if (versionNum != 4) { throw new InvalidDataException($"CHR0 version {versionNum} not supported"); } r.Seek(0x10); var indexGroupOffset = r.ReadUInt32(); var animName = r.ReadString(r.ReadInt32(), -1); r.Skip(4); anim.FrameCount = r.ReadUInt16() - 1; int animDataCount = r.ReadUInt16(); r.Skip(8); r.Seek(indexGroupOffset); var sectionOffset = r.ReadUInt32() + indexGroupOffset; int sectionCount = r.ReadInt32(); for (uint i = 0; i < sectionCount; i++) { r.Seek(indexGroupOffset + 8 + 16 * i); r.Skip(4); // id and unknown r.Skip(2); // let r.Skip(2); // right var boneName = r.ReadString(r.ReadInt32() + (int)indexGroupOffset, -1); var dataOffset = r.ReadUInt32() + indexGroupOffset; if (dataOffset == indexGroupOffset) { sectionCount += 1; continue; } if (jointMap.IndexOf(boneName) == -1) { continue; } r.Seek(dataOffset); var nameOff = r.Position + r.ReadUInt32(); var flags = r.ReadInt32(); //Console.WriteLine(boneName + " " + flags.ToString("X")); //r.PrintPosition(); //01BFE019 int t_type = (flags >> 0x1e) & 0x3; int r_type = (flags >> 0x1b) & 0x7; int s_type = (flags >> 0x19) & 0x3; int hasT = (flags >> 0x18) & 0x1; int hasR = (flags >> 0x17) & 0x1; int hasS = (flags >> 0x16) & 0x1; int Zfixed = (flags >> 0x15) & 0x1; int Yfixed = (flags >> 0x14) & 0x1; int Xfixed = (flags >> 0x13) & 0x1; int RZfixed = (flags >> 0x12) & 0x1; int RYfixed = (flags >> 0x11) & 0x1; int RXfixed = (flags >> 0x10) & 0x1; int SZfixed = (flags >> 0xf) & 0x1; int SYfixed = (flags >> 0xe) & 0x1; int SXfixed = (flags >> 0xd) & 0x1; int Tiso = (flags >> 0x6) & 0x1; int Riso = (flags >> 0x5) & 0x1; int Siso = (flags >> 0x4) & 0x1; AnimNode node = new AnimNode(); FOBJ_Player trackX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAX }; FOBJ_Player trackY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAY }; FOBJ_Player trackZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAZ }; FOBJ_Player trackRX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTX }; FOBJ_Player trackRY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTY }; FOBJ_Player trackRZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTZ }; FOBJ_Player trackSX = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAX }; FOBJ_Player trackSY = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAY }; FOBJ_Player trackSZ = new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAZ }; if (hasS == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackSX, trackSY, trackSZ, Siso == 1, SXfixed == 1, SYfixed == 1, SZfixed == 1, s_type, dataOffset); } if (hasR == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackRX, trackRY, trackRZ, Riso == 1, RXfixed == 1, RYfixed == 1, RZfixed == 1, r_type, dataOffset); } if (hasT == 1) { ReadKeys(r, node, (int)anim.FrameCount, trackX, trackY, trackZ, Tiso == 1, Xfixed == 1, Yfixed == 1, Zfixed == 1, t_type, dataOffset); } if (trackX.Keys.Count > 0) { node.Tracks.Add(trackX); } if (trackY.Keys.Count > 0) { node.Tracks.Add(trackY); } if (trackZ.Keys.Count > 0) { node.Tracks.Add(trackZ); } if (trackRX.Keys.Count > 0) { node.Tracks.Add(trackRX); } if (trackRY.Keys.Count > 0) { node.Tracks.Add(trackRY); } if (trackRZ.Keys.Count > 0) { node.Tracks.Add(trackRZ); } if (trackSX.Keys.Count > 0) { node.Tracks.Add(trackSX); } if (trackSY.Keys.Count > 0) { node.Tracks.Add(trackSY); } if (trackSZ.Keys.Count > 0) { node.Tracks.Add(trackSZ); } foreach (var k in trackRX.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Tan); } foreach (var k in trackRY.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Tan); } foreach (var k in trackRZ.Keys) { k.Value = MathHelper.DegreesToRadians(k.Value); k.Tan = MathHelper.DegreesToRadians(k.Tan); } // make sure all tracks start at frame 0 foreach (var track in node.Tracks) { if (track.Keys.Count > 0 && track.Keys[0].Frame != 0) { track.Keys.Insert(0, new FOBJKey() { Frame = 0, Value = track.Keys[0].Value, InterpolationType = GXInterpolationType.HSD_A_OP_CON, }); } } //Console.WriteLine(boneName + " Tracks:" + node.Tracks.Count + " " + flags.ToString("X")); //Console.WriteLine($"{trackX.Keys.Count} {trackY.Keys.Count} {trackZ.Keys.Count}"); //Console.WriteLine($"{trackRX.Keys.Count} {trackRY.Keys.Count} {trackRZ.Keys.Count}"); //Console.WriteLine($"{trackSX.Keys.Count} {trackSY.Keys.Count} {trackSZ.Keys.Count}"); anim.Nodes[jointMap.IndexOf(boneName)] = node; } } return(anim); }
/// <summary> /// /// </summary> /// <param name="filePath"></param> /// <param name="nodes"></param> public static void ExportToMayaAnim(string filePath, JointAnimManager animation, JointMap jointMap) { using (PropertyDialog d = new PropertyDialog("Maya Settings", MayaSettings)) { if (d.ShowDialog() != DialogResult.OK) { return; } } MayaAnim a = new MayaAnim(); if (!MayaSettings.UseRadians) { a.header.angularUnit = "deg"; } int nodeIndex = 0; int frameCount = 0; foreach (var n in animation.Nodes) { MayaAnim.MayaNode mnode = new MayaAnim.MayaNode(); mnode.name = !string.IsNullOrEmpty(jointMap[nodeIndex]) ? jointMap[nodeIndex] : "JOBJ_" + nodeIndex; a.Nodes.Add(mnode); foreach (var t in n.Tracks) { if (!jointTrackToMayaTrack.ContainsKey(t.JointTrackType)) { continue; } MayaAnim.MayaTrack mtrack = new MayaAnim.MayaTrack(); mnode.atts.Add(mtrack); mtrack.type = jointTrackToMayaTrack[t.JointTrackType]; if (mtrack.IsAngular()) { mtrack.output = MayaAnim.OutputType.angular; } FOBJAnimState prevState = null; for (int i = 0; i < t.Keys.Count; i++) { // get maximum frame to use as framecount frameCount = (int)Math.Max(frameCount, t.Keys[i].Frame); // get current state at this key frame var state = t.GetState(t.Keys[i].Frame); bool nextSlope = i + 1 < t.Keys.Count && t.Keys[i + 1].InterpolationType == GXInterpolationType.HSD_A_OP_SLP; if (t.Keys[i].InterpolationType == GXInterpolationType.HSD_A_OP_SLP) { continue; } // assuming last frame // if last frame shift frame information over if (t.Keys[i].Frame == state.t1) { state.t0 = state.t1; state.p0 = state.p1; state.d0 = state.d1; //state.op_intrp = state.op; } // generate key with time and value var animkey = new MayaAnim.AnimKey() { input = state.t0, output = state.p0, }; // nothing to do for linear //if (op_intrp == GXInterpolationType.HSD_A_OP_LIN) // set step type for constant and key if (state.op_intrp == GXInterpolationType.HSD_A_OP_CON || state.op_intrp == GXInterpolationType.HSD_A_OP_KEY) { animkey.intan = "auto"; animkey.outtan = "step"; } // set tangents for weighted slopes if (state.op_intrp == GXInterpolationType.HSD_A_OP_SLP || state.op_intrp == GXInterpolationType.HSD_A_OP_SPL0 || state.op_intrp == GXInterpolationType.HSD_A_OP_SPL) { animkey.t1 = state.d0; animkey.t2 = state.d0; if (nextSlope && prevState != null) { animkey.t1 = prevState.d1; } animkey.intan = "spline"; animkey.outtan = "spline"; } prevState = state; animkey.t1 = (float)MathHelper.RadiansToDegrees(Math.Atan(animkey.t1)); animkey.t2 = (float)MathHelper.RadiansToDegrees(Math.Atan(animkey.t2)); if (mtrack.IsAngular() && !MayaSettings.UseRadians) { animkey.output = MathHelper.RadiansToDegrees(animkey.output); animkey.t1 = MathHelper.RadiansToDegrees(animkey.t1); animkey.t2 = MathHelper.RadiansToDegrees(animkey.t2); } // add final key mtrack.keys.Add(animkey); } } nodeIndex++; } // set framecount a.header.endTime = animation.FrameCount; a.header.startTime = 0; // save to file a.Save(filePath); }
/// <summary> /// /// </summary> /// <param name="filePath"></param> public static JointAnimManager ImportFromMayaAnim(string filePath, JointMap jointMap) { var mayaFile = new MayaAnim(); mayaFile.Open(filePath); JointAnimManager animation = new JointAnimManager(); animation.FrameCount = mayaFile.header.endTime - mayaFile.header.startTime; var nodeCount = jointMap == null || jointMap.Count == 0 ? mayaFile.Nodes.Count : Math.Max(mayaFile.Nodes.Count, jointMap.Count); for (int i = 0; i < nodeCount; i++) { animation.Nodes.Add(new AnimNode()); } // process and encode FOBJ keys int index = 0; foreach (var mNode in mayaFile.Nodes) { var node = animation.Nodes[index++]; //Debug.WriteLine(mNode.name); if (jointMap != null) { var nodeIndex = jointMap.IndexOf(mNode.name); if (nodeIndex != -1) { node = animation.Nodes[nodeIndex]; } } foreach (var mTrack in mNode.atts) { FOBJ_Player t = new FOBJ_Player(); t.Keys = new List <FOBJKey>(); t.JointTrackType = jointTrackToMayaTrack.FirstOrDefault(e => e.Value == mTrack.type).Key; //Debug.WriteLine("\t" + mTrack.type); var degrees = mayaFile.header.angularUnit == "deg"; var trackUnit = (mTrack.IsAngular() && degrees); for (int i = 0; i < mTrack.keys.Count; i++) { var mKey = mTrack.keys[i]; var mKeyNext = i + 1 < mTrack.keys.Count ? mTrack.keys[i + 1] : mTrack.keys[i]; var k = new FOBJKey(); k.Frame = mKey.input - mayaFile.header.startTime; k.Value = trackUnit ? MathHelper.DegreesToRadians(mKey.output) : mKey.output; switch (mKey.outtan) { case "auto": case "linear": k.InterpolationType = GXInterpolationType.HSD_A_OP_LIN; t.Keys.Add(k); break; case "step": if (mTrack.keys.Count == 1) { k.InterpolationType = GXInterpolationType.HSD_A_OP_KEY; } else { k.InterpolationType = GXInterpolationType.HSD_A_OP_CON; } t.Keys.Add(k); break; case "fixed": case "spline": k.InterpolationType = GXInterpolationType.HSD_A_OP_SPL; k.Tan = AngleToTan(mKey.t1, degrees); if ((mKeyNext.input - mKey.input) <= 1) // optimization { //k.InterpolationType = GXInterpolationType.HSD_A_OP_LIN; t.Keys.Add(k); } else if (mKey.t2 == 0) { k.InterpolationType = GXInterpolationType.HSD_A_OP_SPL0; t.Keys.Add(k); } else if (mKey.t1 != mKey.t2) { t.Keys.Add(k); var slp = new FOBJKey(); slp.Frame = mKeyNext.input - 1; slp.InterpolationType = GXInterpolationType.HSD_A_OP_SLP; slp.Tan = AngleToTan(mKey.t2, degrees); t.Keys.Add(slp); } else { t.Keys.Add(k); } break; default: Console.WriteLine(mKey.outtan + " not supported!"); break; } if (mTrack.keys.Count == 1) { k.InterpolationType = GXInterpolationType.HSD_A_OP_KEY; } //foreach (var key in t.Keys) // Debug.WriteLine($"\t\t{key.Frame} {key.Value}"); } node.Tracks.Add(t); } } return(animation); }
public static JointAnimManager ToJointAnim(string filePath, JointMap jm) { var bke = BKE.Open(filePath); JointAnimManager anim = new JointAnimManager(); anim.FrameCount = bke.CountFrames(); for (int i = 0; i < bke.Nodes.Count; i++) { var node = new AnimNode(); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAX, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAY, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_TRAZ, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTX, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTY, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_ROTZ, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAX, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAY, Keys = new List <FOBJKey>() }); node.Tracks.Add(new FOBJ_Player() { JointTrackType = JointTrackType.HSD_A_J_SCAZ, Keys = new List <FOBJKey>() }); anim.Nodes.Add(node); } foreach (var n in bke.Nodes) { if (jm.IndexOf(n.Name) == -1) { break; } var node = anim.Nodes[jm.IndexOf(n.Name)]; Console.WriteLine(n.Name + " " + n.Parent?.Name); for (int f = 0; f < anim.FrameCount; f++) { var matrix = n.GetLocal(f); var tra = matrix.ExtractTranslation(); var sca = matrix.ExtractScale(); var rot = Math3D.ToEulerAngles(matrix.ExtractRotation().Inverted()); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_TRAX).Keys.Add(new FOBJKey() { Frame = f, Value = tra.X, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_TRAY).Keys.Add(new FOBJKey() { Frame = f, Value = tra.Y, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_TRAZ).Keys.Add(new FOBJKey() { Frame = f, Value = tra.Z, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_ROTX).Keys.Add(new FOBJKey() { Frame = f, Value = rot.X, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_ROTY).Keys.Add(new FOBJKey() { Frame = f, Value = rot.Y, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_ROTZ).Keys.Add(new FOBJKey() { Frame = f, Value = rot.Z, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_SCAX).Keys.Add(new FOBJKey() { Frame = f, Value = sca.X, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_SCAY).Keys.Add(new FOBJKey() { Frame = f, Value = sca.Y, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); node.Tracks.Find(e => e.JointTrackType == JointTrackType.HSD_A_J_SCAZ).Keys.Add(new FOBJKey() { Frame = f, Value = sca.Z, InterpolationType = GXInterpolationType.HSD_A_OP_LIN }); } } return(anim); }