private static void LoadRawAnimationFromFile(Animation anim, string directory, string filename) { Debug.Log("Loading Motion from file \"" + filename + "\""); // Open given file and split the lines TextAsset moCapAsset = Resources.Load <TextAsset>(directory + "/" + filename); if (moCapAsset == null) { Debug.LogError("Unable to load MoCap file: " + filename); return; } string[] data = moCapAsset.text.Split( new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None ); // Read Bone names (Frame 0) var bonesLine = data[0]; var bones = bonesLine.Split(','); // Add all frames to the current Animation (excl. first line (Titles) and last line (empty)) for (var currentFrame = 1; currentFrame < data.Length - 1; currentFrame += CharacterController.SkipFrames) { // Pass the current timestamp to the Frame constructor var dataFrame = data[currentFrame].Split(','); Frame newFrame = new Frame(float.Parse(dataFrame[0])); // Every bone has data in 7 columns (3 position, 4 rotation) foreach (Bone.Type bt in Enum.GetValues(typeof(Bone.Type))) { int off = (int)bt * 7; Bone.Data currentBoneData = new Bone.Data( new Vector3( float.Parse(dataFrame[off + 1]), // Start from 1 because of the Timestamp on 0 float.Parse(dataFrame[off + 2]), float.Parse(dataFrame[off + 3]) ), new Quaternion( float.Parse(dataFrame[off + 4]), float.Parse(dataFrame[off + 5]), float.Parse(dataFrame[off + 6]), float.Parse(dataFrame[off + 7]) ) ); // Create the new Frame newFrame.boneDataDict.Add(bt, currentBoneData); } // Add the new Frame to the current Motion anim.frameList.Add(newFrame); } Debug.Log("Motion contains " + anim.frameList.Count + " frames"); // Unload Asset to free Memory Resources.UnloadAsset(moCapAsset); }
private static (Vector3S, Quaternion) LerpFrame(Bone.Data a, Bone.Data b, float t) { return(Vector3.Lerp((Vector3)a.position, (Vector3)b.position, t), Quaternion.Lerp((Quaternion)a.rotation, (Quaternion)b.rotation, t)); }
private static void ComputeRootTransform(Animation anim) { List <Bone.Data> rootSamples = new List <Bone.Data>(); // 1. Sample the root transform every SampleWindow frames for ( int currentFrame = 0; currentFrame + SampleWindow < anim.frameList.Count; currentFrame += SampleWindow) { Bone.Data sample = SampleFromFrame(anim, currentFrame); rootSamples.Add(sample); } // 2. Use sample to determine intermediate values // Left padding for ( int currentFrame = 0; currentFrame < SampleWindow / 2; currentFrame++) { // Lerp to find a smooth transform (Vector3S position, Quaternion rotation) = LerpFrame( anim.frameList[0].boneDataDict[Bone.Type.hips], rootSamples[0], (float)currentFrame / (SampleWindow / 2)); /// Store found value anim.frameList[currentFrame].boneDataDict[Bone.Type.root].position = position; anim.frameList[currentFrame].boneDataDict[Bone.Type.root].rotation = rotation; } // Intermediate frames for ( int currentSample = 0; currentSample < rootSamples.Count - 1; currentSample++) { for ( int currentFrame = 0; currentFrame < SampleWindow; currentFrame++) { // Compute current offset int currentOffset = currentSample * SampleWindow + currentFrame + SampleWindow / 2; // Lerp to find a smooth transform (Vector3S position, Quaternion rotation) = LerpFrame( rootSamples[currentSample], rootSamples[currentSample + 1], currentFrame / SampleWindow); /// Store found value anim.frameList[currentOffset].boneDataDict[Bone.Type.root].position = position; anim.frameList[currentOffset].boneDataDict[Bone.Type.root].rotation = rotation; Debug.Log("root rotation: " + anim.frameList[currentOffset].boneDataDict[Bone.Type.root].rotation.eulerAngles); } } // Right padding int rightPaddingFrames = SampleWindow / 2 + anim.frameList.Count % SampleWindow; int firstPaddingFrame = anim.frameList.Count - rightPaddingFrames; for ( int currentFrameOffset = 0; currentFrameOffset < rightPaddingFrames; currentFrameOffset++) { // Compute current offset int currentOffset = firstPaddingFrame + currentFrameOffset; // Lerp to find a smooth transform (Vector3S position, Quaternion rotation) = LerpFrame( rootSamples[rootSamples.Count - 1], anim.frameList[anim.frameList.Count - 1].boneDataDict[Bone.Type.hips], currentFrameOffset / rightPaddingFrames); /// Store found value anim.frameList[currentOffset].boneDataDict[Bone.Type.root].position = position; anim.frameList[currentOffset].boneDataDict[Bone.Type.root].rotation = rotation; } // 3. Recalibrate hips to comply with root's rotation //for ( // int currentFrame = 0; // currentFrame < anim.frameList.Count; // currentFrame++) //{ // anim.frameList[currentFrame].boneDataDict[Bone.Type.hips].position -= // anim.frameList[currentFrame].boneDataDict[Bone.Type.root].position; // anim.frameList[currentFrame].boneDataDict[Bone.Type.hips].rotation = // anim.frameList[currentFrame].boneDataDict[Bone.Type.hips].rotation * // Quaternion.Inverse(anim.frameList[currentFrame].boneDataDict[Bone.Type.root].rotation); //} }