繁体   English   中英

如何设置Kinect头像原点轴?

[英]How to set Kinect avatar origin axes?

我正在使用XNA Frameworks开发Kinect项目。 我想使化身在原点轴上保持稳定,以使其看起来像在现实世界中的地板上一样。 我更改了骨骼转换轴,但没有任何积极进展。

这是骨骼转换代码块:

private void SetJointTransformation(BoneOrientation bone, Skeleton skeleton, Matrix bindRoot, ref Matrix[] boneTransforms)
{
    // Always look at the skeleton root
    if (bone.StartJoint == JointType.HipCenter && bone.EndJoint == JointType.HipCenter)
    {
        // Unless in seated mode, the hip center is special - it is the root of the NuiSkeleton and describes the skeleton orientation in the world
        // (camera) coordinate system. All other bones/joint orientations in the hierarchy have hip center as one of their parents.
        // However, if in seated mode, the shoulder center then holds the skeleton orientation in the world (camera) coordinate system.
        bindRoot.Translation = Vector3.Zero;
        Matrix invBindRoot = Matrix.Invert(bindRoot);

        Matrix hipOrientation = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);

        // Here we create a rotation matrix for the hips from the inverse of the bind pose
        // for the pelvis rotation and the inverse of the bind pose for the root node (0) in the Dude model.
        // This multiplication effectively removes the initial 90 degree rotations set in the first two model nodes.
        Matrix pelvis = boneTransforms[1];
        pelvis.Translation = Vector3.Zero; // Ensure pure rotation as we explicitly set world translation from the Kinect camera below.
        Matrix invPelvis = Matrix.Invert(pelvis);

        Matrix combined = (invBindRoot * hipOrientation) * invPelvis;

        this.ReplaceBoneMatrix(JointType.HipCenter, combined, true, ref boneTransforms);
    }
    else if (bone.EndJoint == JointType.ShoulderCenter)
    {
        // This contains an absolute rotation if we are in seated mode, or the hip center is not tracked, as the HipCenter will be identity
        if (this.chooser.SeatedMode || (this.Chooser.SeatedMode == false && skeleton.Joints[JointType.HipCenter].TrackingState == JointTrackingState.NotTracked))
        {
            bindRoot.Translation = Vector3.Zero;
            Matrix invBindRoot = Matrix.Invert(bindRoot);

            Matrix hipOrientation = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);

            // We can use the same method as in HipCenter above to invert the root and pelvis bind pose,
            // however, alternately we can also explicitly swap axes and adjust the rotations to get from
            // the Kinect rotation to the model hip orientation, similar to what we do for the following joints/bones.

            // Kinect = +X left, +Y up, +Z forward in body coordinate system
            // Avatar = +Z left, +X up, +Y forward
            Quaternion kinectRotation = KinectHelper.DecomposeMatRot(hipOrientation);    // XYZ
            Quaternion avatarRotation = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f); // transform from Kinect to avatar coordinate system
            Matrix combined = Matrix.CreateFromQuaternion(avatarRotation);

            // Add a small adjustment rotation to manually correct for the rotation in the parent bind
            // pose node in the model mesh - this can be found by looking in the FBX or in 3DSMax/Maya.
            Matrix adjustment = Matrix.CreateRotationY(MathHelper.ToRadians(-90));
            combined *= adjustment;
            Matrix adjustment2 = Matrix.CreateRotationZ(MathHelper.ToRadians(-90));
            combined *= adjustment2;

            // Although not strictly correct, we apply this to the hip center, as all other bones are children of this joint.
            // Application at the spine or shoulder center instead would require manually updating of the bone orientations below for the whole body to move when the shoulders twist or tilt.
            this.ReplaceBoneMatrix(JointType.HipCenter, combined, true, ref boneTransforms);
        }
    }
    else if (bone.EndJoint == JointType.Spine)
    {
        Matrix tempMat = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);

        // The Dude appears to lean back too far compared to a real person, so here we adjust this lean.
        this.CorrectBackwardsLean(skeleton, ref tempMat);

        // Also add a small constant adjustment rotation to correct for the hip center to spine bone being at a rear-tilted angle in the Kinect skeleton.
        // The dude should now look more straight ahead when avateering
        Matrix adjustment = Matrix.CreateRotationX(MathHelper.ToRadians(20));  // 20 degree rotation around the local Kinect x axis for the spine bone.
        tempMat *= adjustment;

        // Kinect = +X left, +Y up, +Z forward in body coordinate system
        // Avatar = +Z left, +X up, +Y forward
        Quaternion kinectRotation = KinectHelper.DecomposeMatRot(tempMat);    // XYZ
        Quaternion avatarRotation = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f); // transform from Kinect to avatar coordinate system
        tempMat = Matrix.CreateFromQuaternion(avatarRotation);

        // Set the corresponding matrix in the avatar using the translation table we specified.
        // Note for the spine and shoulder center rotations, we could also try to spread the angle
        // over all the Avatar skeleton spine joints, causing a more curved back, rather than apply
        // it all to one joint, as we do here.
        this.ReplaceBoneMatrix(bone.EndJoint, tempMat, false, ref boneTransforms);
    }
    else if (bone.EndJoint == JointType.Head)
    {
        Matrix tempMat = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);

        // Add a small adjustment rotation to correct for the avatar skeleton head bones being defined pointing looking slightly down, not vertical.
        // The dude should now look more straight ahead when avateering
        Matrix adjustment = Matrix.CreateRotationX(MathHelper.ToRadians(-30));  // -30 degree rotation around the local Kinect x axis for the head bone.
        tempMat *= adjustment;

        // Kinect = +X left, +Y up, +Z forward in body coordinate system
        // Avatar = +Z left, +X up, +Y forward
        Quaternion kinectRotation = KinectHelper.DecomposeMatRot(tempMat);    // XYZ
        Quaternion avatarRotation = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f); // transform from Kinect to avatar coordinate system
        tempMat = Matrix.CreateFromQuaternion(avatarRotation);

        // Set the corresponding matrix in the avatar using the translation table we specified
        this.ReplaceBoneMatrix(bone.EndJoint, tempMat, false, ref boneTransforms);
    }
    else if (bone.EndJoint == JointType.ElbowLeft || bone.EndJoint == JointType.WristLeft)
    {
        Matrix tempMat = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);

        if (bone.EndJoint == JointType.ElbowLeft)
        {
            // Add a small adjustment rotation to correct for the avatar skeleton shoulder/upper arm bones.
            // The dude should now be able to have arms correctly down at his sides when avateering
            Matrix adjustment = Matrix.CreateRotationZ(MathHelper.ToRadians(-15));  // -15 degree rotation around the local Kinect z axis for the upper arm bone.
            tempMat *= adjustment;
        }

        // Kinect = +Y along arm, +X down, +Z forward in body coordinate system
        // Avatar = +X along arm, +Y down, +Z backwards
        Quaternion kinectRotation = KinectHelper.DecomposeMatRot(tempMat);    // XYZ
        Quaternion avatarRotation = new Quaternion(kinectRotation.Y, -kinectRotation.Z, -kinectRotation.X, kinectRotation.W); // transform from Kinect to avatar coordinate system
        tempMat = Matrix.CreateFromQuaternion(avatarRotation);

        this.ReplaceBoneMatrix(bone.EndJoint, tempMat, false, ref boneTransforms);
    }
    else if (bone.EndJoint == JointType.HandLeft)
    {
        Matrix tempMat = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);

        // Add a small adjustment rotation to correct for the avatar skeleton wist/hand bone.
        // The dude should now have the palm of his hands toward his body when arms are straight down
        Matrix adjustment = Matrix.CreateRotationY(MathHelper.ToRadians(-90));  // -90 degree rotation around the local Kinect y axis for the wrist-hand bone.
        tempMat *= adjustment;

        // Kinect = +Y along arm, +X down, +Z forward in body coordinate system
        // Avatar = +X along arm, +Y down, +Z backwards
        Quaternion kinectRotation = KinectHelper.DecomposeMatRot(tempMat);    // XYZ
        Quaternion avatarRotation = new Quaternion(0.0f, 0.0f, -kinectRotation.Z, kinectRotation.W);
        tempMat = Matrix.CreateFromQuaternion(avatarRotation);

        this.ReplaceBoneMatrix(bone.EndJoint, tempMat, false, ref boneTransforms);
    }
    else if (bone.EndJoint == JointType.ElbowRight || bone.EndJoint == JointType.WristRight)
    {
        Matrix tempMat = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);

        if (bone.EndJoint == JointType.ElbowRight)
        {
            // Add a small adjustment rotation to correct for the avatar skeleton shoulder/upper arm bones.
            // The dude should now be able to have arms correctly down at his sides when avateering
            Matrix adjustment = Matrix.CreateRotationZ(MathHelper.ToRadians(15));  // 15 degree rotation around the local Kinect  z axis for the upper arm bone.
            tempMat *= adjustment;
        }

        // Kinect = +Y along arm, +X up, +Z forward in body coordinate system
        // Avatar = +X along arm, +Y back, +Z down
        Quaternion kinectRotation = KinectHelper.DecomposeMatRot(tempMat);    // XYZ
        Quaternion avatarRotation = new Quaternion(kinectRotation.Y, -kinectRotation.Z, -kinectRotation.X, kinectRotation.W); // transform from Kinect to avatar coordinate system
        tempMat = Matrix.CreateFromQuaternion(avatarRotation);

        this.ReplaceBoneMatrix(bone.EndJoint, tempMat, false, ref boneTransforms);
    }
    else if (bone.EndJoint == JointType.HandRight)
    {
        Matrix tempMat = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);

        // Add a small adjustment rotation to correct for the avatar skeleton wist/hand bone.
        // The dude should now have the palm of his hands toward his body when arms are straight down
        Matrix adjustment = Matrix.CreateRotationY(MathHelper.ToRadians(90));  // -90 degree rotation around the local Kinect y axis for the wrist-hand bone.
        tempMat *= adjustment;

        // Kinect = +Y along arm, +X up, +Z forward in body coordinate system
        // Avatar = +X along arm, +Y down, +Z forwards
        Quaternion kinectRotation = KinectHelper.DecomposeMatRot(tempMat);    // XYZ
        Quaternion avatarRotation = new Quaternion(kinectRotation.Y, -kinectRotation.X, kinectRotation.Z, kinectRotation.W); // transform from Kinect to avatar coordinate system
        tempMat = Matrix.CreateFromQuaternion(avatarRotation);

        this.ReplaceBoneMatrix(bone.EndJoint, tempMat, false, ref boneTransforms);
    }
    else if (bone.EndJoint == JointType.KneeLeft)
    {
        // Combine the two joint rotations from the hip and knee
        Matrix hipLeft = KinectHelper.Matrix4ToXNAMatrix(skeleton.BoneOrientations[JointType.HipLeft].HierarchicalRotation.Matrix);
        Matrix kneeLeft = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);
        Matrix combined = kneeLeft * hipLeft;

        this.SetLegMatrix(bone.EndJoint, combined, ref boneTransforms);
    }
    else if (bone.EndJoint == JointType.AnkleLeft || bone.EndJoint == JointType.AnkleRight)
    {
        Matrix tempMat = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);
        this.SetLegMatrix(bone.EndJoint, tempMat, ref boneTransforms);
    }
    else if (bone.EndJoint == JointType.KneeRight)
    {
        // Combine the two joint rotations from the hip and knee
        Matrix hipRight = KinectHelper.Matrix4ToXNAMatrix(skeleton.BoneOrientations[JointType.HipRight].HierarchicalRotation.Matrix);
        Matrix kneeRight = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);
        Matrix combined = kneeRight * hipRight;

        this.SetLegMatrix(bone.EndJoint, combined, ref boneTransforms);
    }
    else if (bone.EndJoint == JointType.FootLeft || bone.EndJoint == JointType.FootRight)
    {
        // Only set this if we actually have a good track on this and the parent
        if (skeleton.Joints[bone.EndJoint].TrackingState == JointTrackingState.Tracked && skeleton.Joints[skeleton.BoneOrientations[bone.EndJoint].StartJoint].TrackingState == JointTrackingState.Tracked)
        {
            Matrix tempMat = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);

            // Add a small adjustment rotation to correct for the avatar skeleton foot bones being defined pointing down at 45 degrees, not horizontal
            Matrix adjustment = Matrix.CreateRotationX(MathHelper.ToRadians(-45));
            tempMat *= adjustment;

            // Kinect = +Y along foot (fwd), +Z up, +X right in body coordinate system
            // Avatar = +X along foot (fwd), +Y up, +Z right
            Quaternion kinectRotation = KinectHelper.DecomposeMatRot(tempMat); // XYZ
            Quaternion avatarRotation = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f); // transform from Kinect to avatar coordinate system
            tempMat = Matrix.CreateFromQuaternion(avatarRotation);

            this.ReplaceBoneMatrix(bone.EndJoint, tempMat, false, ref boneTransforms);
        }
    }
}

