[Math] Vector3 Project and Unproject
authorFraser Waters <frassle@gmail.com>
Sat, 14 Feb 2015 18:46:03 +0000 (18:46 +0000)
committerFraser Waters <frassle@gmail.com>
Sat, 14 Feb 2015 19:05:59 +0000 (19:05 +0000)
Add methods to Vector3 to project to and from screen space.

Source/OpenTK/Math/Vector3.cs

index 8a09665..79cabb4 100644 (file)
@@ -1222,6 +1222,120 @@ namespace OpenTK
 
         #endregion
 
+        #region Project
+
+        /// <summary>
+        /// Projects a vector from object space into screen space.
+        /// </summary>
+        /// <param name="vector">The vector to project.</param>
+        /// <param name="x">The X coordinate of the viewport.</param>
+        /// <param name="y">The Y coordinate of the viewport.</param>
+        /// <param name="width">The width of the viewport.</param>
+        /// <param name="height">The height of the viewport.</param>
+        /// <param name="minZ">The minimum depth of the viewport.</param>
+        /// <param name="maxZ">The maximum depth of the viewport.</param>
+        /// <param name="worldViewProjection">The world-view-projection matrix.</param>
+        /// <returns>The vector in screen space.</returns>
+        /// <remarks>
+        /// To project to normalized device coordinates (NDC) use the following parameters:
+        /// Project(vector, -1, -1, 2, 2, -1, 1, worldViewProjection).
+        /// </remarks>
+        public static Vector3 Project(Vector3 vector, float x, float y, float width, float height, float minZ, float maxZ, Matrix4 worldViewProjection)
+        {
+            Vector4 result;
+
+            result.X = 
+                vector.X * worldViewProjection.M11 + 
+                vector.Y * worldViewProjection.M21 + 
+                vector.Z * worldViewProjection.M31 + 
+                worldViewProjection.M41;
+
+            result.Y =
+                vector.X * worldViewProjection.M12 +
+                vector.Y * worldViewProjection.M22 +
+                vector.Z * worldViewProjection.M32 +
+                worldViewProjection.M42;
+
+            result.Z =
+                vector.X * worldViewProjection.M13 +
+                vector.Y * worldViewProjection.M23 +
+                vector.Z * worldViewProjection.M33 +
+                worldViewProjection.M43;
+
+            result.W =
+                vector.X * worldViewProjection.M14 +
+                vector.Y * worldViewProjection.M24 +
+                vector.Z * worldViewProjection.M34 +
+                worldViewProjection.M44;
+
+            result /= result.W;
+
+            result.X = x + (width * ((result.X + 1.0f) / 2.0f));
+            result.Y = y + (height * ((result.Y + 1.0f) / 2.0f));
+            result.Z = minZ + ((maxZ - minZ) * ((result.Z + 1.0f) / 2.0f));
+
+            return new Vector3(result.X, result.Y, result.Z);
+        }
+
+        #endregion
+
+        #region Unproject
+
+        /// <summary>
+        /// Projects a vector from screen space into object space.
+        /// </summary>
+        /// <param name="vector">The vector to project.</param>
+        /// <param name="x">The X coordinate of the viewport.</param>
+        /// <param name="y">The Y coordinate of the viewport.</param>
+        /// <param name="width">The width of the viewport.</param>
+        /// <param name="height">The height of the viewport.</param>
+        /// <param name="minZ">The minimum depth of the viewport.</param>
+        /// <param name="maxZ">The maximum depth of the viewport.</param>
+        /// <param name="worldViewProjection">The inverse of the world-view-projection matrix.</param>
+        /// <returns>The vector in object space.</returns>
+        /// <remarks>
+        /// To project from normalized device coordinates (NDC) use the following parameters:
+        /// Project(vector, -1, -1, 2, 2, -1, 1, inverseWorldViewProjection).
+        /// </remarks>
+        public static Vector3 Unproject(Vector3 vector, float x, float y, float width, float height, float minZ, float maxZ, Matrix4 inverseWorldViewProjection)
+        {
+            Vector4 result;
+
+            result.X = ((((vector.X - x) / width) * 2.0f) - 1.0f);
+            result.Y = ((((vector.Y - y) / height) * 2.0f) - 1.0f);
+            result.Z = (((vector.Z / (maxZ - minZ)) * 2.0f) - 1.0f);
+
+            result.X =
+                result.X * inverseWorldViewProjection.M11 +
+                result.Y * inverseWorldViewProjection.M21 +
+                result.Z * inverseWorldViewProjection.M31 +
+                inverseWorldViewProjection.M41;
+
+            result.Y =
+                result.X * inverseWorldViewProjection.M12 +
+                result.Y * inverseWorldViewProjection.M22 +
+                result.Z * inverseWorldViewProjection.M32 +
+                inverseWorldViewProjection.M42;
+
+            result.Z =
+                result.X * inverseWorldViewProjection.M13 +
+                result.Y * inverseWorldViewProjection.M23 +
+                result.Z * inverseWorldViewProjection.M33 +
+                inverseWorldViewProjection.M43;
+
+            result.W =
+                result.X * inverseWorldViewProjection.M14 +
+                result.Y * inverseWorldViewProjection.M24 +
+                result.Z * inverseWorldViewProjection.M34 +
+                inverseWorldViewProjection.M44;
+
+            result /= result.W;
+
+            return new Vector3(result.X, result.Y, result.Z);
+        }
+
+        #endregion
+
         #endregion
 
         #region Swizzle