Ejemplo n.º 1
0
        //--------------------------------------------------------------
        #region General Methods
        //--------------------------------------------------------------

        public override TimelineGroup Process(NodeContent input, ContentProcessorContext context)
        {
            // Uncomment this to attach and launch a debugger.
            //System.Diagnostics.Debugger.Launch();

            // Get the skeleton node.
            NodeContent skeleton = FindSkeleton(input);

            if (skeleton == null)
            {
                throw new InvalidContentException("Avatar skeleton not found.", input.Identity);
            }
            if (skeleton.Animations.Count < 1)
            {
                throw new InvalidContentException("No animation was found in the file.", input.Identity);
            }
            if (skeleton.Animations.Count > 1)
            {
                throw new InvalidContentException("More than one animation was found.", input.Identity);
            }

            // Remove the extra bones that we are not using.
            RemoveEndBonesAndFixBoneNames(skeleton);

            // Create a list of the bones from the skeleton hierarchy.
            IList <NodeContent> bones = FlattenSkeleton(skeleton);

            if (bones.Count != AvatarRenderer.BoneCount)
            {
                throw new InvalidContentException("Invalid number of bones found.", input.Identity);
            }

            // Fill the bind pose array with the transforms from the bones.
            foreach (NodeContent bone in bones)
            {
                _bindPoses.Add(bone.Transform);
            }

            // Build up a table mapping bone names to indices.
            _boneNames = new Dictionary <string, int>();
            for (int i = 0; i < bones.Count; i++)
            {
                string boneName = bones[i].Name;
                if (!string.IsNullOrEmpty(boneName))
                {
                    _boneNames.Add(boneName, i);
                }
            }

            // Create the custom animation data.
            // From the error-checking above, we know there will only be one animation.
            AnimationContent                  animationContent    = skeleton.Animations.Values.First();
            SkeletonKeyFrameAnimation         skeletonAnimation   = ProcessSkeletonAnimation(animationContent, context);
            AvatarExpressionKeyFrameAnimation expressionAnimation = ProcessExpressionAnimation(input, context);

            var timelineGroup = new TimelineGroup();

            if (skeletonAnimation != null)
            {
                timelineGroup.Add(skeletonAnimation);
            }
            if (expressionAnimation != null)
            {
                timelineGroup.Add(expressionAnimation);
            }

            return(timelineGroup);
        }
        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,
            });
        }
Ejemplo n.º 3
0
        //--------------------------------------------------------------
        #region Avatar Expression Animation
        //--------------------------------------------------------------

        /// <summary>
        /// Converts the input expression animation file into expression animation keyframes.
        /// </summary>
        private AvatarExpressionKeyFrameAnimation ProcessExpressionAnimation(NodeContent input, ContentProcessorContext context)
        {
            if (string.IsNullOrEmpty(ExpressionFile))
            {
                return(null);
            }

            // Create a AvatarExpression key frame animation that will animate the Expression
            // property of an AvatarPose.
            var animation = new AvatarExpressionKeyFrameAnimation
            {
                TargetProperty = "Expression",
            };

            // Let the content pipeline know that we depend on this file and we need to rebuild the
            // content if the file is modified.
            string sourcePath = Path.GetDirectoryName(input.Identity.SourceFilename);
            string filePath   = Path.GetFullPath(Path.Combine(sourcePath, ExpressionFile));

            context.AddDependency(filePath);

            FileStream   fs = File.OpenRead(filePath);
            StreamReader sr = new StreamReader(fs);

            while (!sr.EndOfStream)
            {
                string currentLine = sr.ReadLine();

                // Skip comment lines
                if (currentLine.StartsWith("#"))
                {
                    continue;
                }

                string[] Components = currentLine.Split(',');

                // Check for the correct number of components
                if (Components.Length != 6)
                {
                    throw new InvalidContentException("Error processing facial expression file", input.Identity);
                }

                try
                {
                    TimeSpan         time             = TimeSpan.FromMilliseconds(Convert.ToDouble(Components[0]));
                    AvatarExpression avatarExpression = new AvatarExpression();
                    avatarExpression.LeftEye      = (AvatarEye)Convert.ToInt32(Components[1]);
                    avatarExpression.LeftEyebrow  = (AvatarEyebrow)Convert.ToInt32(Components[2]);
                    avatarExpression.Mouth        = (AvatarMouth)Convert.ToInt32(Components[3]);
                    avatarExpression.RightEye     = (AvatarEye)Convert.ToInt32(Components[4]);
                    avatarExpression.RightEyebrow = (AvatarEyebrow)Convert.ToInt32(Components[5]);

                    // Add key frame.
                    var keyFrame = new KeyFrame <AvatarExpression>(time, avatarExpression);
                    animation.KeyFrames.Add(keyFrame);
                }
                catch (Exception)
                {
                    throw new InvalidContentException("Error processing facial expression file", input.Identity);
                }
            }

            if (animation.KeyFrames.Count == 0)
            {
                return(null);
            }

            // Sort the animation frames
            animation.KeyFrames.Sort();

            return(animation);
        }
Ejemplo n.º 4
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,
      };
    }