/// <summary> /// Adds an AngularLimit between the specified bones. /// </summary> /// <param name="skeletonPose">The skeleton pose.</param> /// <param name="ragdoll">The ragdoll.</param> /// <param name="parent">The parent bone.</param> /// <param name="child">The child bone.</param> /// <param name="minimum">The minimum limits for each constraint axis (x/y/z).</param> /// <param name="maximum">The maximum limits for each constraint axis (x/y/z).</param> /// <remarks> /// The constraint anchor orientation is the orientation of the child bone. /// </remarks> private static void AddAngularLimit(SkeletonPose skeletonPose, Ragdoll ragdoll, int parent, int child, Vector3F minimum, Vector3F maximum) { var skeleton = skeletonPose.Skeleton; var childBody = ragdoll.Bodies[child]; var childOffset = ragdoll.BodyOffsets[child]; var parentBody = ragdoll.Bodies[parent]; var parentOffset = ragdoll.BodyOffsets[parent]; var parentBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(parent).Inverse; var childBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(child).Inverse; var bindPoseRelative = parentBindPoseAbsolute.Inverse * childBindPoseAbsolute; var limit = new AngularLimit { BodyA = parentBody, BodyB = childBody, AnchorOrientationALocal = parentOffset.Orientation.Transposed * bindPoseRelative.Orientation, AnchorOrientationBLocal = childOffset.Orientation.Transposed, Minimum = minimum, Maximum = maximum, ErrorReduction = new Vector3F(0.2f), Softness = new Vector3F(0.001f) }; ragdoll.Limits.Add(limit); }
public override void Update(GameTime gameTime) { _debugRenderer.Clear(); if (_avatarPose == null) { // Must wait till renderer is ready. Before that we do not get skeleton info. if (_avatarRenderer.State == AvatarRendererState.Ready) { // Create AvatarPose. _avatarPose = new AvatarPose(_avatarRenderer); // A 'bone transform' is the transformation of a bone relative to its bind pose. // Bone transforms define the pose of a skeleton. // Rotate arm of avatar. SkeletonPose skeletonPose = _avatarPose.SkeletonPose; int shoulderIndex = skeletonPose.Skeleton.GetIndex("ShoulderLeft"); skeletonPose.SetBoneTransform(shoulderIndex, new SrtTransform(QuaternionF.CreateRotationZ(-0.9f))); // The class SkeletonHelper provides some useful extension methods. // One is SetBoneRotationAbsolute() which sets the orientation of a bone relative // to model space. // Rotate elbow to make the lower arm point forward. int elbowIndex = skeletonPose.Skeleton.GetIndex("ElbowLeft"); SkeletonHelper.SetBoneRotationAbsolute(skeletonPose, elbowIndex, QuaternionF.CreateRotationY(ConstantsF.PiOver2)); // Draw avatar skeleton for debugging. _debugRenderer.DrawSkeleton(skeletonPose, _pose, Vector3F.One, 0.02f, Color.Orange, true); } } }
// Update the skeleton pose using the data from Kinect. private void UpdateKinectSkeletonPose(Body body, SkeletonPose skeletonPose) { if (body == null || !body.IsTracked) { return; } for (int i = 0; i < skeletonPose.Skeleton.NumberOfBones; i++) { var joint = Bones[i].JointType; if (body.Joints[joint].TrackingState != TrackingState.NotTracked) { // The joint position in "Kinect space". var kinectPosition = body.Joints[joint].Position; // Convert Kinect joint position to a Vector3. // z is negated because in XNA the camera forward vectors is -z, but the Kinect // forward vector is +z. Vector3 position = new Vector3(kinectPosition.X, kinectPosition.Y, -kinectPosition.Z); // Apply scale and offset. position = position * Scale + Offset; var orientation = Quaternion.Identity; // TODO: Use orientations of body.JointOrientations. skeletonPose.SetBonePoseAbsolute(i, new SrtTransform(orientation, position)); } } }
/// <summary> /// Adds a BallJoint between the specified bones. /// </summary> /// <param name="skeletonPose">The skeleton pose.</param> /// <param name="ragdoll">The ragdoll.</param> /// <param name="parent">The parent.</param> /// <param name="child">The child.</param> private static void AddJoint(SkeletonPose skeletonPose, Ragdoll ragdoll, int parent, int child) { // Get bodies and offsets for the bones. var skeleton = skeletonPose.Skeleton; var childBody = ragdoll.Bodies[child]; var childOffset = ragdoll.BodyOffsets[child]; var parentBody = ragdoll.Bodies[parent]; var parentOffset = ragdoll.BodyOffsets[parent]; // Get bind poses of the bones in model space. var parentBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(parent).Inverse; var childBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(child).Inverse; // The child pose relative to the parent bone. var bindPoseRelative = parentBindPoseAbsolute.Inverse * childBindPoseAbsolute; // Add BallJoint that connects the two bones. The position of the joint is the // origin of the child bone. BallJoint joint = new BallJoint { BodyA = parentBody, BodyB = childBody, CollisionEnabled = false, AnchorPositionALocal = (parentOffset.Inverse * bindPoseRelative).Position, AnchorPositionBLocal = childOffset.Inverse.Position, ErrorReduction = 0.2f, Softness = 0.0001f, }; ragdoll.Joints.Add(joint); }
/// <inheritdoc/> /// <exception cref="ArgumentNullException"> /// <paramref name="value"/> or <paramref name="property"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// The value of <paramref name="property"/> must not be <see langword="null"/>. /// </exception> public void Set(ref SkeletonPose value, IAnimatableProperty <SkeletonPose> property) { if (value == null) { throw new ArgumentNullException("value"); } if (property == null) { throw new ArgumentNullException("property"); } var animationValue = property.AnimationValue; if (animationValue == null) { if (property.HasBaseValue) { // The SkeletonPose will be recycled in Reset(). Create(ref value, out animationValue); property.AnimationValue = animationValue; } else { throw new ArgumentException("The value of the property must not be null. This exception usually occurs when an IAnimatableProperty<SkeletonPose> is being animated, but the value of the property is null. A SkeletonPose must be set before the property can be animated."); } } SkeletonHelper.Copy(value, animationValue); }
/// <summary> /// Drives the controlled body. /// </summary> /// <param name="skeletonPose">The target skeleton pose.</param> /// <param name="deltaTime">The time step.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="skeletonPose" /> is <see langword="null"/>. /// </exception> internal void DriveToPose(SkeletonPose skeletonPose, float deltaTime) { if (skeletonPose == null) { throw new ArgumentNullException("skeletonPose"); } Debug.Assert(Ragdoll != null, "Motor must not be called when Ragdoll property is null."); Debug.Assert(Ragdoll.Simulation != null, "Ragdoll was not added to a simulation."); if (!Enabled) { return; } if (Mode == RagdollMotorMode.Velocity) { // ----- Velocity motor Debug.Assert(_quaternionMotor.Simulation == null, "Velocity motors should not be added to the simulation."); if (BoneIndex >= Ragdoll.Bodies.Count) { return; } var body = Ragdoll.Bodies[BoneIndex]; if (body == null) { return; } var childOffset = (BoneIndex < Ragdoll.BodyOffsets.Count) ? Ragdoll.BodyOffsets[BoneIndex] : Pose.Identity; var childPose = Ragdoll.Pose * ((Pose)skeletonPose.GetBonePoseAbsolute(BoneIndex)) * childOffset; // Wake the body up. It should move, even if we move it very slowly. body.WakeUp(); // Set velocities. body.LinearVelocity = AnimationHelper.ComputeLinearVelocity(body.Pose.Position, childPose.Position, deltaTime); body.AngularVelocity = AnimationHelper.ComputeAngularVelocity(body.Pose.Orientation, childPose.Orientation, deltaTime); } else { // ----- Constraint motor if (_quaternionMotor.Simulation == null) { // The motor was not added to the simulation. (Invalid configuration) return; } var parentOffset = (ParentIndex < Ragdoll.BodyOffsets.Count) ? Ragdoll.BodyOffsets[ParentIndex] : Pose.Identity; var parentPose = Ragdoll.Pose * ((Pose)skeletonPose.GetBonePoseAbsolute(ParentIndex)) * parentOffset; var childOffset = (BoneIndex < Ragdoll.BodyOffsets.Count) ? Ragdoll.BodyOffsets[BoneIndex] : Pose.Identity; var childPose = Ragdoll.Pose * ((Pose)skeletonPose.GetBonePoseAbsolute(BoneIndex)) * childOffset; // Set the relative motor target. var rotationMatrix = parentPose.Orientation.Transposed * childPose.Orientation; _quaternionMotor.TargetOrientation = Quaternion.CreateFromRotationMatrix(rotationMatrix); } }
protected override void LoadContent() { // Get dude model and start animation on the dude. _dudeModel = Game.Content.Load<Model>("Dude"); var additionalData = (Dictionary<string, object>)_dudeModel.Tag; var skeleton = (Skeleton)additionalData["Skeleton"]; _dudeSkeletonPose = 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)_dudeSkeletonPose); // Get marine model - do not start any animations on the marine model. _marineModel = Game.Content.Load<Model>("PlayerMarine"); additionalData = (Dictionary<string, object>)_marineModel.Tag; skeleton = (Skeleton)additionalData["Skeleton"]; _marineSkeletonPose = SkeletonPose.Create(skeleton); CreateSkeletonMapper(); base.LoadContent(); }
/// <summary> /// Updates the poses of the bodies, so that the bodies match the bone transforms of the given /// skeleton pose. /// </summary> /// <param name="skeletonPose">The skeleton pose.</param> /// <remarks> /// The poses of the rigid bodies are changed instantly. The bodies will "teleport" instantly to /// the target positions. They will not interact correctly with other physics objects. The /// velocities of the rigid bodies are set to zero. The bodies will be positioned relative to /// the world space pose defined by <see cref="Pose"/>. /// </remarks> /// <exception cref="ArgumentNullException"> /// <paramref name="skeletonPose" /> is <see langword="null"/>. /// </exception> public void UpdateBodiesFromSkeleton(SkeletonPose skeletonPose) // = Teleport of bodies. { if (skeletonPose == null) { throw new ArgumentNullException("skeletonPose"); } var skeleton = skeletonPose.Skeleton; for (int i = 0; i < Bodies.Count && i < skeleton.NumberOfBones; i++) { var body = Bodies[i]; if (body == null) { continue; } Pose offset = (i < BodyOffsets.Count) ? BodyOffsets[i] : Pose.Identity; Pose bodyPose = Pose * ((Pose)skeletonPose.GetBonePoseAbsolute(i)) * offset; body.Pose = bodyPose; body.LinearVelocity = Vector3F.Zero; body.AngularVelocity = Vector3F.Zero; } }
public BoneJiggler(SkeletonPose skeletonPose, int boneIndex, Vector3 offset) { if (skeletonPose == null) { throw new ArgumentNullException("skeletonPose"); } if (boneIndex < 0 || boneIndex > skeletonPose.Skeleton.NumberOfBones) { throw new ArgumentOutOfRangeException("boneIndex"); } if (offset.IsNumericallyZero) { throw new ArgumentException("Parameter offset must not be a zero vector."); } SkeletonPose = skeletonPose; BoneIndex = boneIndex; Offset = offset; Spring = 100f; Damping = 1f; Reset(); }
protected override void OnUpdate(RenderContext context) { var meshNode = context.SceneNode as MeshNode; if (meshNode != null) { Value = meshNode.SkeletonPose; if (Value != null) { if (Value.Skeleton.NumberOfBones > Parameter.Elements.Count) { Value = null; var message = string.Format( CultureInfo.InvariantCulture, "Cannot update skeleton pose effect parameter binding: " + "The skeleton has {0} bones. The effect supports only {1} bones.", meshNode.SkeletonPose.Skeleton.NumberOfBones, Parameter.Elements.Count); throw new GraphicsException(message); } Value.Update(); } } else { Value = null; } }
/// <summary> /// Updates the pose of a single body, so that the bodies match the bone transforms of the given /// bone. /// </summary> /// <param name="skeletonPose">The skeleton pose.</param> /// <param name="boneIndex">The index of the bone.</param> /// <remarks> /// See also <see cref="UpdateBodiesFromSkeleton(SkeletonPose)"/>. /// </remarks> /// <exception cref="ArgumentNullException"> /// <paramref name="skeletonPose" /> is <see langword="null"/>. /// </exception> public void UpdateBodyFromSkeleton(SkeletonPose skeletonPose, int boneIndex) { if (skeletonPose == null) { throw new ArgumentNullException("skeletonPose"); } if (boneIndex < 0 || boneIndex >= Bodies.Count) { return; } var body = Bodies[boneIndex]; if (body == null) { return; } Pose offset = (boneIndex < BodyOffsets.Count) ? BodyOffsets[boneIndex] : Pose.Identity; Pose bodyPose = Pose * ((Pose)skeletonPose.GetBonePoseAbsolute(boneIndex)) * offset; body.Pose = bodyPose; body.LinearVelocity = Vector3F.Zero; body.AngularVelocity = Vector3F.Zero; }
public KinectWrapper(Game game) : base(game) { // one sensor is currently supported _kinectSensor = KinectSensor.GetDefault(); // open the reader for the body frames _bodyFrameReader = _kinectSensor.BodyFrameSource.OpenReader(); // open the sensor _kinectSensor.Open(); _bodyFrameReader.FrameArrived += OnKinectBodyFrameArrived; Offset = new Vector3(0, 0.3f, 0); Scale = new Vector3(1, 1, 1); // Create a skeleton that defines the bone hierarchy and rest pose. var skeleton = new Skeleton( Bones.Select(b => b.ParentIndex).ToArray(), // Parent indices Bones.Select(b => b.Name).ToArray(), // Bone names Enumerable.Repeat(SrtTransform.Identity, Bones.Length).ToArray()); // Bind poses = all Identity transforms // Create a SkeletonPose for each player. SkeletonPoseA = SkeletonPose.Create(skeleton); SkeletonPoseB = SkeletonPose.Create(skeleton); }
public ModelContainer(Model modelpass, Pose posepass, SkeletonPose skeletonpass) { _model = modelpass; _pose = posepass; _skeleton = skeletonpass; var additionalData = (Dictionary<string,object>)_model.Tag; var animations = (Dictionary<string, SkeletonKeyFrameAnimation>)additionalData["Animations"]; int index = 0; _animations = new ITimeline[animations.Count]; _animations[0] = new AnimationClip<SkeletonPose>(animations["First"]) { LoopBehavior = LoopBehavior.Cycle, Duration = TimeSpan.MaxValue }; index++; _animations[1] = new AnimationClip<SkeletonPose>(animations["Second"]); _animations[2] = new AnimationClip<SkeletonPose>(animations["Second"]) { LoopBehavior = LoopBehavior.Cycle, Duration = TimeSpan.MaxValue }; }
/// <inheritdoc/> /// <exception cref="ArgumentNullException"> /// <paramref name="value0"/>, <paramref name="value1"/> or <paramref name="result"/> is /// <see langword="null"/>. /// </exception> public void Add(ref SkeletonPose value0, ref SkeletonPose value1, ref SkeletonPose result) { if (value0 == null) { throw new ArgumentNullException("value0"); } if (value1 == null) { throw new ArgumentNullException("value1"); } if (result == null) { throw new ArgumentNullException("result"); } var boneTransforms0 = value0.BoneTransforms; var boneTransforms1 = value1.BoneTransforms; var resultTransforms = result.BoneTransforms; for (int i = 0; i < resultTransforms.Length; i++) { resultTransforms[i] = boneTransforms1[i] * boneTransforms0[i]; } result.Invalidate(); }
/// <inheritdoc/> /// <exception cref="ArgumentNullException"> /// <paramref name="source"/>, <paramref name="target"/> or <paramref name="result"/> is /// <see langword="null"/>. /// </exception> public void Interpolate(ref SkeletonPose source, ref SkeletonPose target, float parameter, ref SkeletonPose result) { if (source == null) { throw new ArgumentNullException("source"); } if (target == null) { throw new ArgumentNullException("target"); } if (result == null) { throw new ArgumentNullException("result"); } var sourceTransforms = source.BoneTransforms; var targetTransforms = target.BoneTransforms; var resultTransforms = result.BoneTransforms; for (int i = 0; i < resultTransforms.Length; i++) { SrtTransform.Interpolate(ref sourceTransforms[i], ref targetTransforms[i], parameter, ref resultTransforms[i]); } result.Invalidate(); }
//-------------------------------------------------------------- /// <summary> /// Initializes a new instance of the <see cref="SkeletonMapper"/> class. /// </summary> /// <param name="skeletonPoseA">The first skeleton pose. Can be <see langword="null"/>.</param> /// <param name="skeletonPoseB">The second skeleton pose. Can be <see langword="null"/>.</param> public SkeletonMapper(SkeletonPose skeletonPoseA, SkeletonPose skeletonPoseB) { _skeletonPoseA = skeletonPoseA; _skeletonPoseB = skeletonPoseB; BoneMappers = new BoneMapperCollection(); BoneMappers.CollectionChanged += OnBoneMappersChanged; }
/// <inheritdoc/> public void Recycle(ref SkeletonPose value) { if (value != null) { value.Recycle(); value = null; } }
/// <inheritdoc/> protected override void CloneCore(EffectParameterBinding source) { // Clone EffectParameterBinding properties. base.CloneCore(source); // Clone SkeletonPoseParameterBinding properties. var sourceTyped = (SkeletonPoseParameterBinding)source; Value = sourceTyped.Value; }
// Note: // SkeletonPose.Invalidate() needs to be called when the internal BoneTransforms // are changed. Invalidate() only has an effect if the SkeletonPose has a // SkeletonBoneAccessor. Newly created SkeletonPose do not have a SkeletonBoneAccessor. // --> Calling Invalidate() should not have a performance impact. Except for the // Set() method. Set() is called in AnimationManager.Apply() where the animation // value is copied into the actual SkeletonPose, which might use a SkeletonBoneAccessor. // Set() is the only method where Invalidate() is mandatory. However, the // SkeletonPoseTraits might be used outside of the animation service. Invalidate() // should be called in all methods to be safe. /// <inheritdoc/> /// <exception cref="ArgumentNullException"> /// <paramref name="reference"/> is <see langword="null"/>. /// </exception> public void Create(ref SkeletonPose reference, out SkeletonPose value) { if (reference == null) { throw new ArgumentNullException("reference", "The reference value must not be null. This exception usually occurs when an IAnimatableProperty<SkeletonPose> is being animated, but the value of the property is null. A SkeletonPose must be set before the property can be animated."); } value = SkeletonPose.Create(reference.Skeleton); }
public int Add(Model _model,Pose _pose,SkeletonPose _skel ) { Map.Add(NumModels, new ICT309Game.Container.ModelContainer(_model, _pose, _skel)); Models.Add(_model); Poses.Add(_pose); SkeletonPoses.Add(_skel); NumModels++; // Map[0]._model = _model; // Walk(NumModels-1); idle(NumModels - 1); return NumModels - 1; }
/// <inheritdoc/> /// <exception cref="ArgumentNullException"> /// <paramref name="value"/> is <see langword="null"/>. /// </exception> public void BeginBlend(ref SkeletonPose value) { if (value == null) { throw new ArgumentNullException("value"); } // Set bone transforms to zero. var transforms = value.BoneTransforms; Array.Clear(transforms, 0, transforms.Length); }
private void InitializeSkeletonPoses() { // Create a list of the bone/joint names of a Kinect skeleton. int numberOfJoints = Enum.GetNames(typeof(JointType)).Length; var boneNames = new string[numberOfJoints]; for (int i = 0; i < numberOfJoints; i++) { boneNames[i] = ((JointType)i).ToString(); } // Create list with one entry per bone. Each entry is the index of the parent bone. var boneParents = new[] { -1, (int)JointType.HipCenter, (int)JointType.Spine, (int)JointType.ShoulderCenter, (int)JointType.ShoulderCenter, (int)JointType.ShoulderLeft, (int)JointType.ElbowLeft, (int)JointType.WristLeft, (int)JointType.ShoulderCenter, (int)JointType.ShoulderRight, (int)JointType.ElbowRight, (int)JointType.WristRight, (int)JointType.HipCenter, (int)JointType.HipLeft, (int)JointType.KneeLeft, (int)JointType.AnkleLeft, (int)JointType.HipCenter, (int)JointType.HipRight, (int)JointType.KneeRight, (int)JointType.AnkleRight, }; // Create a list of the bind pose transformations of all bones. Since we do not // get such information from Kinect, we position all bones in the local origin. var boneBindPoses = new SrtTransform[numberOfJoints]; for (int i = 0; i < numberOfJoints; i++) { boneBindPoses[i] = SrtTransform.Identity; } // Create a skeleton that defines the bone hierarchy and rest pose. var skeleton = new DRSkeleton(boneParents, boneNames, boneBindPoses); // Create a SkeletonPose for each player. SkeletonPoseA = SkeletonPose.Create(skeleton); SkeletonPoseB = SkeletonPose.Create(skeleton); }
internal PrettySkeletonPose([NotNull] SkeletonPose pose) { var transformCount = pose.m_X.Length; var transforms = new RawTransform[transformCount]; for (var i = 0; i < transformCount; i += 1) { var t = new RawTransform(pose.m_X[i]); transforms[i] = t; } Transforms = transforms; }
// Copies the quaternions of all bones to the specified array. private void SkeletonPoseToArray(float[] values) { var numberOfBones = SkeletonPose.Skeleton.NumberOfBones; for (int i = 0; i < numberOfBones; i++) { QuaternionF quaternion = SkeletonPose.GetBoneTransform(i).Rotation; values[i * 4 + 0] = quaternion.W; values[i * 4 + 1] = quaternion.X; values[i * 4 + 2] = quaternion.Y; values[i * 4 + 3] = quaternion.Z; } }
public void Update(float deltaTime, Matrix world) { if (deltaTime <= 0) { return; } // Reset bone transform. SkeletonPose.SetBoneTransform(BoneIndex, SrtTransform.Identity); // Get new fixed point position in world space. var bonePoseAbsolute = SkeletonPose.GetBonePoseAbsolute(BoneIndex); var bonePoseWorld = world * bonePoseAbsolute; var fixedPointPosition = bonePoseWorld.TransformPosition(Offset); // If we haven't set the fixed point position before, then store the position // and we are done. if (_fixedPointPosition.IsNaN) { _fixedPointPosition = fixedPointPosition; return; } // New position and velocity of fixed point. _fixedPointVelocity = (fixedPointPosition - _fixedPointPosition) / deltaTime; _fixedPointPosition = fixedPointPosition; // If the particle position was not set before, then we only store the current values. // The real work starts in the next frame. if (_particlePosition.IsNaN) { _particlePosition = _fixedPointPosition; _particleVelocity = _fixedPointVelocity; return; } // Compute the spring force between the particle and the fixed point. var force = Spring * (_fixedPointPosition - _particlePosition) + Damping * (_fixedPointVelocity - _particleVelocity); // Update velocity and position of the particle using symplectic Euler. _particleVelocity = _particleVelocity + force * deltaTime; _particlePosition = _particlePosition + _particleVelocity * deltaTime; // Convert particle position back to bone space. var particleLocal = bonePoseWorld.Inverse.TransformPosition(_particlePosition); // Create rotation between the fixed point vector and the particle vector. var boneTransform = new SrtTransform(Quaternion.CreateFromRotationMatrix(Offset, particleLocal)); SkeletonPose.SetBoneTransform(BoneIndex, boneTransform); }
/// <summary> /// converts SkeletonPose enum into spoken words /// </summary> /// <param name="pose"></param> /// <returns></returns> private string SkeletonPoseToSpokenString(SkeletonPose pose) { // split CamelCase into words: string sPose = pose.ToString(); Regex upperCaseRegex = new Regex(@"[A-Z]{1}[a-z]*"); MatchCollection matches = upperCaseRegex.Matches(sPose); List <string> words = new List <string>(); foreach (Match match in matches) { words.Add(match.Value); } return(string.Join(" ", words.ToArray())); }
protected override void LoadContent() { _model = Game.Content.Load<Model>("Dude"); var additionalData = (Dictionary<string, object>)_model.Tag; var skeleton = (Skeleton)additionalData["Skeleton"]; _skeletonPoseUncompressed = SkeletonPose.Create(skeleton); _skeletonPoseCompressed = SkeletonPose.Create(skeleton); var animations = (Dictionary<string, SkeletonKeyFrameAnimation>)additionalData["Animations"]; _animation = animations.Values.First(); RestartAnimations(); base.LoadContent(); }
/// <inheritdoc/> /// <exception cref="ArgumentNullException"> /// <paramref name="value"/> is <see langword="null"/>. /// </exception> public void EndBlend(ref SkeletonPose value) { if (value == null) { throw new ArgumentNullException("value"); } var transforms = value.BoneTransforms; for (int i = 0; i < transforms.Length; i++) { transforms[i].Rotation.Normalize(); } value.Invalidate(); }
/// <inheritdoc/> /// <exception cref="ArgumentNullException"> /// <paramref name="value"/> or <paramref name="nextValue"/> is <see langword="null"/>. /// </exception> public void BlendNext(ref SkeletonPose value, ref SkeletonPose nextValue, float normalizedWeight) { if (value == null) { throw new ArgumentNullException("value"); } if (nextValue == null) { throw new ArgumentNullException("nextValue"); } var transforms = value.BoneTransforms; var nextTransforms = nextValue.BoneTransforms; for (int i = 0; i < transforms.Length; i++) { var rotation = transforms[i].Rotation; var nextRotation = nextTransforms[i].Rotation; // Get angle between quaternions: //float cosθ = Quaternion.Dot(rotation, nextRotation); float cosθ = rotation.W * nextRotation.W + rotation.X * nextRotation.X + rotation.Y * nextRotation.Y + rotation.Z * nextRotation.Z; // Invert one quaternion if we would move along the long arc of interpolation. if (cosθ < 0) { // Blend with inverted quaternion! rotation.W = rotation.W - normalizedWeight * nextRotation.W; rotation.X = rotation.X - normalizedWeight * nextRotation.X; rotation.Y = rotation.Y - normalizedWeight * nextRotation.Y; rotation.Z = rotation.Z - normalizedWeight * nextRotation.Z; } else { // Blend with normal quaternion. rotation.W = rotation.W + normalizedWeight * nextRotation.W; rotation.X = rotation.X + normalizedWeight * nextRotation.X; rotation.Y = rotation.Y + normalizedWeight * nextRotation.Y; rotation.Z = rotation.Z + normalizedWeight * nextRotation.Z; } transforms[i].Rotation = rotation; transforms[i].Scale += normalizedWeight * nextTransforms[i].Scale; transforms[i].Translation += normalizedWeight * nextTransforms[i].Translation; } }
protected override void LoadContent() { _model = Game.Content.Load<Model>("Soldier"); var additionalData = (Dictionary<string, object>)_model.Tag; var skeleton = (Skeleton)additionalData["Skeleton"]; _skeletonPose = SkeletonPose.Create(skeleton); // Get the animations from the additional data. var animations = (Dictionary<string, SkeletonKeyFrameAnimation>)additionalData["Animations"]; // The Dude model contains only one animation, which is a SkeletonKeyFrameAnimation with // a walk cycle. SkeletonKeyFrameAnimation walkAnimation = animations.Values.First(); // Wrap the walk animation in an animation clip that loops the animation forever. AnimationClip<SkeletonPose> loopingAnimation = new AnimationClip<SkeletonPose>(walkAnimation) { LoopBehavior = LoopBehavior.Cycle, Duration = TimeSpan.MaxValue, }; // Start the animation and keep the created AnimationController. // We must cast the SkeletonPose to IAnimatableProperty because SkeletonPose implements // IAnimatableObject and IAnimatableProperty. We must tell the AnimationService if we want // to animate an animatable property of the SkeletonPose (IAnimatableObject), or if we want to // animate the whole SkeletonPose (IAnimatableProperty). _animationController = AnimationService.StartAnimation(loopingAnimation, (IAnimatableProperty)_skeletonPose); // The animation will be applied the next time AnimationManager.ApplyAnimations() is called // in the main loop. ApplyAnimations() is called before this method is called, therefore // the model will be rendered in the bind pose in this frame and in the first animation key // frame in the next frame - this creates an annoying visual popping effect. // We can avoid this if we call AnimationController.UpdateAndApply(). This will immediately // change the model pose to the first key frame pose. _animationController.UpdateAndApply(); // (Optional) Enable Auto-Recycling: // After the animation is stopped, the animation service will recycle all // intermediate data structures. _animationController.AutoRecycle(); base.LoadContent(); }
public BoneJiggler(SkeletonPose skeletonPose, int boneIndex, Vector3F offset) { if (skeletonPose == null) throw new ArgumentNullException("skeletonPose"); if (boneIndex < 0 || boneIndex > skeletonPose.Skeleton.NumberOfBones) throw new ArgumentOutOfRangeException("boneIndex"); if (offset.IsNumericallyZero) throw new ArgumentException("Parameter offset must not be a zero vector."); SkeletonPose = skeletonPose; BoneIndex = boneIndex; Offset = offset; Spring = 100f; Damping = 1f; Reset(); }
public void DriveToPose(SkeletonPose skeletonPose, float deltaTime) { if (skeletonPose == null) { throw new ArgumentNullException("skeletonPose"); } if (Simulation == null) { throw new InvalidOperationException("Ragdoll was not added to a simulation. Call AddToSimulation() before calling DriveToPose()."); } foreach (var motor in Motors) { if (motor != null) { motor.DriveToPose(skeletonPose, deltaTime); } } }
private QuaternionF GetBoneOrientation(KinectSkeleton skeletonData, SkeletonPose skeletonPose, int boneIndex) { // Get first child bone. (Kinect stores the bone orientations in the child joints.) int childIndex = -1; if (skeletonPose.Skeleton.GetNumberOfChildren(boneIndex) > 0) { childIndex = skeletonPose.Skeleton.GetChild(boneIndex, 0); } if (childIndex == -1) { return(QuaternionF.Identity); } var q = skeletonData.BoneOrientations[(JointType)childIndex].AbsoluteRotation.Quaternion; // Convert to DigitalRune quaternion and mirror z axis. return(new QuaternionF(-q.W, q.X, q.Y, -q.Z)); }
/// <summary> /// Updates the bone transforms of the skeleton pose, so that the bones match the ragdoll /// bodies. /// </summary> /// <param name="skeletonPose">The skeleton pose that is modified.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="skeletonPose" /> is <see langword="null"/>. /// </exception> public void UpdateSkeletonFromBodies(SkeletonPose skeletonPose) { if (skeletonPose == null) { throw new ArgumentNullException("skeletonPose"); } var skeleton = skeletonPose.Skeleton; for (int i = 0; i < Bodies.Count && i < skeleton.NumberOfBones; i++) { var body = Bodies[i]; if (body == null) { continue; } Pose offset = (i < BodyOffsets.Count) ? BodyOffsets[i] : Pose.Identity; Pose bonePoseAbsolute = Pose.Inverse * body.Pose * offset.Inverse; skeletonPose.SetBonePoseAbsolute(i, bonePoseAbsolute); } }
private void UpdateKinectSkeletonPose(KinectSkeleton skeletonData, SkeletonPose skeletonPose) { if (skeletonData == null) { return; } // Update the skeleton pose using the data from Kinect. for (int i = 0; i < skeletonPose.Skeleton.NumberOfBones; i++) { var joint = (JointType)i; if (skeletonData.Joints[joint].TrackingState != JointTrackingState.NotTracked) { // The joint position in "Kinect space". SkeletonPoint kinectPosition = skeletonData.Joints[joint].Position; // Convert Kinect joint position to a Vector3F. // z is negated because in XNA the camera forward vectors is -z, but the Kinect // forward vector is +z. Vector3F position = new Vector3F(kinectPosition.X, kinectPosition.Y, -kinectPosition.Z); // Apply scale and offset. position = position * Scale + Offset; var orientation = QuaternionF.Identity; // Optional: // The newer Kinect SDKs also compute bone orientations. We do not need these values // because the current samples use only the joint positions to derive bone rotations. //if (joint != JointType.HipCenter) // Motion retargeting seems to work better if the hip center bone is not rotated. //{ // orientation = GetBoneOrientation(skeletonData, skeletonPose, i); //} skeletonPose.SetBonePoseAbsolute(i, new SrtTransform(orientation, position)); } } }
internal void OnAssetLoaded(object sender, EventArgs eventArgs) { // Create MeshNode.SkeletonPoses for all mesh.Skeletons. // (Skeletons can be shared and for each skeleton we create only one SkeletonPose.) Dictionary <Skeleton, SkeletonPose> skeletons = new Dictionary <Skeleton, SkeletonPose>(); foreach (var meshNode in this.GetSubtree().OfType <MeshNode>()) { var skeleton = meshNode.Mesh.Skeleton; if (skeleton != null) { // Get existing skeleton pose or create a new one. SkeletonPose skeletonPose; if (!skeletons.TryGetValue(skeleton, out skeletonPose)) { skeletonPose = SkeletonPose.Create(skeleton); skeletons.Add(skeleton, skeletonPose); } meshNode.SkeletonPose = skeletonPose; } } }
protected override void LoadContent() { _marine = Game.Content.Load<Model>("PlayerMarine"); var additionalData = (Dictionary<string, object>)_marine.Tag; var skeleton = (Skeleton)additionalData["Skeleton"]; _skeletonPose = SkeletonPose.Create(skeleton); // Play a looping 'Idle' animation. var animations = (Dictionary<string, SkeletonKeyFrameAnimation>)additionalData["Animations"]; var idleAnimation = animations["Idle"]; var loopingAnimation = new AnimationClip<SkeletonPose>(idleAnimation) { LoopBehavior = LoopBehavior.Cycle, Duration = TimeSpan.MaxValue, }; var animationController = AnimationService.StartAnimation(loopingAnimation, (IAnimatableProperty)_skeletonPose); animationController.UpdateAndApply(); animationController.AutoRecycle(); _weapon = Game.Content.Load<Model>("WeaponMachineGun"); base.LoadContent(); }
// Initializes the bone rotations using the quaternions of the specified array. private void ArrayToSkeletonPose(float[] values) { var numberOfBones = SkeletonPose.Skeleton.NumberOfBones; for (int i = 0; i < numberOfBones; i++) { QuaternionF quaternion = new QuaternionF( values[i * 4 + 0], values[i * 4 + 1], values[i * 4 + 2], values[i * 4 + 3]); // The quaternions were filtered using component-wise linear interpolation. This // is only an approximation which denormalizes the quaternions. // --> Renormalize the quaternions. quaternion.TryNormalize(); // Exchange the rotation in the bone transform. var boneTransform = SkeletonPose.GetBoneTransform(i); boneTransform.Rotation = quaternion; SkeletonPose.SetBoneTransform(i, boneTransform); } }
/// <summary> /// Adds an AngularLimit between the specified bones. /// </summary> /// <param name="skeletonPose">The skeleton pose.</param> /// <param name="ragdoll">The ragdoll.</param> /// <param name="parent">The parent bone.</param> /// <param name="child">The childbone .</param> /// <param name="minimum">The minimum limits for each constraint axis (x/y/z).</param> /// <param name="maximum">The maximum limits for each constraint axis (x/y/z).</param> /// <remarks> /// The constraint anchor orientation is the orientation of the child bone. /// </remarks> private static void AddAngularLimit(SkeletonPose skeletonPose, Ragdoll ragdoll, int parent, int child, Vector3F minimum, Vector3F maximum) { var skeleton = skeletonPose.Skeleton; var childBody = ragdoll.Bodies[child]; var childOffset = ragdoll.BodyOffsets[child]; var parentBody = ragdoll.Bodies[parent]; var parentOffset = ragdoll.BodyOffsets[parent]; var parentBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(parent).Inverse; var childBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(child).Inverse; var bindPoseRelative = parentBindPoseAbsolute.Inverse * childBindPoseAbsolute; var limit = new AngularLimit { BodyA = parentBody, BodyB = childBody, AnchorOrientationALocal = parentOffset.Orientation.Transposed * bindPoseRelative.Orientation, AnchorOrientationBLocal = childOffset.Orientation.Transposed, Minimum = minimum, Maximum = maximum, ErrorReduction = new Vector3F(0.2f), Softness = new Vector3F(0.001f) }; ragdoll.Limits.Add(limit); }
/// <summary> /// Initializes the ragdoll for the given skeleton pose. /// </summary> /// <param name="skeletonPose">The skeleton pose.</param> /// <param name="ragdoll">The ragdoll.</param> /// <param name="simulation">The simulation in which the ragdoll will be used.</param> public static void Create(SkeletonPose skeletonPose, Ragdoll ragdoll, Simulation simulation) { var skeleton = skeletonPose.Skeleton; const float totalMass = 80; // The total mass of the ragdoll. const int numberOfBodies = 17; // Get distance from foot to head as a measure for the size of the ragdoll. int head = skeleton.GetIndex("Head"); int footLeft = skeleton.GetIndex("L_Ankle1"); var headPosition = skeletonPose.GetBonePoseAbsolute(head).Translation; var footPosition = skeletonPose.GetBonePoseAbsolute(footLeft).Translation; var headToFootDistance = (headPosition - footPosition).Length; // We use the same mass properties for all bodies. This is not realistic but more stable // because large mass differences or thin bodies (arms!) are less stable. // We use the mass properties of sphere proportional to the size of the model. var massFrame = MassFrame.FromShapeAndMass(new SphereShape(headToFootDistance / 8), Vector3F.One, totalMass / numberOfBodies, 0.1f, 1); var material = new UniformMaterial(); #region ----- Add Bodies and Body Offsets ----- var numberOfBones = skeleton.NumberOfBones; ragdoll.Bodies.AddRange(Enumerable.Repeat<RigidBody>(null, numberOfBones)); ragdoll.BodyOffsets.AddRange(Enumerable.Repeat(Pose.Identity, numberOfBones)); var pelvis = skeleton.GetIndex("Pelvis"); ragdoll.Bodies[pelvis] = new RigidBody(new BoxShape(0.3f, 0.4f, 0.55f), massFrame, material); ragdoll.BodyOffsets[pelvis] = new Pose(new Vector3F(0.0f, 0, 0)); var backLower = skeleton.GetIndex("Spine"); ragdoll.Bodies[backLower] = new RigidBody(new BoxShape(0.36f, 0.4f, 0.55f), massFrame, material); ragdoll.BodyOffsets[backLower] = new Pose(new Vector3F(0.18f, 0, 0)); var backUpper = skeleton.GetIndex("Spine2"); ragdoll.Bodies[backUpper] = new RigidBody(new BoxShape(0.5f, 0.4f, 0.65f), massFrame, material); ragdoll.BodyOffsets[backUpper] = new Pose(new Vector3F(0.25f, 0, 0)); var neck = skeleton.GetIndex("Neck"); ragdoll.Bodies[neck] = new RigidBody(new CapsuleShape(0.12f, 0.3f), massFrame, material); ragdoll.BodyOffsets[neck] = new Pose(new Vector3F(0.15f, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); ragdoll.Bodies[neck].CollisionObject.Enabled = false; ragdoll.Bodies[head] = new RigidBody(new SphereShape(0.2f), massFrame, material); ragdoll.BodyOffsets[head] = new Pose(new Vector3F(0.15f, 0.02f, 0)); var armUpperLeft = skeleton.GetIndex("L_UpperArm"); ragdoll.Bodies[armUpperLeft] = new RigidBody(new CapsuleShape(0.12f, 0.6f), massFrame, material); ragdoll.BodyOffsets[armUpperLeft] = new Pose(new Vector3F(0.2f, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var armLowerLeft = skeleton.GetIndex("L_Forearm"); ragdoll.Bodies[armLowerLeft] = new RigidBody(new CapsuleShape(0.08f, 0.5f), massFrame, material); ragdoll.BodyOffsets[armLowerLeft] = new Pose(new Vector3F(0.2f, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var handLeft = skeleton.GetIndex("L_Hand"); ragdoll.Bodies[handLeft] = new RigidBody(new BoxShape(0.2f, 0.06f, 0.15f), massFrame, material); ragdoll.BodyOffsets[handLeft] = new Pose(new Vector3F(0.1f, 0, 0)); var armUpperRight = skeleton.GetIndex("R_UpperArm"); ragdoll.Bodies[armUpperRight] = new RigidBody(new CapsuleShape(0.12f, 0.6f), massFrame, material); ragdoll.BodyOffsets[armUpperRight] = new Pose(new Vector3F(0.2f, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var armLowerRight = skeleton.GetIndex("R_Forearm"); ragdoll.Bodies[armLowerRight] = new RigidBody(new CapsuleShape(0.08f, 0.5f), massFrame, material); ragdoll.BodyOffsets[armLowerRight] = new Pose(new Vector3F(0.2f, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var handRight = skeleton.GetIndex("R_Hand"); ragdoll.Bodies[handRight] = new RigidBody(new BoxShape(0.2f, 0.06f, 0.15f), massFrame, material); ragdoll.BodyOffsets[handRight] = new Pose(new Vector3F(0.1f, 0, 0)); var legUpperLeft = skeleton.GetIndex("L_Thigh1"); ragdoll.Bodies[legUpperLeft] = new RigidBody(new CapsuleShape(0.16f, 0.8f), massFrame, material); ragdoll.BodyOffsets[legUpperLeft] = new Pose(new Vector3F(0.4f, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var legLowerLeft = skeleton.GetIndex("L_Knee2"); ragdoll.Bodies[legLowerLeft] = new RigidBody(new CapsuleShape(0.12f, 0.65f), massFrame, material); ragdoll.BodyOffsets[legLowerLeft] = new Pose(new Vector3F(0.32f, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); //var footLeft = skeleton.GetIndex("L_Ankle1"); ragdoll.Bodies[footLeft] = new RigidBody(new BoxShape(0.20f, 0.5f, 0.3f), massFrame, material); ragdoll.BodyOffsets[footLeft] = new Pose(new Vector3F(0.16f, 0.15f, 0)); var legUpperRight = skeleton.GetIndex("R_Thigh"); ragdoll.Bodies[legUpperRight] = new RigidBody(new CapsuleShape(0.16f, 0.8f), massFrame, material); ragdoll.BodyOffsets[legUpperRight] = new Pose(new Vector3F(0.4f, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var legLowerRight = skeleton.GetIndex("R_Knee"); ragdoll.Bodies[legLowerRight] = new RigidBody(new CapsuleShape(0.12f, 0.65f), massFrame, material); ragdoll.BodyOffsets[legLowerRight] = new Pose(new Vector3F(0.32f, 0, 0), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); var footRight = skeleton.GetIndex("R_Ankle"); ragdoll.Bodies[footRight] = new RigidBody(new BoxShape(0.20f, 0.5f, 0.3f), massFrame, material); ragdoll.BodyOffsets[footRight] = new Pose(new Vector3F(0.16f, 0.15f, 0)); #endregion #region ----- Set Collision Filters ----- // Collisions between connected bodies will be disabled in AddJoint(). (A BallJoint // has a property CollisionEnabled which decides whether connected bodies can // collide.) // But we need to disable some more collision between bodies that are not directly // connected but still too close to each other. var filter = (ICollisionFilter)simulation.CollisionDomain.CollisionDetection.CollisionFilter; filter.Set(ragdoll.Bodies[backUpper].CollisionObject, ragdoll.Bodies[head].CollisionObject, false); filter.Set(ragdoll.Bodies[armUpperRight].CollisionObject, ragdoll.Bodies[backLower].CollisionObject, false); filter.Set(ragdoll.Bodies[armUpperLeft].CollisionObject, ragdoll.Bodies[backLower].CollisionObject, false); filter.Set(ragdoll.Bodies[legUpperLeft].CollisionObject, ragdoll.Bodies[legUpperRight].CollisionObject, false); #endregion #region ----- Add Joints ----- AddJoint(skeletonPose, ragdoll, pelvis, backLower); AddJoint(skeletonPose, ragdoll, backLower, backUpper); AddJoint(skeletonPose, ragdoll, backUpper, neck); AddJoint(skeletonPose, ragdoll, neck, head); AddJoint(skeletonPose, ragdoll, backUpper, armUpperLeft); AddJoint(skeletonPose, ragdoll, armUpperLeft, armLowerLeft); AddJoint(skeletonPose, ragdoll, armLowerLeft, handLeft); AddJoint(skeletonPose, ragdoll, backUpper, armUpperRight); AddJoint(skeletonPose, ragdoll, armUpperRight, armLowerRight); AddJoint(skeletonPose, ragdoll, armLowerRight, handRight); AddJoint(skeletonPose, ragdoll, pelvis, legUpperLeft); AddJoint(skeletonPose, ragdoll, legUpperLeft, legLowerLeft); AddJoint(skeletonPose, ragdoll, legLowerLeft, footLeft); AddJoint(skeletonPose, ragdoll, pelvis, legUpperRight); AddJoint(skeletonPose, ragdoll, legUpperRight, legLowerRight); AddJoint(skeletonPose, ragdoll, legLowerRight, footRight); #endregion #region ----- Add Limits ----- // Choosing limits is difficult. // We create hinge limits with AngularLimits in the back and in the knee. // For all other joints we use TwistSwingLimits with symmetric cones. AddAngularLimit(skeletonPose, ragdoll, pelvis, backLower, new Vector3F(0, 0, -0.3f), new Vector3F(0, 0, 0.3f)); AddAngularLimit(skeletonPose, ragdoll, backLower, backUpper, new Vector3F(0, 0, -0.3f), new Vector3F(0, 0, 0.4f)); AddAngularLimit(skeletonPose, ragdoll, backUpper, neck, new Vector3F(0, 0, -0.3f), new Vector3F(0, 0, 0.3f)); AddTwistSwingLimit(ragdoll, neck, head, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.1f, -0.5f, -0.7f), new Vector3F(0.1f, 0.5f, 0.7f)); var parentBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(backUpper).Inverse; var childBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(armUpperLeft).Inverse; var bindPoseRelative = parentBindPoseAbsolute.Inverse * childBindPoseAbsolute; AddTwistSwingLimit(ragdoll, backUpper, armUpperLeft, bindPoseRelative.Orientation * Matrix33F.CreateRotationY(-0.5f) * Matrix33F.CreateRotationZ(-0.5f), Matrix33F.Identity, new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(0.7f, 1.2f, 1.2f)); AddTwistSwingLimit(ragdoll, armUpperLeft, armLowerLeft, Matrix33F.CreateRotationZ(-1.2f), Matrix33F.Identity, new Vector3F(-0.3f, -1.2f, -1.2f), new Vector3F(0.3f, 1.2f, 1.2f)); AddTwistSwingLimit(ragdoll, armLowerLeft, handLeft, Matrix33F.Identity, Matrix33F.CreateRotationX(+ConstantsF.PiOver2), new Vector3F(-0.3f, -0.7f, -0.7f), new Vector3F(0.3f, 0.7f, 0.7f)); parentBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(backUpper).Inverse; childBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(armUpperRight).Inverse; bindPoseRelative = parentBindPoseAbsolute.Inverse * childBindPoseAbsolute; AddTwistSwingLimit(ragdoll, backUpper, armUpperRight, bindPoseRelative.Orientation * Matrix33F.CreateRotationY(0.5f) * Matrix33F.CreateRotationZ(-0.5f), Matrix33F.Identity, new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(0.7f, 1.2f, 1.2f)); AddTwistSwingLimit(ragdoll, armUpperRight, armLowerRight, Matrix33F.CreateRotationZ(-1.2f), Matrix33F.Identity, new Vector3F(-0.3f, -1.2f, -1.2f), new Vector3F(0.3f, 1.2f, 1.2f)); AddTwistSwingLimit(ragdoll, armLowerRight, handRight, Matrix33F.Identity, Matrix33F.CreateRotationX(-ConstantsF.PiOver2), new Vector3F(-0.3f, -0.7f, -0.7f), new Vector3F(0.3f, 0.7f, 0.7f)); parentBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(pelvis).Inverse; childBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(legUpperLeft).Inverse; bindPoseRelative = parentBindPoseAbsolute.Inverse * childBindPoseAbsolute; AddTwistSwingLimit(ragdoll, pelvis, legUpperLeft, bindPoseRelative.Orientation * Matrix33F.CreateRotationZ(1.2f), Matrix33F.Identity, new Vector3F(-0.1f, -0.7f, -1.5f), new Vector3F(+0.1f, +0.7f, +1.5f)); AddAngularLimit(skeletonPose, ragdoll, legUpperLeft, legLowerLeft, new Vector3F(0, 0, -2.2f), new Vector3F(0, 0, 0.0f)); AddTwistSwingLimit(ragdoll, legLowerLeft, footLeft, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.1f, -0.3f, -0.7f), new Vector3F(0.1f, 0.3f, 0.7f)); parentBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(pelvis).Inverse; childBindPoseAbsolute = (Pose)skeleton.GetBindPoseAbsoluteInverse(legUpperRight).Inverse; bindPoseRelative = parentBindPoseAbsolute.Inverse * childBindPoseAbsolute; AddTwistSwingLimit(ragdoll, pelvis, legUpperRight, bindPoseRelative.Orientation * Matrix33F.CreateRotationZ(1.2f), Matrix33F.Identity, new Vector3F(-0.1f, -0.7f, -1.5f), new Vector3F(+0.1f, +0.7f, +1.5f)); AddAngularLimit(skeletonPose, ragdoll, legUpperRight, legLowerRight, new Vector3F(0, 0, -2.2f), new Vector3F(0, 0, 0.0f)); AddTwistSwingLimit(ragdoll, legLowerRight, footRight, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.1f, -0.3f, -0.7f), new Vector3F(0.1f, 0.3f, 0.7f)); #endregion #region ----- Add Motors ----- ragdoll.Motors.AddRange(Enumerable.Repeat<RagdollMotor>(null, numberOfBones)); ragdoll.Motors[pelvis] = new RagdollMotor(pelvis, -1); ragdoll.Motors[backLower] = new RagdollMotor(backLower, pelvis); ragdoll.Motors[backUpper] = new RagdollMotor(backUpper, backLower); ragdoll.Motors[neck] = new RagdollMotor(neck, backUpper); ragdoll.Motors[head] = new RagdollMotor(head, neck); ragdoll.Motors[armUpperLeft] = new RagdollMotor(armUpperLeft, backUpper); ragdoll.Motors[armLowerLeft] = new RagdollMotor(armLowerLeft, armUpperLeft); ragdoll.Motors[handLeft] = new RagdollMotor(handLeft, armLowerLeft); ragdoll.Motors[armUpperRight] = new RagdollMotor(armUpperRight, backUpper); ragdoll.Motors[armLowerRight] = new RagdollMotor(armLowerRight, armUpperRight); ragdoll.Motors[handRight] = new RagdollMotor(handRight, armLowerRight); ragdoll.Motors[legUpperLeft] = new RagdollMotor(legUpperLeft, pelvis); ragdoll.Motors[legLowerLeft] = new RagdollMotor(legLowerLeft, legUpperLeft); ragdoll.Motors[footLeft] = new RagdollMotor(footLeft, legLowerLeft); ragdoll.Motors[legUpperRight] = new RagdollMotor(legUpperRight, pelvis); ragdoll.Motors[legLowerRight] = new RagdollMotor(legLowerRight, legUpperRight); ragdoll.Motors[footRight] = new RagdollMotor(footRight, legLowerRight); #endregion }
private void InitializeModels() { // Load the two different 3D human models. // The models use our custom SkinnedModelProcessor as the content processor! // This content processor stores the model's skeleton in the additional data of the model. _modelA = Game.Content.Load<Model>("Dude"); var additionalData = (Dictionary<string, object>)_modelA.Tag; var skeleton = (Skeleton)additionalData["Skeleton"]; _skeletonPoseA = SkeletonPose.Create(skeleton); _modelB = Game.Content.Load<Model>("PlayerMarine"); additionalData = (Dictionary<string, object>)_modelB.Tag; skeleton = (Skeleton)additionalData["Skeleton"]; _skeletonPoseB = SkeletonPose.Create(skeleton); }
private void InitializeSkeletonPoses() { // Create a list of the bone/joint names of a Kinect skeleton. int numberOfJoints = Enum.GetNames(typeof(JointType)).Length; var boneNames = new string[numberOfJoints]; for (int i = 0; i < numberOfJoints; i++) boneNames[i] = ((JointType)i).ToString(); // Create list with one entry per bone. Each entry is the index of the parent bone. var boneParents = new[] { -1, (int)JointType.HipCenter, (int)JointType.Spine, (int)JointType.ShoulderCenter, (int)JointType.ShoulderCenter, (int)JointType.ShoulderLeft, (int)JointType.ElbowLeft, (int)JointType.WristLeft, (int)JointType.ShoulderCenter, (int)JointType.ShoulderRight, (int)JointType.ElbowRight, (int)JointType.WristRight, (int)JointType.HipCenter, (int)JointType.HipLeft, (int)JointType.KneeLeft, (int)JointType.AnkleLeft, (int)JointType.HipCenter, (int)JointType.HipRight, (int)JointType.KneeRight, (int)JointType.AnkleRight, }; // Create a list of the bind pose transformations of all bones. Since we do not // get such information from Kinect, we position all bones in the local origin. var boneBindPoses = new SrtTransform[numberOfJoints]; for (int i = 0; i < numberOfJoints; i++) boneBindPoses[i] = SrtTransform.Identity; // Create a skeleton that defines the bone hierarchy and rest pose. var skeleton = new DRSkeleton(boneParents, boneNames, boneBindPoses); // Create a SkeletonPose for each player. SkeletonPoseA = SkeletonPose.Create(skeleton); SkeletonPoseB = SkeletonPose.Create(skeleton); }
private void UpdateKinectSkeletonPose(KinectSkeleton skeletonData, SkeletonPose skeletonPose) { if (skeletonData == null) return; // Update the skeleton pose using the data from Kinect. for (int i = 0; i < skeletonPose.Skeleton.NumberOfBones; i++) { var joint = (JointType)i; if (skeletonData.Joints[joint].TrackingState != JointTrackingState.NotTracked) { // The joint position in "Kinect space". SkeletonPoint kinectPosition = skeletonData.Joints[joint].Position; // Convert Kinect joint position to a Vector3F. // z is negated because in XNA the camera forward vectors is -z, but the Kinect // forward vector is +z. Vector3F position = new Vector3F(kinectPosition.X, kinectPosition.Y, -kinectPosition.Z); // Apply scale and offset. position = position * Scale + Offset; skeletonPose.SetBonePoseAbsolute(i, new SrtTransform(QuaternionF.Identity, position)); } } }
protected override void LoadContent() { _model = Game.Content.Load<Model>("PlayerMarine"); var additionalData = (Dictionary<string, object>)_model.Tag; var skeleton = (Skeleton)additionalData["Skeleton"]; _skeletonPose = SkeletonPose.Create(skeleton); var animations = (Dictionary<string, SkeletonKeyFrameAnimation>)additionalData["Animations"]; // Create a looping 'Idle' animation. _idleAnimation = new AnimationClip<SkeletonPose>(animations["Idle"]) { LoopBehavior = LoopBehavior.Cycle, Duration = TimeSpan.MaxValue, }; // Create a looping 'Run' animation. _runAnimation = new AnimationClip<SkeletonPose>(animations["Run"]) { LoopBehavior = LoopBehavior.Cycle, Duration = TimeSpan.MaxValue, }; // Combine the 'Aim' and 'Shoot' animation. The 'Aim' animation should start immediately. // The 'Shoot' animation should start after 0.3 seconds. // (Animations can be combined by creating timeline groups. All timelines/animations // in a timeline group are played simultaneously. AnimationClips can be used to // arrange animations on a timeline. The property Delay, for example, can be used to // set the begin time.) _aimAndShootAnimation = new TimelineGroup(); _aimAndShootAnimation.Add(animations["Aim"]); _aimAndShootAnimation.Add(new AnimationClip<SkeletonPose>(animations["Shoot"]) { Delay = TimeSpan.FromSeconds(0.3) }); // Start 'Idle' animation. We use a Replace transition with a fade-in. _idleAnimationController = AnimationService.StartAnimation( _idleAnimation, (IAnimatableProperty)_skeletonPose, AnimationTransitions.Replace(TimeSpan.FromSeconds(0.5))); _idleAnimationController.AutoRecycle(); base.LoadContent(); }
protected override void LoadContent() { _basicEffect = new BasicEffect(GraphicsDevice); // Load dude model. _dudeModel = Game.Content.Load<Model>("Dude"); // The SkinnedModelProcessor stores additional data in the tag. Dictionary<string, object> additionalData = (Dictionary<string, object>)_dudeModel.Tag; // Get the skeleton. Skeleton skeleton = (Skeleton)additionalData["Skeleton"]; // Create a skeleton pose that can be used transform and animate the skeleton. _dudeSkeletonPose = SkeletonPose.Create(skeleton); // Repeat the above steps for the marine model: _marineModel = Game.Content.Load<Model>("dude"); additionalData = (Dictionary<string, object>)_marineModel.Tag; skeleton = (Skeleton)additionalData["Skeleton"]; _marineSkeletonPose = SkeletonPose.Create(skeleton); base.LoadContent(); }
protected override void LoadContent() { _model = Game.Content.Load<Model>("PlayerMarine"); var additionalData = (Dictionary<string, object>)_model.Tag; var skeleton = (Skeleton)additionalData["Skeleton"]; _skeletonPose = SkeletonPose.Create(skeleton); var animations = (Dictionary<string, SkeletonKeyFrameAnimation>)additionalData["Animations"]; _runAnimation = new AnimationClip<SkeletonPose>(animations["Run"]) { LoopBehavior = LoopBehavior.Cycle, Duration = TimeSpan.MaxValue, }; _idleAnimation = new AnimationClip<SkeletonPose>(animations["Idle"]) { LoopBehavior = LoopBehavior.Cycle, Duration = TimeSpan.MaxValue, }; // Create a 'Shoot' animation that only affects the upper body. var shootAnimation = animations["Shoot"]; // The SkeletonKeyFrameAnimations allows to set a weight for each bone channel. // For the 'Shoot' animation, we set the weight to 0 for all bones that are // not descendants of the second spine bone (bone index 2). That means, the // animation affects only the upper body bones and is disabled on the lower // body bones. for (int i = 0; i < skeleton.NumberOfBones; i++) { if (!SkeletonHelper.IsAncestorOrSelf(_skeletonPose, 2, i)) shootAnimation.SetWeight(i, 0); } var loopedShootingAnimation = new AnimationClip<SkeletonPose>(shootAnimation) { LoopBehavior = LoopBehavior.Cycle, Duration = TimeSpan.MaxValue, }; // Start 'Idle' animation. _idleAnimationController = AnimationService.StartAnimation(_idleAnimation, (IAnimatableProperty)_skeletonPose); _idleAnimationController.AutoRecycle(); // Start looping the 'Shoot' animation. We use a Compose transition. This will add the // 'Shoot' animation to the animation composition chain and keeping all other playing // animations. // The 'Idle' animation animates the whole skeleton. The 'Shoot' animation replaces // the 'Idle' animation on the bones of the upper body. AnimationService.StartAnimation( loopedShootingAnimation, (IAnimatableProperty)_skeletonPose, AnimationTransitions.Compose()) .AutoRecycle(); base.LoadContent(); }
protected override void LoadContent() { _model = Game.Content.Load<Model>("Dude"); var additionalData = (Dictionary<string, object>)_model.Tag; var skeleton = (Skeleton)additionalData["Skeleton"]; _skeletonPose = SkeletonPose.Create(skeleton); base.LoadContent(); }
/// <summary> /// Copies the bone transforms from skeleton pose to another skeleton pose. /// </summary> /// <param name="source">The <see cref="SkeletonPose"/> from which the bone transforms are copied.</param> /// <param name="target">The <see cref="SkeletonPose"/> to which the bone transforms are copied.</param> /// <remarks> /// Copying a <see cref="SkeletonPose"/> using this method is faster than manually copying all /// bone transforms. /// </remarks> /// <exception cref="ArgumentNullException"> /// <paramref name="source"/> or <paramref name="target"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="source"/> and <paramref name="target"/> belong to different skeletons and /// <paramref name="target"/> has more bones than <paramref name="source"/>. /// </exception> public static void Copy(SkeletonPose source, SkeletonPose target) { if (source == null) throw new ArgumentNullException("source"); if (target == null) throw new ArgumentNullException("target"); if (target != source) { var sourceTransforms = source.BoneTransforms; var targetTransforms = target.BoneTransforms; Array.Copy(sourceTransforms, 0, targetTransforms, 0, targetTransforms.Length); target.Invalidate(); } }
protected void LoadModel(string filepath) { Moving = false; var contentManager = ServiceLocator.Current.GetInstance<ContentManager>(); var graphicsService = ServiceLocator.Current.GetInstance<IGraphicsService>(); var animationService = ServiceLocator.Current.GetInstance<IAnimationService>(); var screen = ((BasicScreen)graphicsService.Screens["Default"]); _model = Content.Load<Model>(filepath); var additionalData = (Dictionary<string, object>)_model.Tag; var skeleton = (Skeleton)additionalData["Skeleton"]; _skeletonPose = SkeletonPose.Create(skeleton); // var animations = (Dictionary<string, SkeletonKeyFrameAnimation>)additionalData["Animations"]; // SkeletonKeyFrameAnimation walkAnimation = animations.Values.First(); //_model = contentManager.Load<ModelNode>(filepath).Clone(); /* foreach (var meshNode in _model.GetSubtree().OfType<MeshNode>()) { Mesh mesh = meshNode.Mesh; foreach (var material in mesh.Materials) { var effectBinding = material["Default"]; effectBinding.Set("DiffuseColor", _color); ((BasicEffectBinding)effectBinding).LightingEnabled = false; } }*/ ID = screen.Add(_model, _pose, _skeletonPose); //screen.Scene.Children.Add(_model); }
/// <summary> /// converts SkeletonPose enum into spoken words /// </summary> /// <param name="pose"></param> /// <returns></returns> private string SkeletonPoseToSpokenString(SkeletonPose pose) { // split CamelCase into words: string sPose = pose.ToString(); Regex upperCaseRegex = new Regex(@"[A-Z]{1}[a-z]*"); MatchCollection matches = upperCaseRegex.Matches(sPose); List<string> words = new List<string>(); foreach (Match match in matches) { words.Add(match.Value); } return string.Join(" ", words.ToArray()); }
public SkeletonPoseFilter(SkeletonPose skeletonPose) { SkeletonPose = skeletonPose; TimeConstant = 0.05f; }
public override void Update(GameTime gameTime) { if (_avatarPose == null) { if (_avatarRenderer.State == AvatarRendererState.Ready) { _avatarPose = new AvatarPose(_avatarRenderer); _targetPose = SkeletonPose.Create(_avatarPose.SkeletonPose.Skeleton); // Create a ragdoll for the avatar. _ragdoll = Ragdoll.CreateAvatarRagdoll(_avatarPose, Simulation); // Set the world space pose of the whole ragdoll. And copy the bone poses // of the current skeleton pose. _ragdoll.Pose = _pose; _ragdoll.UpdateBodiesFromSkeleton(_avatarPose.SkeletonPose); // To simplify collision checks, we need a simple way to determine whether // a rigid body belongs to the ragdoll. // --> Set RigidBody.UserData = _ragdoll. // (Alternatively we could also set specific names for the rigid bodies, // or we could assign the collision objects to a certain collision group.) foreach (var body in _ragdoll.Bodies) if (body != null) body.UserData = _ragdoll; // Add rigid bodies and constraints to the simulation. _ragdoll.AddToSimulation(Simulation); // Start by playing the key frame animation. SwitchMode(RagdollMode.Mode1); // The facial expression can be applied directly to the _avatarPose. _animationController0 = AnimationService.StartAnimation(_expressionAnimation, _avatarPose); // The skeletal animation is applied to the _targetPose. The _targetPose // is used to drive the ragdoll. (See end of method.) _animationController1 = AnimationService.StartAnimation(_skeletonAnimation, (IAnimatableProperty<SkeletonPose>)_targetPose); } return; } if (InputService.IsPressed(Buttons.A, false, LogicalPlayerIndex.One)) SwitchMode(RagdollMode.Mode1); else if (InputService.IsPressed(Buttons.B, false, LogicalPlayerIndex.One)) SwitchMode(RagdollMode.Mode2); else if (InputService.IsPressed(Buttons.X, false, LogicalPlayerIndex.One)) SwitchMode(RagdollMode.Mode3); else if (InputService.IsPressed(Buttons.Y, false, LogicalPlayerIndex.One)) SwitchMode(RagdollMode.Mode4); if (_mode == RagdollMode.Mode1 || _mode == RagdollMode.Mode2) { // The ragdoll plays a certain animation. Check whether the character was // hit by a ball. foreach (var contactConstraint in Simulation.ContactConstraints) { if (contactConstraint.BodyA.UserData == _ragdoll && contactConstraint.BodyB.Name.StartsWith("Ball") || contactConstraint.BodyB.UserData == _ragdoll && contactConstraint.BodyA.Name.StartsWith("Ball")) { // Switch to the "Passive Ragdoll" mode and let the character collapse. SwitchMode(RagdollMode.Mode3); // Hint: You can read contactConstraint.LinearConstraintImpulse.Length to // determine the strength of the impact. } } } switch (_mode) { case RagdollMode.Mode1: // In mode 1 we update the rigid bodies directly. _ragdoll.UpdateBodiesFromSkeleton(_targetPose); break; case RagdollMode.Mode2: // Compute how much time the simulation will advance in the next Update(). TimeSpan nextSimulationTimeStep; int numberOfSubTimeSteps; Simulation.GetNextTimeStep(gameTime.ElapsedGameTime, out nextSimulationTimeStep, out numberOfSubTimeSteps); // In mode 2 velocity motors update the rigid bodies. _ragdoll.DriveToPose(_targetPose, (float)nextSimulationTimeStep.TotalSeconds); break; case RagdollMode.Mode3: // In mode 3 we don't have to update the rigid bodies. break; case RagdollMode.Mode4: // In mode 4 constraint motors control the joints of the ragdoll. // (The second parameter is only required for velocity motors.) _ragdoll.DriveToPose(_targetPose, 0); break; } // Copy the skeleton pose. (_avatarPose stores the skeleton pose which is // being rendered.) _ragdoll.UpdateSkeletonFromBodies(_avatarPose.SkeletonPose); _debugRenderer.Clear(); _debugRenderer.DrawText("\n"); _debugRenderer.DrawText(_statusMessage); // Render rigid bodies. foreach (var body in Simulation.RigidBodies) if (!(body.Shape is EmptyShape)) // Do not draw dummy bodies which might be used by the ragdoll. _debugRenderer.DrawObject(body, Color.Black, true, false); }
protected override void LoadContent() { // Add a ground plane to the simulation. Simulation.RigidBodies.Add( new RigidBody(new PlaneShape(Vector3F.UnitY, 0)) { MotionType = MotionType.Static }); // Load model. _model = Game.Content.Load<Model>("Dude"); var additionalData = (Dictionary<string, object>)_model.Tag; var skeleton = (Skeleton)additionalData["Skeleton"]; // Create the two skeleton poses. _targetSkeletonPose = SkeletonPose.Create(skeleton); _actualSkeletonPose = SkeletonPose.Create(skeleton); // Animate the _targetSkeletonPose. 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)_targetSkeletonPose); // Create a ragdoll for the Dude model. _ragdoll = new Ragdoll(); DudeRagdollCreator.Create(_targetSkeletonPose, _ragdoll, Simulation); // Set the world space pose of the whole ragdoll. And copy the bone poses of the // current skeleton pose. _ragdoll.Pose = _pose; _ragdoll.UpdateBodiesFromSkeleton(_targetSkeletonPose); // In this sample we use an active ragdoll. We need joints because constraint ragdoll // motors only affect the body rotations. _ragdoll.EnableJoints(); // We disable limits. If limits are enabled, the ragdoll could get unstable if // the animation tries to move a limb beyond an allowed limit. (This happens if // a pose in the animation violates one of our limits.) _ragdoll.DisableLimits(); // Set all motors to constraint motors. Constraint motors are like springs that // rotate the limbs to a target position. foreach (RagdollMotor motor in _ragdoll.Motors) { if (motor != null) { motor.Mode = RagdollMotorMode.Constraint; motor.ConstraintDamping = 10000; motor.ConstraintSpring = 100000; } } _ragdoll.EnableMotors(); // Add rigid bodies and the constraints of the ragdoll to the simulation. _ragdoll.AddToSimulation(Simulation); base.LoadContent(); }
protected override void LoadContent() { // Load model and start 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 a ragdoll for the Dude model. _ragdoll = new Ragdoll(); DudeRagdollCreator.Create(_skeletonPose, _ragdoll, Simulation); // Set the world space pose of the whole ragdoll. _ragdoll.Pose = _pose; // And copy the bone poses of the current skeleton pose. _ragdoll.UpdateBodiesFromSkeleton(_skeletonPose); foreach(var body in _ragdoll.Bodies) { if (body != null) { // Set all bodies to kinematic - they should not be affected by forces. body.MotionType = MotionType.Kinematic; // Disable collision response. body.CollisionResponseEnabled = false; } } // In this sample, we do not need joints, limits or motors. _ragdoll.DisableJoints(); _ragdoll.DisableLimits(); _ragdoll.DisableMotors(); // Add ragdoll rigid bodies to the simulation. _ragdoll.AddToSimulation(Simulation); base.LoadContent(); }
private void InitializeModel() { // Load dude model including the skeleton. _model = Game.Content.Load<Model>("Dude"); var additionalData = (Dictionary<string, object>)_model.Tag; var ragdollSkeleton = (DRSkeleton)additionalData["Skeleton"]; _skeletonPose = SkeletonPose.Create(ragdollSkeleton); // Create a ragdoll for the Dude model. _ragdoll = new Ragdoll(); DudeRagdollCreator.Create(_skeletonPose, _ragdoll, Simulation, 0.57f); // Set the world space pose of the whole ragdoll. And copy the bone poses of the // current skeleton pose. _ragdoll.UpdateBodiesFromSkeleton(_skeletonPose); // Disable sleeping. foreach (var body in _ragdoll.Bodies) { if (body != null) body.CanSleep = false; } // The pelvis bone (index 1) is updated directly from the Kinect hip center. _ragdoll.Bodies[1].MotionType = MotionType.Kinematic; // In this sample we use a passive ragdoll where we need joints to hold the // limbs together and limits to restrict angular movement. _ragdoll.EnableJoints(); _ragdoll.EnableLimits(); // Set all motors to constraint motors that only use damping. This adds a damping // effect to all ragdoll limbs. foreach (RagdollMotor motor in _ragdoll.Motors) { if (motor != null) { motor.Mode = RagdollMotorMode.Constraint; motor.ConstraintDamping = 100; motor.ConstraintSpring = 0; } } _ragdoll.EnableMotors(); // Add rigid bodies and the constraints of the ragdoll to the simulation. _ragdoll.AddToSimulation(Simulation); }
/// <summary> /// when changed, announce pose and react to it. Left and right are mirror in robot view. /// </summary> /// <param name="skeletonPose"></param> private void ReactOnSkeletonPose(SkeletonPose skeletonPose) { if (skeletonPose != skeletonPoseLast) { skeletonPoseLast = skeletonPose; switch (skeletonPose) { case SkeletonPose.NotDetected: // we don't come here with "NotDetected" case SkeletonPose.None: case SkeletonPose.BothArmsForward: // special case - growling at human break; default: talkerToHuman.Say(9, SkeletonPoseToSpokenString(skeletonPose)); break; } switch (skeletonPose) { case SkeletonPose.NotDetected: // we don't come here with "NotDetected" default: StartHeadAnimationCombo(HeadComboAnimations.Restpose); AddHeadAnimationCombo(HeadComboAnimations.BlinkCycle); HeadlightsOff(); break; case SkeletonPose.ArmsCrossed: case SkeletonPose.LeftHandPointingRight: case SkeletonPose.LeftHandUp: case SkeletonPose.RightHandPointingLeft: case SkeletonPose.RightHandUp: StartHeadAnimationCombo(HeadComboAnimations.Blink1, true, 0.5d); break; case SkeletonPose.None: //talkerToHuman.Say(9, "At ease"); HeadlightsOff(); StartHeadAnimationCombo(HeadComboAnimations.Restpose); AddHeadAnimationCombo(HeadComboAnimations.Acknowledge); break; case SkeletonPose.HandsUp: //talkerToHuman.Say(9, "Hands Up"); StartHeadAnimationCombo(HeadComboAnimations.Angry); break; case SkeletonPose.BothArmsForward: //talkerToHuman.Say(9, "Pointing At Me"); talkerToHuman.GrowlAtHuman(); break; case SkeletonPose.LeftArmForward: StartHeadAnimationCombo(HeadComboAnimations.Alert_lookright); break; case SkeletonPose.RightArmForward: StartHeadAnimationCombo(HeadComboAnimations.Alert_lookleft); break; // react to headlights commanding pose gestures: case SkeletonPose.BothArmsOut: { HeadlightsOn(); FollowDirectionTargetDistanceToGoalMeters += 0.3d; // hands to the sides also means back up a bit StartHeadAnimationCombo(HeadComboAnimations.Angry); } break; case SkeletonPose.LeftArmOut: { HeadlightsOnOff(false, true); // right light on StartHeadAnimationCombo(HeadComboAnimations.Acknowledge); AddHeadAnimationCombo(HeadComboAnimations.Turn_right); } break; case SkeletonPose.RightArmOut: { HeadlightsOnOff(true, false); // left light on StartHeadAnimationCombo(HeadComboAnimations.Acknowledge); AddHeadAnimationCombo(HeadComboAnimations.Turn_left); } break; } } }
public override void Update(GameTime gameTime) { base.Update(gameTime); if (_avatarPose == null) { if (_avatarRenderer.State == AvatarRendererState.Ready) { _avatarPose = new AvatarPose(_avatarRenderer); _targetPose = SkeletonPose.Create(_avatarPose.SkeletonPose.Skeleton); // Create a ragdoll for the avatar. _ragdoll = Ragdoll.CreateAvatarRagdoll(_avatarPose, Simulation); // Set the world space pose of the whole ragdoll. And copy the bone poses // of the current skeleton pose. _ragdoll.Pose = _pose; _ragdoll.UpdateBodiesFromSkeleton(_avatarPose.SkeletonPose); // To simplify collision checks, we need a simple way to determine whether // a rigid body belongs to the ragdoll. // --> Set RigidBody.UserData = _ragdoll. // (Alternatively we could also set specific names for the rigid bodies, // or we could assign the collision objects to a certain collision group.) foreach (var body in _ragdoll.Bodies) if (body != null) body.UserData = _ragdoll; // Add rigid bodies and constraints to the simulation. _ragdoll.AddToSimulation(Simulation); // Start by playing the key frame animation. SwitchMode(RagdollMode.Mode1); // The facial expression can be applied directly to the _avatarPose. _animationController0 = AnimationService.StartAnimation(_expressionAnimation, _avatarPose); // The skeletal animation is applied to the _targetPose. The _targetPose // is used to drive the ragdoll. (See end of method.) _animationController1 = AnimationService.StartAnimation(_skeletonAnimation, (IAnimatableProperty<SkeletonPose>)_targetPose); } return; } if (InputService.IsPressed(Buttons.A, false, PlayerIndex.One)) SwitchMode(RagdollMode.Mode1); else if (InputService.IsPressed(Buttons.B, false, PlayerIndex.One)) SwitchMode(RagdollMode.Mode2); else if (InputService.IsPressed(Buttons.X, false, PlayerIndex.One)) SwitchMode(RagdollMode.Mode3); else if (InputService.IsPressed(Buttons.Y, false, PlayerIndex.One)) SwitchMode(RagdollMode.Mode4); if (_mode == RagdollMode.Mode1 || _mode == RagdollMode.Mode2) { // The ragdoll plays a certain animation. Check whether the character was // hit by a ball. foreach (var contactConstraint in Simulation.ContactConstraints) { if (contactConstraint.BodyA.UserData == _ragdoll && contactConstraint.BodyB.Name.StartsWith("Ball") || contactConstraint.BodyB.UserData == _ragdoll && contactConstraint.BodyA.Name.StartsWith("Ball")) { // Switch to the "Passive Ragdoll" mode and let the character collapse. SwitchMode(RagdollMode.Mode3); // Hint: You can read contactConstraint.LinearConstraintImpulse.Length to // determine the strength of the impact. } } } switch (_mode) { case RagdollMode.Mode1: // In mode 1 we update the rigid bodies directly. _ragdoll.UpdateBodiesFromSkeleton(_targetPose); break; case RagdollMode.Mode2: // In mode 2 velocity motors update the rigid bodies. _ragdoll.DriveToPose(_targetPose, gameTime.ElapsedGameTime); break; case RagdollMode.Mode3: // In mode 3 we don't have to update the rigid bodies. break; case RagdollMode.Mode4: // In mode 4 constraint motors control the joints of the ragdoll. _ragdoll.DriveToPose(_targetPose, gameTime.ElapsedGameTime); break; } // Copy the skeleton pose. (_avatarPose stores the skeleton pose which is // being rendered.) _ragdoll.UpdateSkeletonFromBodies(_avatarPose.SkeletonPose); }