/// <summary> /// Helper used by the Update method to refresh the BoneTransforms data. /// </summary> public void UpdateBoneTransforms(TimeSpan elapsedTime) { for (int i = 0; i < this.skinningData.BindPose.Count; i++) { this.boneTransforms[i] = this.skinningData.BindPose[i]; } for (int i = 0; i < this.CurrentClips.Count; i++) { SkinnedModel.Clip clip = this.CurrentClips[i]; TimeSpan newTime = clip.CurrentTime + new TimeSpan((long)((float)elapsedTime.Ticks * clip.Speed)); List <Callback> callbacks; if (this.callbacks.TryGetValue(clip.Name, out callbacks)) { float currentSeconds = (float)clip.CurrentTime.TotalSeconds; float newSeconds = (float)newTime.TotalSeconds; for (int j = 0; j < callbacks.Count; j++) { Callback c = callbacks[j]; if (currentSeconds < c.Offset && newSeconds > c.Offset) { c.Command.Execute(); } } } float targetStrength = MathHelper.Clamp(clip.TargetStrength, 0.0f, 1.0f); float strengthBlendSpeed = (1.0f / AnimatedModel.DefaultBlendTime) * (float)elapsedTime.TotalSeconds; clip.Strength += MathHelper.Clamp(targetStrength - clip.Strength, -strengthBlendSpeed, strengthBlendSpeed); if (!clip.Stopping && clip.Duration.TotalSeconds > 0) { if (!clip.Loop && newTime >= clip.Duration) { clip.Stopping = true; clip.BlendTime = 0.0f; } else { clip.CurrentTime = newTime; } } clip.BlendTime += (float)elapsedTime.TotalSeconds; float blend = clip.Strength; if (clip.BlendTime < clip.BlendTotalTime) { float b = clip.BlendTime / clip.BlendTotalTime; b = -b * (b - 2); // Quadratic easing if (clip.Stopping) { blend *= 1.0f - b; } else { blend *= b; } } else if (clip.Stopping) { clip.Active = false; this.CurrentClips.RemoveAt(i); i--; continue; } if (blend > 0.0f) { if (blend < 1.0f) { for (int j = 0; j < clip.Channels.Count; j++) { SkinnedModel.Channel channel = clip.Channels[j]; Matrix bone1 = this.boneTransforms[channel.BoneIndex]; Vector3 scale1; Quaternion quat1; Vector3 translation1; bone1.Decompose(out scale1, out quat1, out translation1); Matrix bone2 = channel.CurrentMatrix; Vector3 scale2; Quaternion quat2; Vector3 translation2; bone2.Decompose(out scale2, out quat2, out translation2); this.boneTransforms[channel.BoneIndex] = Matrix.CreateScale(Vector3.Lerp(scale1, scale2, blend)) * Matrix.CreateFromQuaternion(Quaternion.Lerp(quat1, quat2, blend)) * Matrix.CreateTranslation(Vector3.Lerp(translation1, translation2, blend)); } } else { for (int j = 0; j < clip.Channels.Count; j++) { SkinnedModel.Channel channel = clip.Channels[j]; this.boneTransforms[channel.BoneIndex] = channel.CurrentMatrix; } } } } foreach (KeyValuePair <int, Property <Matrix> > pair in this.relativeBoneTransformProperties) { pair.Value.Value = this.boneTransforms[pair.Key]; } }
public void Bind(AnimatedModel m) { this.model = m; this.sprintAnimation = m["Sprint"]; this.runAnimation = m["Run"]; this.fallAnimation = m["Fall"]; m["Idle"].GetChannel(m.GetBoneIndex("ORG-spine")).Filter = delegate(Matrix spine) { float x; if (this.idleRotationBlend < 1.0f) { x = (this.Rotation - this.idleRotation.ClosestAngle(this.Rotation)) * Math.Max(0.0f, 1.0f - this.idleRotationBlend); } else if (this.idling) { x = this.Rotation - this.idleRotation.ClosestAngle(this.Rotation); } else { x = 0.0f; } return(spine * Matrix.CreateRotationY(x)); }; int headIndex = m.GetBoneIndex("ORG-head"); Matrix headBindPose = m.GetWorldBindTransform(headIndex) * Matrix.CreateTranslation(0, 0.1f, 0.25f); Func <SkinnedModel.Clip, Func <Matrix, Matrix> > cancelHeadBob = delegate(SkinnedModel.Clip clip) { int bone = headIndex; List <SkinnedModel.Channel> channels = new List <SkinnedModel.Channel>(); channels.Add(new SkinnedModel.Channel { BoneIndex = bone }); while (true) { int parent = m.SkeletonHierarchy[bone]; if (parent == -1) { break; } else { channels.Add(clip.GetChannel(parent) ?? new SkinnedModel.Channel { BoneIndex = bone }); } bone = parent; } return(delegate(Matrix x) { if (main.MinimizeCameraMovement) { Matrix world = Matrix.Identity; for (int i = 0; i < channels.Count; i++) { SkinnedModel.Channel channel = channels[i]; if (channel.Count == 0) { world = world * m.BindPose[channel.BoneIndex]; } else { world = world * channel.CurrentMatrix; } } return headBindPose * Matrix.Invert(world); } else { return x; } }); }; int cameraIndex = m.GetBoneIndex("Camera"); Func <SkinnedModel.Clip, Func <Matrix, Matrix> > cancelRotation = delegate(SkinnedModel.Clip clip) { int bone = cameraIndex; List <SkinnedModel.Channel> channels = new List <SkinnedModel.Channel>(); channels.Add(new SkinnedModel.Channel { BoneIndex = bone }); while (true) { int parent = m.SkeletonHierarchy[bone]; if (parent == -1) { break; } else { channels.Add(clip.GetChannel(parent) ?? new SkinnedModel.Channel { BoneIndex = bone }); } bone = parent; } return(delegate(Matrix x) { if ( #if VR this.main.VR || #endif this.main.MinimizeCameraMovement) { Matrix world = Matrix.Identity; for (int i = 0; i < channels.Count; i++) { SkinnedModel.Channel channel = channels[i]; if (channel.Count == 0) { world = world * m.BindPose[channel.BoneIndex]; } else { world = world * channel.CurrentMatrix; } } Matrix rot = Matrix.Invert(world) * Matrix.CreateRotationX((float)Math.PI * 0.5f); rot.Translation = x.Translation; return rot; } else { return x; } }); }; m["Run"].GetChannel(headIndex).Filter = cancelHeadBob(m["Run"]); m["RunLeft"].GetChannel(headIndex).Filter = cancelHeadBob(m["RunLeft"]); m["RunRight"].GetChannel(headIndex).Filter = cancelHeadBob(m["RunRight"]); m["RunLeftForward"].GetChannel(headIndex).Filter = cancelHeadBob(m["RunLeftForward"]); m["RunRightForward"].GetChannel(headIndex).Filter = cancelHeadBob(m["RunRightForward"]); m["Sprint"].GetChannel(headIndex).Filter = cancelHeadBob(m["Sprint"]); m["Slide"].GetChannel(cameraIndex).Filter = cancelRotation(m["Slide"]); m["WallRunLeft"].GetChannel(cameraIndex).Filter = cancelRotation(m["WallRunLeft"]); m["WallRunRight"].GetChannel(cameraIndex).Filter = cancelRotation(m["WallRunRight"]); m["TopOut"].GetChannel(cameraIndex).Filter = cancelRotation(m["TopOut"]); m["Land"].GetChannel(cameraIndex).Filter = cancelRotation(m["Land"]); m["LandHard"].GetChannel(cameraIndex).Filter = cancelRotation(m["LandHard"]); m["Idle"].GetChannel(m.GetBoneIndex("ORG-hips")).Filter = delegate(Matrix hips) { float x; if (this.idleRotationBlend < 1.0f) { x = (this.idleRotation.ClosestAngle(this.Rotation) - this.Rotation) * Math.Max(0.0f, 1.0f - this.idleRotationBlend); } else if (this.idling) { x = this.idleRotation.ClosestAngle(this.Rotation) - this.Rotation; } else { x = 0.0f; } return(hips * Matrix.CreateRotationZ(x)); }; this.relativeHeadBone = m.GetRelativeBoneTransform("ORG-head"); m["Swim"].Speed = 2.0f; m["SwimForward"].Speed = 2.0f; m["TurnLeft"].Speed = 2.0f; m["TurnRight"].Speed = 2.0f; m["WallRunStraight"].GetChannel(m.GetBoneIndex("ORG-hips")).Filter = delegate(Matrix hips) { hips.Translation += new Vector3(0, 1, 0); return(hips); }; }