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 static OutlineItem CreateOutlineItem(Skeleton skeleton, int boneIndex) { var item = new OutlineItem { Text = $"Bone {boneIndex} \"{skeleton.GetName(boneIndex)}\"", Icon = MultiColorGlyphs.Bone, Children = new OutlineItemCollection(), UserData = boneIndex, }; for (int bone = 0; bone < skeleton.NumberOfBones; bone++) if (skeleton.GetParent(bone) == boneIndex) item.Children.Add(CreateOutlineItem(skeleton, bone)); return item; }
private static OutlineItem CreateOutlineItem(Skeleton skeleton) { var item = new OutlineItem { Text = $"Skeleton \"{skeleton.Name}\"", Icon = MultiColorGlyphs.Skeleton, IsExpanded = false, Children = new OutlineItemCollection(), UserData = skeleton, }; for (int bone = 0; bone < skeleton.NumberOfBones; bone++) if (skeleton.GetParent(bone) == -1) item.Children.Add(CreateOutlineItem(skeleton, bone)); return item; }
/// <summary> /// Extracts all animations and stores them in a dictionary of timelines. /// </summary> private Dictionary<string, SkeletonKeyFrameAnimation> ProcessAnimations(AnimationContentDictionary animationContentDictionary, Skeleton skeleton, ContentProcessorContext context) { var animations = new Dictionary<string, SkeletonKeyFrameAnimation>(); foreach (var item in animationContentDictionary) { string animationName = item.Key; AnimationContent animationContent = item.Value; // Convert the AnimationContent to a SkeletonKeyFrameAnimation. SkeletonKeyFrameAnimation skeletonAnimation = ProcessAnimation(animationContent, skeleton, context); animations.Add(animationName, skeletonAnimation); } if (animations.Count == 0) context.Logger.LogWarning(null, null, "Skinned model does not contain any animations."); return animations; }
/// <summary> /// Converts an AnimationContent to a SkeletonKeyFrameAnimation. /// </summary> private SkeletonKeyFrameAnimation ProcessAnimation(AnimationContent animationContent, Skeleton skeleton, ContentProcessorContext context) { var animation = new SkeletonKeyFrameAnimation { EnableInterpolation = true }; // Process all animation channels (each channel animates a bone). int numberOfKeyFrames = 0; foreach (var item in animationContent.Channels) { string channelName = item.Key; AnimationChannel channel = item.Value; int boneIndex = skeleton.GetIndex(channelName); if (boneIndex == -1) { var message = string.Format("Found animation for bone '{0}', which is not part of the skeleton.", channelName); throw new InvalidContentException(message, animationContent.Identity); } var bindPoseRelativeInverse = skeleton.GetBindPoseRelative(boneIndex).Inverse; foreach (AnimationKeyframe keyframe in channel) { TimeSpan time = keyframe.Time; SrtTransform transform = SrtTransform.FromMatrix(keyframe.Transform); // The matrix in the key frame is the transformation in the coordinate space of the // parent bone. --> Convert it to a transformation relative to the animated bone. transform = bindPoseRelativeInverse * transform; // To start with minimal numerical errors, we normalize the rotation quaternion. transform.Rotation.Normalize(); animation.AddKeyFrame(boneIndex, time, transform); numberOfKeyFrames++; } } if (numberOfKeyFrames == 0) throw new InvalidContentException("Animation has no keyframes.", animationContent.Identity); // Compress animation to safe memory. float removedKeyFrames = animation.Compress( CompressionScaleThreshold, CompressionRotationThreshold, CompressionTranslationThreshold); if (removedKeyFrames > 0) context.Logger.LogImportantMessage("{0}: Compression removed {1:P} of all key frames.", animationContent.Name, removedKeyFrames); // Finalize the animation. (Optimizes the animation data for fast runtime access.) animation.Freeze(); return animation; }
/// <summary> /// Creates a <see cref="Ragdoll"/> for an Xbox LIVE Avatar. (Only available on Xbox 360.) /// </summary> /// <param name="skeleton">The skeleton of the Xbox LIVE Avatar.</param> /// <param name="simulation">The simulation.</param> /// <returns>The avatar ragdoll.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="skeleton"/> or <paramref name="simulation"/> is /// <see langword="null"/>. /// </exception> /// <remarks> /// This method is available only in the Xbox 360 build of the /// DigitalRune.Physics.Specialized.dll. /// </remarks> public static Ragdoll CreateAvatarRagdoll(Skeleton skeleton, Simulation simulation) { if (skeleton == null) throw new ArgumentNullException("skeleton"); if (simulation == null) throw new ArgumentNullException("simulation"); var ragdoll = new Ragdoll(); // The lists ragdoll.Bodies, ragdoll.BodyOffsets and _motors contain one entry per bone - even if there // is no RigidBody for this bone. - This wastes memory but simplifies the code. for (int i = 0; i < AvatarRenderer.BoneCount; i++) { ragdoll.Bodies.Add(null); ragdoll.BodyOffsets.Add(Pose.Identity); ragdoll.Joints.Add(null); ragdoll.Limits.Add(null); ragdoll.Motors.Add(null); } // ----- Create bodies. // We use the same mass for all bodies. This is not physically correct but it makes the // simulation more stable, for several reasons: // - It is better to avoid large mass differences. Therefore, all limbs have the same mass. // - Capsule shapes have a low inertia value about their height axis. This causes instability // and it is better to use larger inertia values. var massFrame = MassFrame.FromShapeAndMass(new SphereShape(0.2f), Vector3F.One, 4, 0.1f, 1); // Use standard material. var material = new UniformMaterial(); // Create rigid bodies for the important bones. The shapes have been manually adapted to // produce useful results for thin and overweight avatars. // Without offset, the bodies are centered at the joint. ragdoll.BodyOffsets stores an offset pose // for each body. Instead, we could use TransformedShape but we can easily handle that // ourselves. // The collar bones are special, they use dummy shapes and are only used to connect the // shoulder bones. ragdoll.Bodies[(int)AvatarBone.Root] = new RigidBody(new BoxShape(0.22f, 0.16f, 0.16f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.Root] = new Pose(new Vector3F(0, -0.08f, -0.01f), QuaternionF.CreateRotationX(-0.0f)); ragdoll.Bodies[(int)AvatarBone.BackLower] = new RigidBody(new BoxShape(0.22f, 0.16f, 0.16f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.BackLower] = new Pose(new Vector3F(0, 0.08f, -0.01f), QuaternionF.CreateRotationX(-0.0f)); ragdoll.Bodies[(int)AvatarBone.BackUpper] = new RigidBody(new BoxShape(0.22f, 0.16f, 0.16f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.BackUpper] = new Pose(new Vector3F(0, 0.08f, -0.01f), QuaternionF.CreateRotationX(-0.1f)); ragdoll.Bodies[(int)AvatarBone.Neck] = new RigidBody(new CapsuleShape(0.04f, 0.09f), massFrame, material); ragdoll.Bodies[(int)AvatarBone.Head] = new RigidBody(new SphereShape(0.15f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.Head] = new Pose(new Vector3F(0, 0.1f, 0)); ragdoll.Bodies[(int)AvatarBone.CollarLeft] = new RigidBody(Shape.Empty, massFrame, material); ragdoll.Bodies[(int)AvatarBone.CollarRight] = new RigidBody(Shape.Empty, massFrame, material); ragdoll.Bodies[(int)AvatarBone.ShoulderLeft] = new RigidBody(new CapsuleShape(0.04f, 0.25f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.ShoulderLeft] = new Pose(new Vector3F(0.08f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); ragdoll.Bodies[(int)AvatarBone.ShoulderRight] = new RigidBody(new CapsuleShape(0.04f, 0.25f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.ShoulderRight] = new Pose(new Vector3F(-0.08f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); ragdoll.Bodies[(int)AvatarBone.ElbowLeft] = new RigidBody(new CapsuleShape(0.04f, 0.21f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.ElbowLeft] = new Pose(new Vector3F(0.06f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); ragdoll.Bodies[(int)AvatarBone.ElbowRight] = new RigidBody(new CapsuleShape(0.04f , 0.21f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.ElbowRight] = new Pose(new Vector3F(-0.06f, 0, -0.02f), QuaternionF.CreateRotationZ(ConstantsF.PiOver2)); ragdoll.Bodies[(int)AvatarBone.WristLeft] = new RigidBody(new BoxShape(0.1f, 0.04f, 0.1f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.WristLeft] = new Pose(new Vector3F(0.06f, -0.02f, -0.01f), QuaternionF.CreateRotationZ(0.0f)); ragdoll.Bodies[(int)AvatarBone.WristRight] = new RigidBody(new BoxShape(0.1f, 0.04f, 0.1f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.WristRight] = new Pose(new Vector3F(-0.06f, -0.02f, -0.01f), QuaternionF.CreateRotationZ(0.0f)); ragdoll.Bodies[(int)AvatarBone.HipLeft] = new RigidBody(new CapsuleShape(0.06f, 0.34f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.HipLeft] = new Pose(new Vector3F(0, -0.14f, -0.02f), QuaternionF.CreateRotationX(0.1f)); ragdoll.Bodies[(int)AvatarBone.HipRight] = new RigidBody(new CapsuleShape(0.06f, 0.34f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.HipRight] = new Pose(new Vector3F(0, -0.14f, -0.02f), QuaternionF.CreateRotationX(0.1f)); ragdoll.Bodies[(int)AvatarBone.KneeLeft] = new RigidBody(new CapsuleShape(0.06f, 0.36f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.KneeLeft] = new Pose(new Vector3F(0, -0.18f, -0.04f), QuaternionF.CreateRotationX(0.1f)); ragdoll.Bodies[(int)AvatarBone.KneeRight] = new RigidBody(new CapsuleShape(0.06f, 0.36f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.KneeRight] = new Pose(new Vector3F(0, -0.18f, -0.04f), QuaternionF.CreateRotationX(0.1f)); ragdoll.Bodies[(int)AvatarBone.AnkleLeft] = new RigidBody(new BoxShape(0.1f, 0.06f, 0.22f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.AnkleLeft] = new Pose(new Vector3F(0, -0.07f, 0.05f), QuaternionF.CreateRotationZ(0)); ragdoll.Bodies[(int)AvatarBone.AnkleRight] = new RigidBody(new BoxShape(0.1f, 0.06f, 0.22f), massFrame, material); ragdoll.BodyOffsets[(int)AvatarBone.AnkleRight] = new Pose(new Vector3F(0, -0.07f, 0.05f), QuaternionF.CreateRotationZ(0)); // ----- Add joint constraints. const float jointErrorReduction = 0.2f; const float jointSoftness = 0.0001f; AddJoint(ragdoll, skeleton, AvatarBone.Root, AvatarBone.BackLower, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.BackLower, AvatarBone.BackUpper, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.Neck, 0.6f, 0.000001f); AddJoint(ragdoll, skeleton, AvatarBone.Neck, AvatarBone.Head, 0.6f, 0.000001f); AddJoint(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.CollarLeft, AvatarBone.ShoulderLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.CollarRight, AvatarBone.ShoulderRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.ShoulderLeft, AvatarBone.ElbowLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.ShoulderRight, AvatarBone.ElbowRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.ElbowLeft, AvatarBone.WristLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.ElbowRight, AvatarBone.WristRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.HipLeft, AvatarBone.KneeLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.HipRight, AvatarBone.KneeRight, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.KneeLeft, AvatarBone.AnkleLeft, jointErrorReduction, jointSoftness); AddJoint(ragdoll, skeleton, AvatarBone.KneeRight, AvatarBone.AnkleRight, jointErrorReduction, jointSoftness); // ----- Add constraint limits. // We use TwistSwingLimits to define an allowed twist and swing cone for the joints. // Exceptions are the back and knees, where we use AngularLimits to create hinges. // (We could also create a hinge with a TwistSwingLimit where the twist axis is the hinge // axis and no swing is allowed - but AngularLimits create more stable hinges.) // Another exception are the collar bones joint. We use AngularLimits to disallow any // rotations. AddAngularLimit(ragdoll, skeleton, AvatarBone.Root, AvatarBone.BackLower, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackLower).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackLower).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(-0.3f, 0, 0), new Vector3F(0.3f, 0, 0)); AddAngularLimit(ragdoll, skeleton, AvatarBone.BackLower, AvatarBone.BackUpper, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackUpper).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.BackUpper).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(-0.3f, 0, 0), new Vector3F(0.4f, 0, 0)); var rotationZ90Degrees = Matrix33F.CreateRotationZ(ConstantsF.PiOver2); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.Neck, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.3f, -0.3f), new Vector3F(+0.1f, +0.3f, +0.3f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.Neck, AvatarBone.Head, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.6f, -0.6f), new Vector3F(+0.1f, +0.6f, +0.6f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarLeft, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarLeft).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarLeft).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(0), new Vector3F(0)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.BackUpper, AvatarBone.CollarRight, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarRight).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.CollarRight).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(0), new Vector3F(0)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.CollarLeft, AvatarBone.ShoulderLeft, Matrix33F.Identity, Matrix33F.CreateRotationY(0.7f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.CollarRight, AvatarBone.ShoulderRight, Matrix33F.Identity, Matrix33F.CreateRotationY(-0.7f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ShoulderLeft, AvatarBone.ElbowLeft, Matrix33F.Identity, Matrix33F.CreateRotationY(1.2f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ShoulderRight, AvatarBone.ElbowRight, Matrix33F.Identity, Matrix33F.CreateRotationY(-1.2f), new Vector3F(-0.7f, -1.2f, -1.2f), new Vector3F(+0.7f, +1.2f, +1.2f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ElbowLeft, AvatarBone.WristLeft, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.7f, -0.7f, -0.7f), new Vector3F(+0.7f, +0.7f, +0.7f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.ElbowRight, AvatarBone.WristRight, Matrix33F.Identity, Matrix33F.Identity, new Vector3F(-0.7f, -0.7f, -0.7f), new Vector3F(+0.7f, +0.7f, +0.7f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipLeft, rotationZ90Degrees, Matrix33F.CreateRotationX(-1.2f) * Matrix33F.CreateRotationZ(ConstantsF.PiOver2 + 0.2f), new Vector3F(-0.1f, -1.5f, -0.7f), new Vector3F(+0.1f, +1.5f, +0.7f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.Root, AvatarBone.HipRight, rotationZ90Degrees, Matrix33F.CreateRotationX(-1.2f) * Matrix33F.CreateRotationZ(ConstantsF.PiOver2 - 0.2f), new Vector3F(-0.1f, -1.5f, -0.7f), new Vector3F(+0.1f, +1.5f, +0.7f)); AddAngularLimit(ragdoll, skeleton, AvatarBone.HipLeft, AvatarBone.KneeLeft, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeLeft).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeLeft).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(0, 0, 0), new Vector3F(2.2f, 0, 0)); AddAngularLimit(ragdoll, skeleton, AvatarBone.HipRight, AvatarBone.KneeRight, skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeRight).Rotation.Conjugated.ToRotationMatrix33(), skeleton.GetBindPoseAbsoluteInverse((int)AvatarBone.KneeRight).Rotation.Conjugated.ToRotationMatrix33(), new Vector3F(0, 0, 0), new Vector3F(2.2f, 0, 0)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.KneeLeft, AvatarBone.AnkleLeft, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.7f, -0.3f), new Vector3F(+0.1f, +0.7f, +0.3f)); AddTwistSwingLimit(ragdoll, skeleton, AvatarBone.KneeRight, AvatarBone.AnkleRight, rotationZ90Degrees, rotationZ90Degrees, new Vector3F(-0.1f, -0.7f, -0.3f), new Vector3F(+0.1f, +0.7f, +0.3f)); // ----- Add motors // We use QuaternionMotors to create forces that rotate the bones into desired poses. // This can be used for damping, spring or animating the ragdoll. AddMotor(ragdoll, (AvatarBone)(-1), AvatarBone.Root); AddMotor(ragdoll, AvatarBone.Root, AvatarBone.BackLower); AddMotor(ragdoll, AvatarBone.BackLower, AvatarBone.BackUpper); AddMotor(ragdoll, AvatarBone.BackUpper, AvatarBone.Neck); AddMotor(ragdoll, AvatarBone.Neck, AvatarBone.Head); AddMotor(ragdoll, AvatarBone.BackUpper, AvatarBone.CollarLeft); AddMotor(ragdoll, AvatarBone.BackUpper, AvatarBone.CollarRight); AddMotor(ragdoll, AvatarBone.CollarLeft, AvatarBone.ShoulderLeft); AddMotor(ragdoll, AvatarBone.CollarRight, AvatarBone.ShoulderRight); AddMotor(ragdoll, AvatarBone.ShoulderLeft, AvatarBone.ElbowLeft); AddMotor(ragdoll, AvatarBone.ShoulderRight, AvatarBone.ElbowRight); AddMotor(ragdoll, AvatarBone.ElbowLeft, AvatarBone.WristLeft); AddMotor(ragdoll, AvatarBone.ElbowRight, AvatarBone.WristRight); AddMotor(ragdoll, AvatarBone.Root, AvatarBone.HipLeft); AddMotor(ragdoll, AvatarBone.Root, AvatarBone.HipRight); AddMotor(ragdoll, AvatarBone.HipLeft, AvatarBone.KneeLeft); AddMotor(ragdoll, AvatarBone.HipRight, AvatarBone.KneeRight); AddMotor(ragdoll, AvatarBone.KneeLeft, AvatarBone.AnkleLeft); AddMotor(ragdoll, AvatarBone.KneeRight, AvatarBone.AnkleRight); // ----- Set collision filters. // Collisions between connected bones have been disabled with Constraint.CollisionEnabled // = false in the joints. We need to disable a few other collisions. // Following bodies do not collide with anything. They are only used to connect other // bones. ragdoll.Bodies[(int)AvatarBone.Neck].CollisionObject.Enabled = false; ragdoll.Bodies[(int)AvatarBone.CollarLeft].CollisionObject.Enabled = false; ragdoll.Bodies[(int)AvatarBone.CollarRight].CollisionObject.Enabled = false; // We disable filters for following body pairs because they are usually penetrating each // other, which needs to be ignored. var filter = simulation.CollisionDomain.CollisionDetection.CollisionFilter as CollisionFilter; if (filter != null) { filter.Set(ragdoll.Bodies[(int)AvatarBone.BackUpper].CollisionObject, ragdoll.Bodies[(int)AvatarBone.ShoulderLeft].CollisionObject, false); filter.Set(ragdoll.Bodies[(int)AvatarBone.BackUpper].CollisionObject, ragdoll.Bodies[(int)AvatarBone.ShoulderRight].CollisionObject, false); } return ragdoll; }
private static void AddTwistSwingLimit(Ragdoll ragdoll, Skeleton skeleton, AvatarBone parentBone, AvatarBone childBone, Matrix33F orientationA, Matrix33F orientationB, Vector3F minimum, Vector3F maximum) { int parentIndex = (int)parentBone; int childIndex = (int)childBone; // The difficult part is to define the constraint anchor orientation. // Here is how we do it: // When we look at the front side of an Avatar in bind pose, the x-axis is parallel // to the arms. y points up and z is normal to the those axes. // // To define orientationA/B: // The anchor x-axis is the twist axis. That means, this is already the correct axis // for the hands (wrist joints) and orientationA/B are therefore Matrix33F.Identity. // For the Head, the twist axis must point up. Therefore orientationA/B must be a 90° // rotation about z to rotate the twist axis up. // For the shoulder-elbow connection, orientationA is Matrix.Identity. The swing cone must // not be parallel to the arm axis (because the elbow cannot bend backwards). Therefore, // orientationB defines a rotation that rotates the twist axis (= swing cone center) to the // front. // // To define AnchorOrientationALocal/AnchorOrientationBLocal: // AnchorOrientationALocal must be a rotation matrix that transforms a vector from local // constraint anchor space to local body space of A. // orientationA defines the constraint anchor orientation in model space. // With jointPosesAbsolute[boneAIndex].Orientation.Transposed, we convert from model space // to joint space. With ragdoll.BodyOffsets[boneAIndex].Orientation.Transposed, we convert from joint // space to body space. The combined rotation matrix converts from constraint anchor space // to body space. var limit = new TwistSwingLimit { BodyA = ragdoll.Bodies[parentIndex], BodyB = ragdoll.Bodies[childIndex], AnchorOrientationALocal = ragdoll.BodyOffsets[parentIndex].Orientation.Transposed * skeleton.GetBindPoseAbsoluteInverse(parentIndex).Rotation.ToRotationMatrix33() * orientationA, AnchorOrientationBLocal = ragdoll.BodyOffsets[childIndex].Orientation.Transposed * skeleton.GetBindPoseAbsoluteInverse(childIndex).Rotation.ToRotationMatrix33() * orientationB, Minimum = minimum, Maximum = maximum, ErrorReduction = 0.2f, Softness = 0.001f }; ragdoll.Limits[childIndex] = limit; }
private static void AddJoint(Ragdoll ragdoll, Skeleton skeleton, AvatarBone parentBone, AvatarBone childBone, float errorReduction, float softness) { int parentIndex = (int)parentBone; int childIndex = (int)childBone; // To define AnchorPositionALocal/AnchorPositionBLocal: // To get the AnchorPositionALocal we apply jointPosesAbsolute[indexA].Inverse to // convert the joint pose from model space into the joints space of parentBone. Then we apply // ragdoll.BodyOffsets[boneAIndex].Inverse to convert from joint space to body space. The result is // the joint position of B in body space of A. // To get AnchorPositionBLocal, we only have to apply the inverse offset. BallJoint joint = new BallJoint { BodyA = ragdoll.Bodies[parentIndex], BodyB = ragdoll.Bodies[childIndex], CollisionEnabled = false, AnchorPositionALocal = (ragdoll.BodyOffsets[parentIndex].Inverse * skeleton.GetBindPoseAbsoluteInverse(parentIndex) * skeleton.GetBindPoseAbsoluteInverse(childIndex).Inverse).Translation, AnchorPositionBLocal = ragdoll.BodyOffsets[childIndex].Inverse.Position, ErrorReduction = errorReduction, Softness = softness, }; ragdoll.Joints[childIndex] = joint; }
private static void AddAngularLimit(Ragdoll ragdoll, Skeleton skeleton, AvatarBone parentBone, AvatarBone childBone, Matrix33F orientationA, Matrix33F orientationB, Vector3F minimum, Vector3F maximum) { // Similar to AddTwistSwingLimit int parentIndex = (int)parentBone; int childIndex = (int)childBone; var limit = new AngularLimit { BodyA = ragdoll.Bodies[parentIndex], BodyB = ragdoll.Bodies[childIndex], AnchorOrientationALocal = ragdoll.BodyOffsets[parentIndex].Orientation.Transposed * skeleton.GetBindPoseAbsoluteInverse(parentIndex).Rotation.ToRotationMatrix33() * orientationA, AnchorOrientationBLocal = ragdoll.BodyOffsets[childIndex].Orientation.Transposed * skeleton.GetBindPoseAbsoluteInverse(childIndex).Rotation.ToRotationMatrix33() * orientationB, Minimum = minimum, Maximum = maximum, ErrorReduction = new Vector3F(0.2f), Softness = new Vector3F(0.001f) }; ragdoll.Limits[childIndex] = limit; }
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 BuildSkeleton() { // Get an array of all bones in depth-first order. // (Same as MeshHelper.FlattenSkeleton(root).) var bones = TreeHelper.GetSubtree(_rootBone, n => n.Children.OfType<BoneContent>(), true) .ToList(); // Create list of parent indices, bind pose transformations and bone names. var boneParents = new List<int>(); var bindTransforms = new List<SrtTransform>(); var boneNames = new List<string>(); int numberOfWarnings = 0; foreach (var bone in bones) { int parentIndex = bones.IndexOf(bone.Parent as BoneContent); boneParents.Add(parentIndex); // Log warning for invalid transform matrices - but not too many warnings. if (numberOfWarnings < 2) { if (!SrtTransform.IsValid((Matrix44F)bone.Transform)) { if (numberOfWarnings < 1) _context.Logger.LogWarning(null, _input.Identity, "Bone transform is not supported. Bone transform matrices may only contain scaling, rotation and translation."); else _context.Logger.LogWarning(null, _input.Identity, "More unsupported bone transform found."); numberOfWarnings++; } } bindTransforms.Add(SrtTransform.FromMatrix(bone.Transform)); if (boneNames.Contains(bone.Name)) { string message = String.Format(CultureInfo.InvariantCulture, "Duplicate bone name (\"{0}\") found.", bone.Name); throw new InvalidContentException(message, _input.Identity); } boneNames.Add(bone.Name); } // Create and return a new skeleton instance. _skeleton = new Skeleton(boneParents, boneNames, bindTransforms); }