public LookAtIKSample(Microsoft.Xna.Framework.Game game) : base(game) { var modelNode = ContentManager.Load<ModelNode>("Dude/Dude"); _meshNode = modelNode.GetSubtree().OfType<MeshNode>().First().Clone(); _meshNode.PoseLocal = new Pose(new Vector3F(0, 0, 0), Matrix33F.CreateRotationY(ConstantsF.Pi)); SampleHelper.EnablePerPixelLighting(_meshNode); GraphicsScreen.Scene.Children.Add(_meshNode); var animations = _meshNode.Mesh.Animations; var loopingAnimation = new AnimationClip<SkeletonPose>(animations.Values.First()) { LoopBehavior = LoopBehavior.Cycle, Duration = TimeSpan.MaxValue, }; AnimationService.StartAnimation(loopingAnimation, (IAnimatableProperty)_meshNode.SkeletonPose); // Create LookAtIKSolvers for some spine bones, the neck and the head. _spine1IK = new LookAtIKSolver { SkeletonPose = _meshNode.SkeletonPose, BoneIndex = 3, // The bone space axis that points in look direction. Forward = Vector3F.UnitY, // The bone space axis that points in up direction Up = Vector3F.UnitX, // An arbitrary rotation limit. Limit = ConstantsF.PiOver4, // We use a weight of 1 for the head, and lower weights for all other bones. Thus, most // of the looking will be done by the head bone, and the influence on the other bones is // smaller. Weight = 0.2f, // It is important to set the EyeOffsets. If we do not set EyeOffsets, the IK solver // assumes that the eyes are positioned in the origin of the bone. // Approximate EyeOffsets are sufficient. EyeOffset = new Vector3F(0.8f, 0, 0), }; _spine2IK = new LookAtIKSolver { SkeletonPose = _meshNode.SkeletonPose, BoneIndex = 4, Forward = Vector3F.UnitY, Up = Vector3F.UnitX, Limit = ConstantsF.PiOver4, Weight = 0.2f, EyeOffset = new Vector3F(0.64f, 0, 0), }; _spine3IK = new LookAtIKSolver { SkeletonPose = _meshNode.SkeletonPose, BoneIndex = 5, Forward = Vector3F.UnitY, Up = Vector3F.UnitX, Limit = ConstantsF.PiOver4, Weight = 0.3f, EyeOffset = new Vector3F(0.48f, 0, 0), }; _neckIK = new LookAtIKSolver { SkeletonPose = _meshNode.SkeletonPose, BoneIndex = 6, Forward = Vector3F.UnitY, Up = Vector3F.UnitX, Limit = ConstantsF.PiOver4, Weight = 0.4f, EyeOffset = new Vector3F(0.32f, 0, 0), }; _headIK = new LookAtIKSolver { SkeletonPose = _meshNode.SkeletonPose, BoneIndex = 7, Forward = Vector3F.UnitY, Up = Vector3F.UnitX, EyeOffset = new Vector3F(0.16f, 0.16f, 0), Weight = 1.0f, Limit = ConstantsF.PiOver4, }; }
protected override void LoadContent() { // Load model and start a looping animation. _model = Game.Content.Load<Model>("Dude"); var additionalData = (Dictionary<string, object>)_model.Tag; var skeleton = (Skeleton)additionalData["Skeleton"]; _skeletonPose = SkeletonPose.Create(skeleton); var animations = (Dictionary<string, SkeletonKeyFrameAnimation>)additionalData["Animations"]; var loopingAnimation = new AnimationClip<SkeletonPose>(animations.Values.First()) { LoopBehavior = LoopBehavior.Cycle, Duration = TimeSpan.MaxValue, }; AnimationService.StartAnimation(loopingAnimation, (IAnimatableProperty)_skeletonPose); // Create LookAtIKSolvers for some spine bones, the neck and the head. _spine1IK = new LookAtIKSolver { SkeletonPose = _skeletonPose, BoneIndex = 3, // The bone space axis that points in look direction. Forward = Vector3F.UnitY, // The bone space axis that points in up direction Up = Vector3F.UnitX, // An arbitrary rotation limit. Limit = ConstantsF.PiOver4, // We use a weight of 1 for the head, and lower weights for all other bones. Thus, most // of the looking will be done by the head bone, and the influence on the other bones is // smaller. Weight = 0.2f, // It is important to set the EyeOffsets. If we do not set EyeOffsets, the IK solver // assumes that the eyes are positioned in the origin of the bone. // Approximate EyeOffsets are sufficient. EyeOffset = new Vector3F(0.8f, 0, 0), }; _spine2IK = new LookAtIKSolver { SkeletonPose = _skeletonPose, BoneIndex = 4, Forward = Vector3F.UnitY, Up = Vector3F.UnitX, Limit = ConstantsF.PiOver4, Weight = 0.2f, EyeOffset = new Vector3F(0.64f, 0, 0), }; _spine3IK = new LookAtIKSolver { SkeletonPose = _skeletonPose, BoneIndex = 5, Forward = Vector3F.UnitY, Up = Vector3F.UnitX, Limit = ConstantsF.PiOver4, Weight = 0.3f, EyeOffset = new Vector3F(0.48f, 0, 0), }; _neckIK = new LookAtIKSolver { SkeletonPose = _skeletonPose, BoneIndex = 6, Forward = Vector3F.UnitY, Up = Vector3F.UnitX, Limit = ConstantsF.PiOver4, Weight = 0.4f, EyeOffset = new Vector3F(0.32f, 0, 0), }; _headIK = new LookAtIKSolver { SkeletonPose = _skeletonPose, BoneIndex = 7, Forward = Vector3F.UnitY, Up = Vector3F.UnitX, EyeOffset = new Vector3F(0.16f, 0.16f, 0), Weight = 1.0f, Limit = ConstantsF.PiOver4, }; base.LoadContent(); }