public H3DAnimation ToH3DSkeletalAnimation(H3DDict <H3DBone> Skeleton) { H3DAnimation Output = new H3DAnimation() { Name = "GFMotion", FramesCount = FramesCount, AnimationType = H3DAnimationType.Skeletal }; foreach (GF1MotBoneTransform Bone in Bones) { H3DAnimTransform Transform = new H3DAnimTransform(); SetKeyFrameGroup(Bone.TranslationX, Transform.TranslationX, 0); SetKeyFrameGroup(Bone.TranslationY, Transform.TranslationY, 1); SetKeyFrameGroup(Bone.TranslationZ, Transform.TranslationZ, 2); SetKeyFrameGroup(Bone.RotationX, Transform.RotationX, 3); SetKeyFrameGroup(Bone.RotationY, Transform.RotationY, 4); SetKeyFrameGroup(Bone.RotationZ, Transform.RotationZ, 5); SetKeyFrameGroup(Bone.ScaleX, Transform.ScaleX, 6); SetKeyFrameGroup(Bone.ScaleY, Transform.ScaleY, 7); SetKeyFrameGroup(Bone.ScaleZ, Transform.ScaleZ, 8); Output.Elements.Add(new H3DAnimationElement() { Name = Bone.Name, Content = Transform, TargetType = H3DTargetType.Bone, PrimitiveType = H3DPrimitiveType.Transform }); } //If we don't have a Skeleton then can't convert anything, just return with //what we have. if (Skeleton == null) { return(Output); } /* * Transform World Space bones to Local Space. * Not all animations have those. * This can be improved, for example, by supporting Scales aswell, * and checking for the special case where the World Space bone have no parent. * Those cases doesn't actually happen in any of the observed animations, * but it's always good pratice to check all fail paths. */ int AnimIdx = 0; foreach (GF1MotBoneTransform Bone in Bones) { if (Bone.IsWorldSpace) { if (!Skeleton.Contains(Bone.Name)) { break; } H3DBone PoseBone = Skeleton[Bone.Name]; Vector3[] LocalTrans = new Vector3[FramesCount + 1]; Vector3[] ParentRot = new Vector3[FramesCount + 1]; int BoneIndex = Skeleton.Find(Bone.Name); int ParentIndex = Skeleton[BoneIndex].ParentIndex; string ParentName = Skeleton[ParentIndex].Name; for (int Frame = 0; Frame < FramesCount + 1; Frame++) { Matrix4x4 Transform = Matrix4x4.Identity; int b = BoneIndex; while ((b = Skeleton[b].ParentIndex) != -1) { GetBoneRT( Output, Skeleton, Skeleton[b].Name, Frame, out Vector3 R, out Vector3 T); Transform *= Matrix4x4.CreateRotationX(R.X); Transform *= Matrix4x4.CreateRotationY(R.Y); Transform *= Matrix4x4.CreateRotationZ(R.Z); Transform *= Matrix4x4.CreateTranslation(T); } GetBoneRT( Output, Skeleton, ParentName, Frame, out Vector3 PR, out Vector3 PT); GetBoneRT( Output, Skeleton, Bone.Name, Frame, out Vector3 BR, out Vector3 BT); Matrix4x4.Invert(Transform, out Matrix4x4 ITransform); BT = Vector3.Transform(BT, ITransform); Quaternion Rotation = VectorExtensions.CreateRotationBetweenVectors(PT, BT); LocalTrans[Frame] = Vector3.Transform(BT, Quaternion.Inverse(Rotation)); ParentRot[Frame] = Rotation.ToEuler(); } H3DAnimationElement B_Anim = Output.Elements[AnimIdx]; H3DAnimationElement P_Anim = Output.Elements.Find(x => x.Name == ParentName); if (P_Anim == null) { P_Anim = new H3DAnimationElement() { Name = ParentName, Content = new H3DAnimTransform(), TargetType = H3DTargetType.Bone, PrimitiveType = H3DPrimitiveType.Transform }; Output.Elements.Add(P_Anim); } H3DAnimTransform B_AT = (H3DAnimTransform)B_Anim.Content; H3DAnimTransform P_AT = (H3DAnimTransform)P_Anim.Content; AddVectors(LocalTrans, B_AT.TranslationX, B_AT.TranslationY, B_AT.TranslationZ); if (!P_AT.RotationExists) { AddVectors(ParentRot, P_AT.RotationX, P_AT.RotationY, P_AT.RotationZ); } } AnimIdx++; } return(Output); }