private void ConformAnimationBindPoses(Skeleton skeleton, Skeleton conformToSkeleton) { foreach (var trackGroup in Root.TrackGroups) { for (var i = 0; i < trackGroup.TransformTracks.Count; i++) { var track = trackGroup.TransformTracks[i]; var bone = skeleton.GetBoneByName(track.Name); if (bone == null) { string msg = String.Format("Animation track references bone '{0}' that cannot be found in the skeleton.", track.Name); throw new ExportException(msg); } var conformingBone = conformToSkeleton.GetBoneByName(track.Name); if (conformingBone == null) { string msg = String.Format("Animation track references bone '{0}' that cannot be found in the conforming skeleton.", track.Name); throw new ExportException(msg); } var keyframes = track.ToKeyframes(); keyframes.SwapBindPose(bone.OriginalTransform, conformingBone.Transform.ToMatrix4()); var newTrack = TransformTrack.FromKeyframes(keyframes); newTrack.Flags = track.Flags; newTrack.Name = track.Name; newTrack.ParentAnimation = track.ParentAnimation; trackGroup.TransformTracks[i] = newTrack; } } }
public List <animation> ExportTrack(TransformTrack track) { var anims = new List <animation>(); var name = "Bone_" + track.Name.Replace(' ', '_'); // Export all tracks in a single transform anims.AddRange(ExportKeyframeTrack(track, name + "_Transform", name + "/Transform")); return(anims); }
private void ConformAnimationBindPoses(Skeleton skeleton, Skeleton conformToSkeleton) { if (Root.TrackGroups == null) { return; } foreach (var trackGroup in Root.TrackGroups) { for (var i = 0; i < trackGroup.TransformTracks.Count; i++) { var track = trackGroup.TransformTracks[i]; var bone = skeleton.GetBoneByName(track.Name); if (bone == null) { //Dummy_Foot -> Dummy_Foot_01 bone = skeleton.GetBoneByName(track.Name + "_01"); } if (bone == null) { throw new ExportException($"Animation track references bone '{track.Name}' that cannot be found in the skeleton '{skeleton.Name}'."); } var conformingBone = conformToSkeleton.GetBoneByName(bone.Name); if (conformingBone == null) { throw new ExportException($"Animation track references bone '{bone.Name}' that cannot be found in the conforming skeleton '{conformToSkeleton.Name}'."); } var keyframes = track.ToKeyframes(); keyframes.SwapBindPose(bone.OriginalTransform, conformingBone.Transform.ToMatrix4()); var newTrack = TransformTrack.FromKeyframes(keyframes); newTrack.Flags = track.Flags; newTrack.Name = track.Name; newTrack.ParentAnimation = track.ParentAnimation; trackGroup.TransformTracks[i] = newTrack; } } }
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; }
public List <animation> ExportKeyframeTrack(TransformTrack transformTrack, string name, string target) { var track = transformTrack.ToKeyframes(); track.MergeAdjacentFrames(); track.InterpolateFrames(); var anims = new List <animation>(); var inputs = new List <InputLocal>(); var outputs = new List <float>(track.Keyframes.Count * 16); foreach (var keyframe in track.Keyframes.Values) { var transform = keyframe.ToTransform().ToMatrix4(); transform.Transpose(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { outputs.Add(transform[i, j]); } } } var interpolations = new List <string>(track.Keyframes.Count); for (int i = 0; i < track.Keyframes.Count; i++) { interpolations.Add("LINEAR"); } var knots = new List <float>(track.Keyframes.Count); foreach (var keyframe in track.Keyframes) { knots.Add(keyframe.Key); } /* * Fix up animations that have only one keyframe by adding another keyframe at * the end of the animation. * (This mainly applies to DaIdentity and DnConstant32f) */ if (track.Keyframes.Count == 1) { knots.Add(transformTrack.ParentAnimation.Duration); for (int i = 0; i < 16; i++) { outputs.Add(outputs[i]); } interpolations.Add(interpolations[0]); } var knotsSource = ColladaUtils.MakeFloatSource(name, "inputs", new string[] { "TIME" }, knots.ToArray()); var knotsInput = new InputLocal(); knotsInput.semantic = "INPUT"; knotsInput.source = "#" + knotsSource.id; inputs.Add(knotsInput); var outSource = ColladaUtils.MakeFloatSource(name, "outputs", new string[] { "TRANSFORM" }, outputs.ToArray(), 16, "float4x4"); var outInput = new InputLocal(); outInput.semantic = "OUTPUT"; outInput.source = "#" + outSource.id; inputs.Add(outInput); var interpSource = ColladaUtils.MakeNameSource(name, "interpolations", new string[] { "INTERPOLATION" }, interpolations.ToArray()); var interpInput = new InputLocal(); interpInput.semantic = "INTERPOLATION"; interpInput.source = "#" + interpSource.id; inputs.Add(interpInput); var sampler = new sampler(); sampler.id = name + "_sampler"; sampler.input = inputs.ToArray(); var channel = new channel(); channel.source = "#" + sampler.id; channel.target = target; var animation = new animation(); animation.id = name; animation.name = name; var animItems = new List <object>(); animItems.Add(knotsSource); animItems.Add(outSource); animItems.Add(interpSource); animItems.Add(sampler); animItems.Add(channel); animation.Items = animItems.ToArray(); anims.Add(animation); return(anims); }
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); }