예제 #1
0
    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>
        /// Converts an AnimationContent to a SkeletonKeyFrameAnimation.
        /// </summary>
        private SkeletonKeyFrameAnimation ProcessAnimation(AnimationContent animationContent, Skeleton skeleton, ContentProcessorContext context)
        {
            var animation = new SkeletonKeyFrameAnimation { EnableInterpolation = true };

              // Process all animation channels (each channel animates a bone).
              int numberOfKeyFrames = 0;
              foreach (var item in animationContent.Channels)
              {
            string channelName = item.Key;
            AnimationChannel channel = item.Value;

            int boneIndex = skeleton.GetIndex(channelName);
            if (boneIndex == -1)
            {
              var message = string.Format("Found animation for bone '{0}', which is not part of the skeleton.", channelName);
              throw new InvalidContentException(message, animationContent.Identity);
            }

            var bindPoseRelativeInverse = skeleton.GetBindPoseRelative(boneIndex).Inverse;
            foreach (AnimationKeyframe keyframe in channel)
            {
              TimeSpan time = keyframe.Time;
              SrtTransform transform = SrtTransform.FromMatrix(keyframe.Transform);

              // The matrix in the key frame is the transformation in the coordinate space of the
              // parent bone. --> Convert it to a transformation relative to the animated bone.
              transform = bindPoseRelativeInverse * transform;

              // To start with minimal numerical errors, we normalize the rotation quaternion.
              transform.Rotation.Normalize();

              animation.AddKeyFrame(boneIndex, time, transform);
              numberOfKeyFrames++;
            }
              }

              if (numberOfKeyFrames == 0)
            throw new InvalidContentException("Animation has no keyframes.", animationContent.Identity);

             // Compress animation to safe memory.
              float removedKeyFrames = animation.Compress(
            CompressionScaleThreshold,
            CompressionRotationThreshold,
            CompressionTranslationThreshold);

              if (removedKeyFrames > 0)
            context.Logger.LogImportantMessage("{0}: Compression removed {1:P} of all key frames.",
                                           animationContent.Name,
                                           removedKeyFrames);

              // Finalize the animation. (Optimizes the animation data for fast runtime access.)
              animation.Freeze();

              return animation;
        }
        private SkeletonKeyFrameAnimation BuildAnimation(AnimationContent animationContent)
        {
            string name = animationContent.Name;

              // Add loop frame?
              bool addLoopFrame = false;
              if (_modelDescription != null)
              {
            var animationDescription = _modelDescription.Animation;
            if (animationDescription != null)
            {
              addLoopFrame = animationDescription.AddLoopFrame ?? false;

              if (animationDescription.Splits != null)
              {
            foreach (var split in animationDescription.Splits)
            {
              if (split.Name == name)
              {
                if (split.AddLoopFrame.HasValue)
                  addLoopFrame = split.AddLoopFrame.Value;

                break;
              }
            }
              }
            }
              }

              var animation = new SkeletonKeyFrameAnimation { EnableInterpolation = true };

              // Process all animation channels (each channel animates a bone).
              int numberOfKeyFrames = 0;
              foreach (var item in animationContent.Channels)
              {
            string channelName = item.Key;
            AnimationChannel channel = item.Value;

            int boneIndex = _skeleton.GetIndex(channelName);
            if (boneIndex != -1)
            {
              SrtTransform? loopFrame = null;

              var bindPoseRelativeInverse = _skeleton.GetBindPoseRelative(boneIndex).Inverse;
              foreach (AnimationKeyframe keyframe in channel)
              {
            TimeSpan time = keyframe.Time;
            SrtTransform transform = SrtTransform.FromMatrix(keyframe.Transform);

            // The matrix in the key frame is the transformation in the coordinate space of the
            // parent bone. --> Convert it to a transformation relative to the animated bone.
            transform = bindPoseRelativeInverse * transform;

            // To start with minimal numerical errors, we normalize the rotation quaternion.
            transform.Rotation.Normalize();

            if (loopFrame == null)
              loopFrame = transform;

            if (!addLoopFrame || time < animationContent.Duration)
              animation.AddKeyFrame(boneIndex, time, transform);

            numberOfKeyFrames++;
              }

              if (addLoopFrame && loopFrame.HasValue)
            animation.AddKeyFrame(boneIndex, animationContent.Duration, loopFrame.Value);
            }
            else
            {
              _context.Logger.LogWarning(
            null, animationContent.Identity,
            "Found animation for bone \"{0}\", which is not part of the skeleton.",
            channelName);
            }
              }

              if (numberOfKeyFrames == 0)
              {
            _context.Logger.LogWarning(null, animationContent.Identity, "Animation is ignored because it has no keyframes.");
            return null;
              }

              // Compress animation to save memory.
              if (_modelDescription != null)
              {
            var animationDescription = _modelDescription.Animation;
            if (animationDescription != null)
            {
              float removedKeyFrames = animation.Compress(
            animationDescription.ScaleCompression,
            animationDescription.RotationCompression,
            animationDescription.TranslationCompression);

              if (removedKeyFrames > 0)
              {
            _context.Logger.LogImportantMessage("{0}: Compression removed {1:P} of all key frames.",
                                                string.IsNullOrEmpty(name) ? "Unnamed" : name,
                                                removedKeyFrames);
              }
            }
              }

              // Finalize the animation. (Optimizes the animation data for fast runtime access.)
              animation.Freeze();

              return animation;
        }