public SkeletonExporter(FbxScene scene, FLVER2 flver, HKX.HKASkeleton hKASkeleton, List <DsBone> bones) { Scene = scene; this.Flver = flver; this.bones = bones; this.hkaSkeleton = hKASkeleton; }
public DsBone(HKX.Bone hkxBone, HKX.HKASkeleton hkaSkeleton) : this() { HkxBoneIndex = hkaSkeleton.Bones.GetArrayData().Elements.IndexOf(hkxBone); Name = hkxBone.Name.GetString(); ParentName = InitializeHkxParentName(hkxBone, hkaSkeleton); }
private string InitializeHkxParentName(HKX.Bone hkxBone, HKX.HKASkeleton hkaSkeleton) { short hkxParentBoneIndex = hkaSkeleton.ParentIndices.GetArrayData().Elements[HkxBoneIndex].data; if (hkxParentBoneIndex >= 0) { HKX.Bone hkxParentBone = hkaSkeleton.Bones.GetArrayData().Elements[hkxParentBoneIndex]; return(hkxParentBone.Name.GetString()); } return(null); }
private static IEnumerable <DsBone> FixupDsBonesInternal(FLVER2 flver, HKX.HKASkeleton hkx) { if (hkx == null) { return(FixupDsBones(flver)); } if (flver == null) { return(FixupDsBones(hkx)); } return(flver.Bones.Join(hkx.Bones.GetArrayData().Elements, flverBone => flverBone.Name, hkxBone => hkxBone.Name.GetString(), (flverBone, hkxBone) => new DsBone(flverBone, flver, hkxBone, hkx) )); }
public static IEnumerable <DsBone> FixupDsBones(FLVER2 flver, HKX.HKASkeleton hkx) { var skel = FixupDsBonesInternal(flver, hkx); Func <DsBone, DsBone> boneConversion = bone => { //if (bone.Name == "Pelvis") //{ // bone.ParentName = "RootRotXZ"; //} if (bone.Name == "Spine") { bone.ParentName = "Pelvis"; } return(bone); }; return(skel.Select(boneConversion)); }
private static Matrix4x4 CalculateGlobalTransformHka(int hkxBoneIndex, HKX.HKASkeleton skeleton) { var hkxTransform = skeleton.Transforms.GetArrayData().Elements[hkxBoneIndex]; Matrix4x4 transformMatrix = Matrix4x4.CreateScale(hkxTransform.Scale.Vector.X, hkxTransform.Scale.Vector.Y, hkxTransform.Scale.Vector.Z) * Matrix4x4.CreateFromQuaternion(new Quaternion(hkxTransform.Rotation.Vector.X, hkxTransform.Rotation.Vector.Y, hkxTransform.Rotation.Vector.Z, hkxTransform.Rotation.Vector.W)) * Matrix4x4.CreateTranslation(hkxTransform.Position.Vector.X, hkxTransform.Position.Vector.Y, hkxTransform.Position.Vector.Z); short parentIndex = skeleton.ParentIndices[hkxBoneIndex].data; if (parentIndex >= 0) { transformMatrix *= CalculateGlobalTransformHka(parentIndex, skeleton); } else { //transformMatrix *= Matrix4x4.CreateRotationX((float)(-Math.PI / 2)) * Matrix4x4.CreateRotationZ((float)(Math.PI / 2)); } return(transformMatrix); }
public void LoadHKXSkeleton(HKX.HKASkeleton skeleton) { OriginalHavokSkeleton = skeleton; HkxSkeleton.Clear(); for (int i = 0; i < skeleton.Bones.Size; i++) { var newHkxBone = new HkxBoneInfo(); newHkxBone.Name = skeleton.Bones[i].Name.GetString(); newHkxBone.ParentIndex = skeleton.ParentIndices[i].data; newHkxBone.RelativeReferenceMatrix = Matrix.CreateScale(new Vector3( skeleton.Transforms[i].Scale.Vector.X, skeleton.Transforms[i].Scale.Vector.Y, skeleton.Transforms[i].Scale.Vector.Z)) * Matrix.CreateFromQuaternion(new Quaternion( skeleton.Transforms[i].Rotation.Vector.X, skeleton.Transforms[i].Rotation.Vector.Y, skeleton.Transforms[i].Rotation.Vector.Z, skeleton.Transforms[i].Rotation.Vector.W)) * Matrix.CreateTranslation(new Vector3( skeleton.Transforms[i].Position.Vector.X, skeleton.Transforms[i].Position.Vector.Y, skeleton.Transforms[i].Position.Vector.Z)); for (int j = 0; j < FlverSkeleton.Count; j++) { if (FlverSkeleton[j].Name == newHkxBone.Name) { FlverSkeleton[j].HkxBoneIndex = i; newHkxBone.FlverBoneIndex = j; break; } } HkxSkeleton.Add(newHkxBone); } Matrix GetAbsoluteReferenceMatrix(int i) { Matrix result = Matrix.Identity; do { result *= HkxSkeleton[i].RelativeReferenceMatrix; i = HkxSkeleton[i].ParentIndex; }while (i >= 0); return(result); } var flverDeadBonesToApplyHkxChildrenTo = new Dictionary <int, int>(); for (int i = 0; i < HkxSkeleton.Count; i++) { HkxSkeleton[i].ReferenceMatrix = GetAbsoluteReferenceMatrix(i); for (int j = 0; j < HkxSkeleton.Count; j++) { if (HkxSkeleton[j].ParentIndex == i) { HkxSkeleton[i].ChildIndices.Add(j); } } if (HkxSkeleton[i].ParentIndex < 0) { RootBoneIndices.Add(i); } if (HkxSkeleton[i].FlverBoneIndex == -1) { HkxSkeleton[i].FlverBoneIndex = FlverSkeleton.Count; var newFlverBone = new FlverBoneInfo(HkxSkeleton[i], HkxSkeleton, FlverSkeleton); FlverSkeleton.Add(newFlverBone); if (!flverDeadBonesToApplyHkxChildrenTo.ContainsKey(HkxSkeleton[i].FlverBoneIndex)) { flverDeadBonesToApplyHkxChildrenTo.Add(HkxSkeleton[i].FlverBoneIndex, i); } } else if (FlverSkeleton[HkxSkeleton[i].FlverBoneIndex].IsNub) { FlverSkeleton[HkxSkeleton[i].FlverBoneIndex].ApplyHkxBoneProperties(HkxSkeleton[i], HkxSkeleton, FlverSkeleton); if (!flverDeadBonesToApplyHkxChildrenTo.ContainsKey(HkxSkeleton[i].FlverBoneIndex)) { flverDeadBonesToApplyHkxChildrenTo.Add(HkxSkeleton[i].FlverBoneIndex, i); } } foreach (var kvp in flverDeadBonesToApplyHkxChildrenTo) { FlverSkeleton[kvp.Key].ChildBones.Clear(); var copyFromHkx = HkxSkeleton[kvp.Value]; foreach (var ci in copyFromHkx.ChildIndices) { if (ci >= 0 && ci < HkxSkeleton.Count) { var matchingFlverChildBone = FlverSkeleton.FirstOrDefault(b => b.Name == HkxSkeleton[ci].Name); if (matchingFlverChildBone != null && !FlverSkeleton[kvp.Key].ChildBones.Contains(matchingFlverChildBone)) { FlverSkeleton[kvp.Key].ChildBones.Add(matchingFlverChildBone); } } } if (HkxSkeleton[kvp.Value].ParentIndex >= 0 && HkxSkeleton[kvp.Value].ParentIndex < HkxSkeleton.Count) { var matchingFlverParentBone = FlverSkeleton.FirstOrDefault(b => b.Name == HkxSkeleton[HkxSkeleton[kvp.Value].ParentIndex].Name); if (matchingFlverParentBone != null && !matchingFlverParentBone.ChildBones.Contains(FlverSkeleton[kvp.Key])) { matchingFlverParentBone.ChildBones.Add(FlverSkeleton[kvp.Key]); } } } } }
public void LoadHKXSkeleton(HKX.HKASkeleton skeleton) { OriginalHavokSkeleton = skeleton; HkxSkeleton.Clear(); TopLevelHkxBoneIndices.Clear(); for (int i = 0; i < skeleton.Bones.Size; i++) { var newHkxBone = new HkxBoneInfo(); newHkxBone.Name = skeleton.Bones[i].Name.GetString(); newHkxBone.ParentIndex = skeleton.ParentIndices[i].data; newHkxBone.RelativeReferenceTransform = new NewBlendableTransform() { Translation = new System.Numerics.Vector3( skeleton.Transforms[i].Position.Vector.X, skeleton.Transforms[i].Position.Vector.Y, skeleton.Transforms[i].Position.Vector.Z), Rotation = new System.Numerics.Quaternion( skeleton.Transforms[i].Rotation.Vector.X, skeleton.Transforms[i].Rotation.Vector.Y, skeleton.Transforms[i].Rotation.Vector.Z, skeleton.Transforms[i].Rotation.Vector.W), Scale = new System.Numerics.Vector3( skeleton.Transforms[i].Scale.Vector.X, skeleton.Transforms[i].Scale.Vector.Y, skeleton.Transforms[i].Scale.Vector.Z), }; newHkxBone.RelativeReferenceMatrix = Matrix.CreateScale(new Vector3( skeleton.Transforms[i].Scale.Vector.X, skeleton.Transforms[i].Scale.Vector.Y, skeleton.Transforms[i].Scale.Vector.Z)) * Matrix.CreateFromQuaternion(Quaternion.Normalize(new Quaternion( skeleton.Transforms[i].Rotation.Vector.X, skeleton.Transforms[i].Rotation.Vector.Y, skeleton.Transforms[i].Rotation.Vector.Z, skeleton.Transforms[i].Rotation.Vector.W))) * Matrix.CreateTranslation(new Vector3( skeleton.Transforms[i].Position.Vector.X, skeleton.Transforms[i].Position.Vector.Y, skeleton.Transforms[i].Position.Vector.Z)); HkxSkeleton.Add(newHkxBone); } void GetAbsoluteReferenceMatrix(int i) { Matrix result = Matrix.Identity; int j = i; do { result = HkxSkeleton[j].RelativeReferenceMatrix * result; j = HkxSkeleton[j].ParentIndex; }while (j >= 0); HkxSkeleton[i].ReferenceMatrix = result; HkxSkeleton[i].ReferenceMatrixRootBoneIndex = j; } for (int i = 0; i < HkxSkeleton.Count; i++) { if (HkxSkeleton[i].ParentIndex < 0) { TopLevelHkxBoneIndices.Add(i); } for (int j = 0; j < HkxSkeleton.Count; j++) { if (HkxSkeleton[j].ParentIndex == i) { HkxSkeleton[i].ChildIndices.Add(j); } } GetAbsoluteReferenceMatrix(i); } }
private static Matrix4x4 CalculateGlobalTransform(DsBoneData boneData, FLVER2 flver, HKX.HKASkeleton hkaSkeleton) { if (boneData.exportData.SoulsData.HkxBoneIndex >= 0) { System.Diagnostics.Debug.Assert(hkaSkeleton != null); System.Console.WriteLine("Using HKA transform"); return(CalculateGlobalTransformHka(boneData.exportData.SoulsData.HkxBoneIndex, hkaSkeleton)); } if (flver != null) { System.Console.WriteLine("Using FLVER transform"); return(CalculateGlobalTransformFlver(boneData.flverBone, flver)); } throw new System.ArgumentException("Can't calculate transform " + nameof(boneData)); }
public void LoadHKXSkeleton(HKX.HKASkeleton skeleton) { OriginalHavokSkeleton = skeleton; HkxSkeleton.Clear(); for (int i = 0; i < skeleton.Bones.Size; i++) { var newHkxBone = new HkxBoneInfo(); newHkxBone.Name = skeleton.Bones[i].Name.GetString(); newHkxBone.ParentIndex = skeleton.ParentIndices[i].data; newHkxBone.RelativeReferenceMatrix = Matrix.CreateScale(new Vector3( skeleton.Transforms[i].Scale.Vector.X, skeleton.Transforms[i].Scale.Vector.Y, skeleton.Transforms[i].Scale.Vector.Z)) * Matrix.CreateFromQuaternion(new Quaternion( skeleton.Transforms[i].Rotation.Vector.X, skeleton.Transforms[i].Rotation.Vector.Y, skeleton.Transforms[i].Rotation.Vector.Z, skeleton.Transforms[i].Rotation.Vector.W)) * Matrix.CreateTranslation(new Vector3( skeleton.Transforms[i].Position.Vector.X, skeleton.Transforms[i].Position.Vector.Y, skeleton.Transforms[i].Position.Vector.Z)); for (int j = 0; j < FlverSkeleton.Count; j++) { if (FlverSkeleton[j].Name == newHkxBone.Name) { FlverSkeleton[j].HkxBoneIndex = i; newHkxBone.FlverBoneIndex = j; break; } } HkxSkeleton.Add(newHkxBone); } Matrix GetAbsoluteReferenceMatrix(int i) { Matrix result = Matrix.Identity; do { result *= HkxSkeleton[i].RelativeReferenceMatrix; i = HkxSkeleton[i].ParentIndex; }while (i >= 0); return(result); } for (int i = 0; i < HkxSkeleton.Count; i++) { HkxSkeleton[i].ReferenceMatrix = GetAbsoluteReferenceMatrix(i); for (int j = 0; j < HkxSkeleton.Count; j++) { if (HkxSkeleton[j].ParentIndex == i) { HkxSkeleton[i].ChildIndices.Add(j); } } if (HkxSkeleton[i].ParentIndex < 0) { RootBoneIndices.Add(i); } } }
public DsBone(FLVER.Bone flverBone, FLVER2 flver, HKX.Bone hkxBone, HKX.HKASkeleton hkaSkeleton) : this(flverBone, flver) { HkxBoneIndex = hkaSkeleton.Bones.GetArrayData().Elements.IndexOf(hkxBone); ParentName = InitializeHkxParentName(hkxBone, hkaSkeleton); }
private static IEnumerable <DsBone> FixupDsBones(HKX.HKASkeleton hkx) { return(hkx.Bones.GetArrayData().Elements.Select(hkxBone => new DsBone(hkxBone, hkx))); }
private static void LoadRemoHKX(byte[] hkxBytes, string animName) { Scene.DisableModelDrawing(); Scene.DisableModelDrawing2(); HKX.HKAAnimationBinding hk_binding = null; HKX.HKASplineCompressedAnimation hk_anim = null; HKX.HKASkeleton hk_skeleton = null; if (remoCutsLoaded.ContainsKey(animName)) { hk_binding = remoCutsLoaded[animName].hk_binding; hk_anim = remoCutsLoaded[animName].hk_anim; hk_skeleton = remoCutsLoaded[animName].hk_skeleton; } else { var hkx = HKX.Read(hkxBytes, HKX.HKXVariation.HKXDS1, false); foreach (var o in hkx.DataSection.Objects) { if (o is HKX.HKASkeleton asSkeleton) { hk_skeleton = asSkeleton; } else if (o is HKX.HKAAnimationBinding asBinding) { hk_binding = asBinding; } else if (o is HKX.HKASplineCompressedAnimation asAnim) { hk_anim = asAnim; } } remoCutsLoaded.Add(animName, new RemoCutCache() { hk_binding = hk_binding, hk_anim = hk_anim, hk_skeleton = hk_skeleton, }); } var animContainer = new NewAnimationContainer(); AnimContainer = animContainer; animContainer.ClearAnimations(); animContainer.Skeleton.LoadHKXSkeleton(hk_skeleton); var testIdleAnimThing = new NewHavokAnimation_SplineCompressed(animName, animContainer.Skeleton, null, hk_binding, hk_anim, animContainer); animContainer.AddNewAnimation(animName, testIdleAnimThing); animContainer.CurrentAnimationName = animName; var modelNames = animContainer.Skeleton.TopLevelHkxBoneIndices.Select(b => animContainer.Skeleton.HkxSkeleton[b].Name).ToList(); CurrentCutHits.Clear(); CurrentCutOtherBlocks.Clear(); lock (Scene._lock_ModelLoad_Draw) { Scene.Models.Clear(); } foreach (var name in modelNames) { Model mdl = null; if (!remoModelDict.ContainsKey(name)) { PauseStreamBGM(); if (name.StartsWith("c")) { string shortName = name.Substring(0, 5); mdl = GameDataManager.LoadCharacter(shortName); FmodManager.LoadInterrootFEV(shortName); if (mdl.IS_PLAYER) { ViewportInteractor.InitializeCharacterModel(mdl, isRemo: true); } } else if (name.StartsWith("o")) { string shortName = name.Substring(0, 5); mdl = GameDataManager.LoadObject(shortName); FmodManager.LoadInterrootFEV(shortName); } else if (name.StartsWith("m")) { mdl = GameDataManager.LoadMapPiece(AreaInt, BlockInt, 0, 0, int.Parse(name.Substring(1, 4))); } else if (name.StartsWith("A")) { int a = int.Parse(name.Substring(1, 2)); int b = int.Parse(name.Substring(4, 2)); if (b != BlockInt && !CurrentCutOtherBlocks.Contains(b)) { CurrentCutOtherBlocks.Add(b); } mdl = GameDataManager.LoadMapPiece(a, b, 0, 0, int.Parse(name.Substring(8, 4))); } else if (name.StartsWith("d")) { // TODO // Dummy entity e.g. 'd0000_0000'. Apparently just acts as a single DummyPoly? mdl = GameDataManager.LoadCharacter("c1000"); mdl.RemoDummyTransformPrim = new DebugPrimitives.DbgPrimWireArrow(name, new Transform(Microsoft.Xna.Framework.Matrix.CreateScale(0.25f) * mdl.CurrentTransform.WorldMatrix), Microsoft.Xna.Framework.Color.Lime) { Category = DebugPrimitives.DbgPrimCategory.AlwaysDraw }; mdl.RemoDummyTransformTextPrint = new StatusPrinter(null, Microsoft.Xna.Framework.Color.Lime); mdl.RemoDummyTransformTextPrint.AppendLine(name); mdl.IS_REMO_DUMMY = true; } else if (name.StartsWith("h")) { // Collision. CurrentCutHits.Add(name); } else { throw new NotImplementedException($"Cannot tell what object type '{name}' is in remo HKX"); } if (mdl != null) { mdl.Name = name; remoModelDict.Add(name, mdl); } } else { mdl = remoModelDict[name]; } if (mdl != null) { mdl.AnimContainer = animContainer; mdl.IsRemoModel = true; mdl.Name = name; mdl.SkeletonFlver.RevertToReferencePose(); mdl.SkeletonFlver.MapToSkeleton(animContainer.Skeleton, isRemo: true); mdl.UpdateSkeleton(); lock (Scene._lock_ModelLoad_Draw) { Scene.Models.Add(mdl); } } } var msbName = GameDataManager.GetInterrootPath($@"map\MapStudio\m{AreaInt:D2}_{BlockInt:D2}_00_00.msb"); var msb = MSB1.Read(msbName); Vector3 mapOffset = msb.Events.MapOffsets.FirstOrDefault()?.Position.ToXna() ?? Vector3.Zero; uint dg1 = 0, dg2 = 0, dg3 = 0, dg4 = 0; foreach (var hitName in CurrentCutHits) { var hit = msb.Parts.Collisions.FirstOrDefault(h => h.Name == hitName); dg1 |= hit.DrawGroups[0]; dg2 |= hit.DrawGroups[1]; dg3 |= hit.DrawGroups[2]; dg4 |= hit.DrawGroups[3]; } bool IsThingVisible(uint[] drawGroups) { return(((drawGroups[0] & dg1) == dg1) && ((drawGroups[1] & dg2) == dg2) && ((drawGroups[2] & dg3) == dg3) && ((drawGroups[3] & dg4) == dg4)); } foreach (var mapPiece in msb.Parts.MapPieces) { var thisEntityName = CurrentCutOtherBlocks.Count > 0 ? $"A{AreaInt:D2}B{BlockInt:D2}_{mapPiece.Name}" : mapPiece.Name; if (IsThingVisible(mapPiece.DrawGroups)) { Model mdl = null; if (remoModelDict.ContainsKey(thisEntityName)) { mdl = remoModelDict[thisEntityName]; mdl.AnimContainer = animContainer; mdl.IsRemoModel = true; mdl.SkeletonFlver.RevertToReferencePose(); mdl.SkeletonFlver.MapToSkeleton(animContainer.Skeleton, isRemo: true); mdl.UpdateSkeleton(); lock (Scene._lock_ModelLoad_Draw) { Scene.Models.Add(mdl); } continue; } mdl = GameDataManager.LoadMapPiece(AreaInt, BlockInt, 0, 0, int.Parse(mapPiece.ModelName.Substring(1, 4))); mdl.AnimContainer = animContainer; mdl.IsRemoModel = true; mdl.Name = thisEntityName; mdl.SkeletonFlver.RevertToReferencePose(); mdl.StartTransform.Position = mapPiece.Position.ToXna() - mapOffset; mdl.StartTransform.Rotation = Utils.EulerToQuaternion((mapPiece.Rotation * (SapMath.Pi / 180f)).ToXna()); mdl.StartTransform.Scale = mapPiece.Scale.ToXna(); mdl.CurrentTransform = mdl.StartTransform; mdl.IS_REMO_NOTSKINNED = true; mdl.SkeletonFlver.MapToSkeleton(animContainer.Skeleton, isRemo: true); mdl.UpdateSkeleton(); lock (Scene._lock_ModelLoad_Draw) { Scene.Models.Add(mdl); } remoModelDict.Add(thisEntityName, mdl); } } foreach (var mapPiece in msb.Parts.Objects) { var thisEntityName = CurrentCutOtherBlocks.Count > 0 ? $"A{AreaInt:D2}B{BlockInt:D2}_{mapPiece.Name}" : mapPiece.Name; if (IsThingVisible(mapPiece.DrawGroups)) { Model mdl = null; if (remoModelDict.ContainsKey(thisEntityName)) { mdl = remoModelDict[thisEntityName]; mdl.AnimContainer = animContainer; mdl.IsRemoModel = true; mdl.SkeletonFlver.RevertToReferencePose(); mdl.SkeletonFlver.MapToSkeleton(animContainer.Skeleton, isRemo: true); mdl.UpdateSkeleton(); lock (Scene._lock_ModelLoad_Draw) { Scene.Models.Add(mdl); } continue; } mdl = GameDataManager.LoadObject(mapPiece.ModelName); mdl.AnimContainer = animContainer; mdl.IsRemoModel = true; mdl.Name = thisEntityName; mdl.StartTransform.Position = mapPiece.Position.ToXna() - mapOffset; mdl.StartTransform.Rotation = Utils.EulerToQuaternion((mapPiece.Rotation * (SapMath.Pi / 180f)).ToXna()); mdl.StartTransform.Scale = mapPiece.Scale.ToXna(); mdl.CurrentTransform = mdl.StartTransform; mdl.IS_REMO_NOTSKINNED = true; mdl.SkeletonFlver.RevertToReferencePose(); mdl.SkeletonFlver.MapToSkeleton(animContainer.Skeleton, isRemo: true); mdl.UpdateSkeleton(); lock (Scene._lock_ModelLoad_Draw) { Scene.Models.Add(mdl); } remoModelDict.Add(thisEntityName, mdl); } } lock (Scene._lock_ModelLoad_Draw) { Scene.Models = Scene.Models.OrderBy(m => m.IS_PLAYER ? 0 : 1).ToList(); } CurrentCut = animName; animContainer.ScrubRelative(0); List <Model> mdls = null; lock (Scene._lock_ModelLoad_Draw) { mdls = Scene.Models.ToList(); } foreach (var m in mdls) { m.UpdateSkeleton(); } GFX.World.Update(0); Scene.EnableModelDrawing(); Scene.EnableModelDrawing2(); ResumeStreamedBGM(); ViewportInteractor.Graph.MainScreen.REMO_HOTFIX_REQUEST_PLAY_RESUME_NEXT_FRAME = true; ViewportInteractor.Graph.MainScreen.HardReset(); }
private byte[] ImportAnimToHKX() { var importedAnim = ImportAnim(); byte[] finalHkxDataToImport = null; var compressed2010Hkx = importedAnim.WriteToSplineCompressedHKX2010Bytes(ImportConfig.RotationQuantizationType, ImportConfig.RotationTolerance); if (GameDataManager.GameType == SoulsAssetPipeline.SoulsGames.DS1R) { finalHkxDataToImport = HavokDowngrade.UpgradeHkx2010to2015(compressed2010Hkx); } else if (GameDataManager.GameType == SoulsAssetPipeline.SoulsGames.DS1) { finalHkxDataToImport = compressed2010Hkx; } else if (GameDataManager.GameType == SoulsAssetPipeline.SoulsGames.DS3) { HKX.HKAAnimationBinding hk_binding = null; HKX.HKASplineCompressedAnimation hk_anim = null; HKX.HKASkeleton hk_skeleton = null; HKX.HKADefaultAnimatedReferenceFrame hk_refFrame = null; var hkx = HKX.Read(compressed2010Hkx); foreach (var o in hkx.DataSection.Objects) { if (o is HKX.HKASkeleton asSkeleton) { hk_skeleton = asSkeleton; } else if (o is HKX.HKAAnimationBinding asBinding) { hk_binding = asBinding; } else if (o is HKX.HKASplineCompressedAnimation asAnim) { hk_anim = asAnim; } else if (o is HKX.HKADefaultAnimatedReferenceFrame asRefFrame) { hk_refFrame = asRefFrame; } } var root = new HKX2.hkRootLevelContainer(); var animBinding = new HKX2.hkaAnimationBinding(); var anim = new HKX2.hkaSplineCompressedAnimation(); animBinding.m_animation = anim; animBinding.m_originalSkeletonName = hk_binding.OriginalSkeletonName; animBinding.m_transformTrackToBoneIndices = hk_binding.TransformTrackToBoneIndices.GetArrayData().Elements.Select(x => x.data).ToList(); animBinding.m_floatTrackToFloatSlotIndices = new List <short>(); animBinding.m_partitionIndices = new List <short>(); animBinding.m_blendHint = (HKX2.BlendHint)(int) hk_binding.BlendHint; anim.m_blockDuration = hk_anim.BlockDuration; anim.m_blockInverseDuration = hk_anim.InverseBlockDuration; anim.m_data = hk_anim.Data.GetArrayData().Elements.Select(x => x.data).ToList(); anim.m_duration = hk_anim.Duration; anim.m_endian = hk_anim.Endian; if (hk_refFrame != null) { var rootMotion = new HKX2.hkaDefaultAnimatedReferenceFrame(); rootMotion.m_duration = hk_refFrame.Duration; rootMotion.m_forward = hk_refFrame.Forward; rootMotion.m_referenceFrameSamples = new List <System.Numerics.Vector4>(); foreach (var rf in hk_refFrame.ReferenceFrameSamples.GetArrayData().Elements) { rootMotion.m_referenceFrameSamples.Add(rf.Vector); } rootMotion.m_up = hk_refFrame.Up; anim.m_extractedMotion = rootMotion; } anim.m_frameDuration = hk_anim.FrameDuration; anim.m_maskAndQuantizationSize = (int)hk_anim.MaskAndQuantization; anim.m_maxFramesPerBlock = hk_anim.FramesPerBlock; anim.m_numberOfFloatTracks = hk_anim.FloatTrackCount; anim.m_numberOfTransformTracks = hk_anim.TransformTrackCount; anim.m_numBlocks = hk_anim.BlockCount; anim.m_numFrames = hk_anim.FrameCount; anim.m_floatBlockOffsets = hk_anim.FloatBlockOffsets.GetArrayData().Elements.Select(b => b.data).ToList(); anim.m_type = HKX2.AnimationType.HK_SPLINE_COMPRESSED_ANIMATION; anim.m_blockOffsets = hk_anim.BlockOffsets.GetArrayData().Elements.Select(b => b.data).ToList(); anim.m_floatOffsets = new List <uint>(); anim.m_transformOffsets = new List <uint>(); //TODO: IMPLEMENT ANNOTATION TRACK READ IN LEGACY HKX TO TRANSFER IT TO HKX2 //anim.m_annotationTracks = new List<HKX2.hkaAnnotationTrack>(); //for (int i = 0; i < hk_anim.TransformTrackCount; i++) //{ // var boneIndex = animBinding.m_transformTrackToBoneIndices[i]; // string boneName = boneNames[boneIndex]; // anim.m_annotationTracks.Add(new HKX2.hkaAnnotationTrack() // { // m_trackName = boneName, // m_annotations = new List<HKX2.hkaAnnotationTrackAnnotation>(), // }); //} var animContainer = new HKX2.hkaAnimationContainer(); animContainer.m_attachments = new List <HKX2.hkaBoneAttachment>(); animContainer.m_skins = new List <HKX2.hkaMeshBinding>(); animContainer.m_skeletons = new List <HKX2.hkaSkeleton>(); animContainer.m_animations = new List <HKX2.hkaAnimation>(); animContainer.m_animations.Add(anim); animContainer.m_bindings = new List <HKX2.hkaAnimationBinding>(); animContainer.m_bindings.Add(animBinding); root.m_namedVariants = new List <HKX2.hkRootLevelContainerNamedVariant>(); root.m_namedVariants.Add(new HKX2.hkRootLevelContainerNamedVariant() { m_className = "hkaAnimationContainer", m_name = "Merged Animation Container", m_variant = animContainer }); using (MemoryStream s2 = new MemoryStream()) { BinaryWriterEx bw = new BinaryWriterEx(false, s2); var s = new HKX2.PackFileSerializer(); s.Serialize(root, bw); finalHkxDataToImport = s2.ToArray(); } } return(finalHkxDataToImport); }