public void Draw(IList<Matrix> bones, AvatarExpression expression) { throw new NotImplementedException(); }
/// <summary> /// Updates the expression with the correct keyframes based on the current time. /// </summary> /// <param name="playingForward"> /// If true, the animation is playing forward; otherwise, it is playing backwards /// </param> private void UpdateAvatarExpression(bool playingForward) { // Check to see if we have an expression animation if (ExpressionKeyframes == null || ExpressionKeyframes.Count == 0) return; if (playingForward) { while (currentExpressionKeyframe < ExpressionKeyframes.Count) { // Get the current keyframe AvatarExpressionKeyFrame keyframe = ExpressionKeyframes[currentExpressionKeyframe]; // Stop when we've read up to the current time. if (keyframe.Time >= currentPosition) break; // Set the current expression avatarExpression = keyframe.Expression; // Move the current keyframe forward. currentExpressionKeyframe++; } } else { while (currentExpressionKeyframe >= 0) { // Get the current keyframe AvatarExpressionKeyFrame keyframe = ExpressionKeyframes[currentExpressionKeyframe]; // Stop when we've read back to the current time. if (keyframe.Time <= currentPosition) break; // Set the current expression avatarExpression = keyframe.Expression; // Move the current keyframe backwards. currentExpressionKeyframe--; } } }
public void Draw(IList <Matrix> bones, AvatarExpression expression) { throw new NotImplementedException(); }
private ITimeline BakeAnimation(AvatarAnimation avatarAnimation) { // Create an AvatarExpression key frame animation that will be applied to the Expression // property of an AvatarPose. AvatarExpressionKeyFrameAnimation expressionAnimation = new AvatarExpressionKeyFrameAnimation { TargetProperty = "Expression" }; // Create a SkeletonPose key frame animation that will be applied to the SkeletonPose // property of an AvatarPose. SkeletonKeyFrameAnimation skeletonKeyFrameAnimation = new SkeletonKeyFrameAnimation { TargetProperty = "SkeletonPose" }; // In the next loop, we sample the original animation with 30 Hz and store the key frames. int numberOfKeyFrames = 0; AvatarExpression previousExpression = new AvatarExpression(); TimeSpan time = TimeSpan.Zero; TimeSpan length = avatarAnimation.Length; TimeSpan step = new TimeSpan(333333); // 1/30 seconds; while (true) { // Advance time in AvatarAnimation. avatarAnimation.CurrentPosition = time; // Add expression key frame if this is the first key frame or if the key frame is // different from the last key frame. AvatarExpression expression = avatarAnimation.Expression; if (time == TimeSpan.Zero || !expression.Equals(previousExpression)) expressionAnimation.KeyFrames.Add(new KeyFrame<AvatarExpression>(time, expression)); previousExpression = expression; // Convert bone transforms to SrtTransforms and add key frames to the SkeletonPose // animation. for (int i = 0; i < avatarAnimation.BoneTransforms.Count; i++) { SrtTransform boneTransform = SrtTransform.FromMatrix(avatarAnimation.BoneTransforms[i]); skeletonKeyFrameAnimation.AddKeyFrame(i, time, boneTransform); numberOfKeyFrames++; } // Abort if we have arrived at the end time. if (time == length) break; // Increase time. We check that we do not step over the end time. if (time + step > length) time = length; else time += step; } // Compress animation to save memory. float numberOfRemovedKeyFrames = skeletonKeyFrameAnimation.Compress(0.1f, 0.1f, 0.001f); Debug.WriteLine("Compression removed " + numberOfRemovedKeyFrames * 100 + "% of the key frames."); // Finalize the skeleton key frame animation. This optimizes the internal data structures. skeletonKeyFrameAnimation.Freeze(); return new TimelineGroup { expressionAnimation, skeletonKeyFrameAnimation, }; }
/// <summary> /// Constructs a new CustomAvatarAnimationPlayer object. /// </summary> /// <param name="name">The name of the animation.</param> /// <param name="length">The length of the animation.</param> /// <param name="keyframes">The keyframes in the animation.</param> public CustomAvatarAnimation(string name, TimeSpan length, List<AvatarKeyFrame> keyframes) : base(name, length, keyframes) { // Reset the current bone transforms for (int i = 0; i < AvatarRenderer.BoneCount; i++) avatarBoneTransforms[i] = Matrix.Identity; BoneTransforms = new ReadOnlyCollection<Matrix>( avatarBoneTransforms ); Expression = new AvatarExpression(); // Update the current bone transforms to the first position in the animation Update(TimeSpan.Zero, false); }
/// <summary></summary> protected override void OnEndProcessAnimation() { Matrix identity = Matrix.Identity; overrideExpression = false; expression = new Microsoft.Xna.Framework.GamerServices.AvatarExpression(); foreach (AnimationStreamControl animation in this.animations) { AvatarAnimationStreamControl anim = animation as AvatarAnimationStreamControl; if (anim != null) { overrideExpression |= anim.GetExpression(ref expression); float weight = anim.WeightedScale; if (weight == 0) continue; Matrix matrix; if (weight == 1) { //mult the bone matrices... for (int i = 0; i < this.boneList.Length; i++) { matrix = anim.BoneTransforms[i]; Transform transform = new Transform(ref matrix); Transform.Multiply(ref this.transformedBones[i], ref transform, out this.transformedBones[i]); } } else { for (int i = 0; i < this.boneList.Length; i++) { //matrices are annoying to lerp... //so.. use a transform. matrix = anim.BoneTransforms[i]; Transform transform = new Transform(ref matrix); transform.InterpolateToIdentity(weight); Transform.Multiply(ref this.transformedBones[i], ref transform, out this.transformedBones[i]); } } } } if (this.parent.sourceData != null && boneModifierBuffer != null) { boneModifierBuffer.ProcessAvatarBones(this.transformedBones, parent.sourceData, new ReadOnlyArrayCollection<Transform>(parent.bindPoseWorld), new ReadOnlyArrayCollection<Transform>(parent.bindPoseWorldInverse)); } for (int i = 0; i < this.transformedBones.Length; i++) { this.transformedBones[i].GetMatrix(out this.boneList[i]); } if (this.parent.sourceData != null && boneModifierBuffer != null && boneModifierBuffer.CallProcessReadonlyHierarchyTransformedBones) { this.parent.sourceData.skeleton.TransformHierarchy(this.transformedBones); boneModifierBuffer.ProcessReadonlyHierarchyTransformedBones(this.transformedBones, parent.sourceData, new ReadOnlyArrayCollection<Transform>(parent.bindPoseWorld), new ReadOnlyArrayCollection<Transform>(parent.bindPoseWorldInverse)); } }
internal bool GetExpressionOverride(ref Microsoft.Xna.Framework.GamerServices.AvatarExpression expression) { if (overrideExpression) expression = this.expression; return overrideExpression; }
/// <summary> /// Constructs a new AvatarExpressionKeyFrame object. /// </summary> public AvatarExpressionKeyFrame(TimeSpan time, AvatarExpression expression) { Time = time; Expression = expression; }