/// <summary> /// This method retrieves a new skeleton frame if necessary. /// </summary> /// <param name="gameTime">The elapsed game time.</param> public override void Update(GameTime gameTime) { // If the sensor is not found, not running, or not connected, return now if (null == this.Chooser || null == this.Chooser.Sensor || false == this.Chooser.Sensor.IsRunning || this.Chooser.Sensor.Status != KinectStatus.Connected) { return; } // If we have already drawn this skeleton, then we should retrieve a new frame // This prevents us from calling the next frame more than once per update if (false == this.SkeletonDrawn && null != this.skeleton && this.useKinectAvateering && this.SkeletonVisible) { // Copy all bind pose matrices to boneTransforms // Note: most are identity, but the translation is important to describe bone length/the offset between bone drawing positions this.skinningDataValue.BindPose.CopyTo(this.boneTransforms, 0); this.UpdateWorldTransforms(Matrix.Identity); this.UpdateSkinTransforms(); // If required, we should modify the joint positions before we access the bone orientations, as orientations are calculated // on the first access, and then whenever a joint position changes. Hence changing joint positions interleaved with accessing // rotations will cause unnecessary additional computation. float currentNuiTime = (float)this.frameTimer.AbsoluteTime; float deltaNuiTime = currentNuiTime - this.lastNuiTime; // Fixup Skeleton to improve avatar appearance. if (this.filterClippedLegs && null != this.clippedLegs && null != this.Chooser && !this.Chooser.SeatedMode) { this.clippedLegs.FilterSkeleton(this.skeleton, deltaNuiTime); } if (this.selfIntersectionConstraints) { // Constrain the wrist and hand joint positions to not intersect the torso SkeletonJointsSelfIntersectionConstraint.Constrain(this.skeleton); } if (this.tiltCompensate) { int elevationAngle = 0; try { elevationAngle = this.Chooser.Sensor.ElevationAngle; } catch (InvalidOperationException) { // Ignore any exception accessing the sensor if it has just been disconnected } // Correct for sensor tilt if we have a valid floor plane or a sensor tilt value from the motor. SkeletonJointsSensorTiltCorrection.CorrectSensorTilt(this.skeleton, this.FloorClipPlane, elevationAngle); } if (this.floorOffsetCompensate && 0.0f != this.AvatarHipCenterHeight) { // Correct for the sensor height from the floor (moves the skeleton to the floor plane) if we have a valid plane, or feet visible in the image. // Note that by default this will not run unless we have set a non-zero AvatarHipCenterHeight this.sensorOffsetCorrection.CorrectSkeletonOffsetFromFloor(this.skeleton, this.FloorClipPlane, this.AvatarHipCenterHeight); } if (this.mirrorView) { SkeletonJointsMirror.MirrorSkeleton(this.skeleton); } // Filter the joint positions manually, using a double exponential filter. this.jointPositionFilter.UpdateFilter(this.skeleton); if (this.boneConstraints && null != this.boneOrientationConstraints) { // Constrain the joint positions to approximate range of human motion. this.boneOrientationConstraints.Constrain(this.skeleton, this.mirrorView); } if (this.filterBoneOrientations && null != this.boneOrientationFilter) { // Double Exponential Filtering of the joint orientations. // Note: This updates the joint orientations directly in the skeleton. // It should be performed after all joint position modifications. this.boneOrientationFilter.UpdateFilter(this.skeleton); } if (null != this.retargetMethod) { // Adapt the rotation matrices to the avatar mesh joint local coordinate systems this.retargetMethod(this.skeleton, this.skinningDataValue.BindPose[0], this.boneTransforms); } // Calculate the Avatar world transforms from the relative bone transforms of Kinect skeleton this.UpdateWorldTransforms(Matrix.Identity); // Refresh the Avatar SkinTransforms data based on the transforms we just applied this.UpdateSkinTransforms(); this.lastNuiTime = currentNuiTime; } this.HandleInput(); base.Update(gameTime); }
/// <summary> /// This method retrieves a new skeleton frame if necessary. /// </summary> /// <param name="gameTime">The elapsed game time.</param> public Skeleton Filter(Skeleton skel) { this.skeleton = skel; // If we have already drawn this skeleton, then we should retrieve a new frame // This prevents us from calling the next frame more than once per update if (null != this.skeleton) { // If required, we should modify the joint positions before we access the bone orientations, as orientations are calculated // on the first access, and then whenever a joint position changes. Hence changing joint positions interleaved with accessing // rotations will cause unnecessary additional computation. float currentNuiTime = (float)this.frameTimer.AbsoluteTime; float deltaNuiTime = currentNuiTime - this.lastNuiTime; // Fixup Skeleton to improve avatar appearance. if (this.filterClippedLegs && null != this.clippedLegs) { this.clippedLegs.FilterSkeleton(this.skeleton, deltaNuiTime); } if (this.selfIntersectionConstraints) { // Constrain the wrist and hand joint positions to not intersect the torso SkeletonJointsSelfIntersectionConstraint.Constrain(this.skeleton); } if (this.tiltCompensate) { int elevationAngle = 0; try { elevationAngle = this.sensor.ElevationAngle; } catch (InvalidOperationException) { // Ignore any exception accessing the sensor if it has just been disconnected } // Correct for sensor tilt if we have a valid floor plane or a sensor tilt value from the motor. SkeletonJointsSensorTiltCorrection.CorrectSensorTilt(this.skeleton, this.FloorClipPlane, elevationAngle); } if (this.floorOffsetCompensate && 0.0f != this.AvatarHipCenterHeight) { // Correct for the sensor height from the floor (moves the skeleton to the floor plane) if we have a valid plane, or feet visible in the image. // Note that by default this will not run unless we have set a non-zero AvatarHipCenterHeight this.sensorOffsetCorrection.CorrectSkeletonOffsetFromFloor(this.skeleton, this.FloorClipPlane, this.AvatarHipCenterHeight); } if (this.mirrorView) { SkeletonJointsMirror.MirrorSkeleton(this.skeleton); } // Filter the joint positions manually, using a double exponential filter. this.jointPositionFilter.UpdateFilter(this.skeleton); if (this.boneConstraints && null != this.boneOrientationConstraints) { // Constrain the joint positions to approximate range of human motion. this.boneOrientationConstraints.Constrain(this.skeleton, this.mirrorView); } /*if (this.filterBoneOrientations && null != this.boneOrientationFilter) * { * // Double Exponential Filtering of the joint orientations. * // Note: This updates the joint orientations directly in the skeleton. * // It should be performed after all joint position modifications. * this.boneOrientationFilter.UpdateFilter(this.skeleton); * } */ this.lastNuiTime = currentNuiTime; } return(skel); }