有什么办法可以将化身保留在原点上吗?

身体的根部定义为:

if (bone.StartJoint == JointType.HipCenter && bone.EndJoint == JointType.HipCenter)
{
    // Unless in seated mode, the hip center is special - it is the root of the NuiSkeleton and describes the skeleton orientation in the world
    // (camera) coordinate system. All other bones/joint orientations in the hierarchy have hip center as one of their parents.
    // However, if in seated mode, the shoulder center then holds the skeleton orientation in the world (camera) coordinate system.
    bindRoot.Translation = Vector3.Zero;
    Matrix invBindRoot = Matrix.Invert(bindRoot);

    Matrix hipOrientation = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);

    // Here we create a rotation matrix for the hips from the inverse of the bind pose
    // for the pelvis rotation and the inverse of the bind pose for the root node (0) in the Dude model.
    // This multiplication effectively removes the initial 90 degree rotations set in the first two model nodes.
    Matrix pelvis = boneTransforms[1];
    pelvis.Translation = Vector3.Zero; // Ensure pure rotation as we explicitly set world translation from the Kinect camera below.
    Matrix invPelvis = Matrix.Invert(pelvis);

    Matrix combined = (invBindRoot * hipOrientation) * invPelvis;

    this.ReplaceBoneMatrix(JointType.HipCenter, combined, true, ref boneTransforms);
}

