public static TransformTrack FromKeyframes(KeyframeTrack keyframes) { var track = new TransformTrack(); track.Flags = 0; var translateTimes = keyframes.Keyframes.Where(f => f.Value.HasTranslation).Select(f => f.Key).ToList(); var translations = keyframes.Keyframes.Where(f => f.Value.HasTranslation).Select(f => f.Value.Translation).ToList(); if (translateTimes.Count == 1) { var posCurve = new D3Constant32f(); posCurve.CurveDataHeader_D3Constant32f = new CurveDataHeader { Format = (int)CurveFormat.D3Constant32f, Degree = 2 }; posCurve.Controls = new float[3] { translations[0].X, translations[0].Y, translations[0].Z }; track.PositionCurve = new AnimationCurve { CurveData = posCurve }; } else { var posCurve = new DaK32fC32f(); posCurve.CurveDataHeader_DaK32fC32f = new CurveDataHeader { Format = (int)CurveFormat.DaK32fC32f, Degree = 2 }; posCurve.SetKnots(translateTimes); posCurve.SetPoints(translations); track.PositionCurve = new AnimationCurve { CurveData = posCurve }; } var rotationTimes = keyframes.Keyframes.Where(f => f.Value.HasRotation).Select(f => f.Key).ToList(); var rotations = keyframes.Keyframes.Where(f => f.Value.HasRotation).Select(f => f.Value.Rotation).ToList(); if (rotationTimes.Count == 1) { var rotCurve = new D4Constant32f(); rotCurve.CurveDataHeader_D4Constant32f = new CurveDataHeader { Format = (int)CurveFormat.D4Constant32f, Degree = 2 }; rotCurve.Controls = new float[4] { rotations[0].X, rotations[0].Y, rotations[0].Z, rotations[0].W }; track.OrientationCurve = new AnimationCurve { CurveData = rotCurve }; } else { var rotCurve = new DaK32fC32f(); rotCurve.CurveDataHeader_DaK32fC32f = new CurveDataHeader { Format = (int)CurveFormat.DaK32fC32f, Degree = 2 }; rotCurve.SetKnots(rotationTimes); rotCurve.SetQuaternions(rotations); track.OrientationCurve = new AnimationCurve { CurveData = rotCurve }; } var scaleTimes = keyframes.Keyframes.Where(f => f.Value.HasScaleShear).Select(f => f.Key).ToList(); var scales = keyframes.Keyframes.Where(f => f.Value.HasScaleShear).Select(f => f.Value.ScaleShear).ToList(); if (scaleTimes.Count == 1) { var scaleCurve = new DaConstant32f(); scaleCurve.CurveDataHeader_DaConstant32f = new CurveDataHeader { Format = (int)CurveFormat.DaConstant32f, Degree = 2 }; var m = scales[0]; scaleCurve.Controls = new List <float> { m[0, 0], m[0, 1], m[0, 2], m[1, 0], m[1, 1], m[1, 2], m[2, 0], m[2, 1], m[2, 2] }; track.ScaleShearCurve = new AnimationCurve { CurveData = scaleCurve }; } else { var scaleCurve = new DaK32fC32f(); scaleCurve.CurveDataHeader_DaK32fC32f = new CurveDataHeader { Format = (int)CurveFormat.DaK32fC32f, Degree = 2 }; scaleCurve.SetKnots(scaleTimes); scaleCurve.SetMatrices(scales); track.ScaleShearCurve = new AnimationCurve { CurveData = scaleCurve }; } return(track); }
public TransformTrack MakeTrack() { var track = new TransformTrack(); track.Flags = 0; track.Name = Bone.Name; var positions = Transforms.Select(m => m.ExtractTranslation()).ToList(); var rotations = Transforms.Select(m => m.ExtractRotation()).ToList(); var scales = Transforms.Select(m => ScaleToScaleShear(m.ExtractScale())).ToList(); // Quaternion sign fixup // Since GR2 interpolation operates on the raw XYZ values of the quaternion, two subsequent quaternions // that express the same rotation (eg. [1, 0.5, 0.5, -0.5] and [1, -0.5, -0.5, 0.5]) will result in a 360 deg // rotation during the animation. Shuffle XYZ signs around to make this less likely to happen for (var i = 1; i < rotations.Count; i++) { var r0 = rotations[i - 1]; var r1 = rotations[i]; var dot = r0.W * r1.W + r0.X * r1.X + r0.Y * r1.Y + r0.Z * r1.Z; if (dot < 0.0) { rotations[i] = new Quaternion(-r1.X, -r1.Y, -r1.Z, r1.W); } } var posTimes = Times; var minPositions = positions; RemoveTrivialFrames(ref posTimes, ref minPositions); if (minPositions.Count == 1) { var posCurve = new D3Constant32f(); posCurve.CurveDataHeader_D3Constant32f = new CurveDataHeader { Format = (int)CurveFormat.D3Constant32f, Degree = 2 }; posCurve.Controls = new float[3] { positions[0].X, positions[0].Y, positions[0].Z }; track.PositionCurve = new AnimationCurve { CurveData = posCurve }; } else { var posCurve = new DaK32fC32f(); posCurve.CurveDataHeader_DaK32fC32f = new CurveDataHeader { Format = (int)CurveFormat.DaK32fC32f, Degree = 2 }; posCurve.SetKnots(Times); posCurve.SetPoints(positions); track.PositionCurve = new AnimationCurve { CurveData = posCurve }; } var rotTimes = Times; var minRotations = rotations; RemoveTrivialFrames(ref rotTimes, ref minRotations); if (minRotations.Count == 1) { var rotCurve = new D4Constant32f(); rotCurve.CurveDataHeader_D4Constant32f = new CurveDataHeader { Format = (int)CurveFormat.D4Constant32f, Degree = 2 }; rotCurve.Controls = new float[4] { rotations[0].X, rotations[0].Y, rotations[0].Z, rotations[0].W }; track.OrientationCurve = new AnimationCurve { CurveData = rotCurve }; } else { var rotCurve = new DaK32fC32f(); rotCurve.CurveDataHeader_DaK32fC32f = new CurveDataHeader { Format = (int)CurveFormat.DaK32fC32f, Degree = 2 }; rotCurve.SetKnots(Times); rotCurve.SetQuaternions(rotations); track.OrientationCurve = new AnimationCurve { CurveData = rotCurve }; } var scaleTimes = Times; var minScales = scales; RemoveTrivialFrames(ref scaleTimes, ref minScales); if (minScales.Count == 1) { var scaleCurve = new DaConstant32f(); scaleCurve.CurveDataHeader_DaConstant32f = new CurveDataHeader { Format = (int)CurveFormat.DaConstant32f, Degree = 2 }; var m = minScales[0]; scaleCurve.Controls = new List <float> { m[0, 0], m[0, 1], m[0, 2], m[1, 0], m[1, 1], m[1, 2], m[2, 0], m[2, 1], m[2, 2] }; track.ScaleShearCurve = new AnimationCurve { CurveData = scaleCurve }; } else { var scaleCurve = new DaK32fC32f(); scaleCurve.CurveDataHeader_DaK32fC32f = new CurveDataHeader { Format = (int)CurveFormat.DaK32fC32f, Degree = 2 }; scaleCurve.SetKnots(Times); scaleCurve.SetMatrices(scales); track.ScaleShearCurve = new AnimationCurve { CurveData = scaleCurve }; } return(track); }