The Kinect SDK provides a property SkeletonFrame.FloorClipPlane that describes the orientation of the floor plane relative to the camera. MSDN contains slightly more information in the Coordinate Spaces page for Kinect.
I want to determine a matrix that transforms the camera coordinate space to a 'world space'. In this world space the origin would correspond be a projection of the camera position on the floor, ie straight below the camera.
- The X axis is to the sides of the camera, but rotated to be parallel to the floor, compensating for pitch
- The Y axis is straight up from the ground to the Kinect, compensating for yaw
- The Z axis is straight forward from the camera/origin, but rotated to be parallel to the floor, compensating for tilt
The 2 steps in the transformation would be
- Translate from the camera position to the ground
- Rotate around the origin while keeping orientation
Unfortunately my linear algebra is rusty and always has been.
Solution update:
I adapted the solution below to create the following method that creates a transformation matrix based on the floor normal and camera height:
Matrix CameraTransform(Vector3 normal, float scalar)
{
// Note the first three coefficients of the plane equation are the normal
Vector3 yNew = new Vector3(normal.X, normal.Y, normal.Z);
Vector3 zNew = new Vector3(0, 1, -normal.Y / normal.Z);
zNew.Normalize();
Vector3 xNew = Vector3.Cross(yNew, zNew);
// assumes column vectors, multiplied on the right
Matrix rotMatrix = new Matrix(
xNew.X, yNew.X, zNew.X, 0,
xNew.Y, yNew.Y, zNew.Y, 0,
xNew.Z, yNew.Z, zNew.Z, 0,
0, 0, 0, 1);
Matrix translationMatrix = Matrix.CreateTranslation(0, scalar, 0);
return rotMatrix * translationMatrix;
}