您应该能够忽略hipOrientation而忽略身体的旋转。 但是,如果要让化身在用户转身时转回,则必须检查身体的方向并相应地设置化身的方向。

if (bone.StartJoint == JointType.HipCenter && bone.EndJoint == JointType.HipCenter)
{
    bindRoot.Translation = Vector3.Zero;
    Matrix invBindRoot = Matrix.Invert(bindRoot);

    // Gets the orientation of the body
    Matrix hipOrientation = KinectHelper.Matrix4ToXNAMatrix(bone.HierarchicalRotation.Matrix);
    if (Vector3.DotProduct(hipOrientation.Forward, Vector3.Forward) > 0) // Checks if the body is forward or backward
        hipOrientation = Matrix.Identity; // Fix the avatar orientation to a specific forward position
    else
        hipOrientation = Matrix.CreateRotationX(Math.PI); // Fix the avatar orientation to a specific backward position

    Matrix pelvis = boneTransforms[1];
    pelvis.Translation = Vector3.Zero;
    Matrix invPelvis = Matrix.Invert(pelvis);

    Matrix combined = (invBindRoot * hipOrientation) * invPelvis;

    this.ReplaceBoneMatrix(JointType.HipCenter, combined, true, ref boneTransforms);
}

也许您还应该尝试删除该行:

pelvis.Translation = Vector3.Zero;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM