Browse Source

Merge pull request #1319 from KellyThomas/advanced-vectors

C# code samples for Advanced Vector Math
Max Hilbrunner 7 years ago
parent
commit
d2db7ecd6e
1 changed files with 253 additions and 24 deletions
  1. 253 24
      tutorials/math/vectors_advanced.rst

+ 253 - 24
tutorials/math/vectors_advanced.rst

@@ -16,10 +16,10 @@ popular belief) you can also use their math in 2D:
 
 
 Unit vectors that are perpendicular to a surface (so, they describe the
 Unit vectors that are perpendicular to a surface (so, they describe the
 orientation of the surface) are called **unit normal vectors**. Though,
 orientation of the surface) are called **unit normal vectors**. Though,
-usually they are just abbreviated as \*normals. Normals appear in
+usually they are just abbreviated as *normals*. Normals appear in
 planes, 3D geometry (to determine where each face or vertex is siding),
 planes, 3D geometry (to determine where each face or vertex is siding),
 etc. A **normal** *is* a **unit vector**, but it's called *normal*
 etc. A **normal** *is* a **unit vector**, but it's called *normal*
-because of its usage. (Just like we call Origin to (0,0)!).
+because of its usage. (Just like we call (0,0) the Origin!).
 
 
 It's as simple as it looks. The plane passes by the origin and the
 It's as simple as it looks. The plane passes by the origin and the
 surface of it is perpendicular to the unit vector (or *normal*). The
 surface of it is perpendicular to the unit vector (or *normal*). The
@@ -37,10 +37,15 @@ The dot product between a **unit vector** and any **point in space**
 (yes, this time we do dot product between vector and position), returns
 (yes, this time we do dot product between vector and position), returns
 the **distance from the point to the plane**:
 the **distance from the point to the plane**:
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     var distance = normal.dot(point)
     var distance = normal.dot(point)
 
 
+ .. code-tab:: csharp
+
+    var distance = normal.Dot(point);
+
 But not just the absolute distance, if the point is in the negative half
 But not just the absolute distance, if the point is in the negative half
 space the distance will be negative, too:
 space the distance will be negative, too:
 
 
@@ -74,43 +79,69 @@ for both. It's the same as before, but D is the distance from the origin
 to the plane, travelling in N direction. As an example, imagine you want
 to the plane, travelling in N direction. As an example, imagine you want
 to reach a point in the plane, you will just do:
 to reach a point in the plane, you will just do:
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     var point_in_plane = N*D
     var point_in_plane = N*D
 
 
+ .. code-tab:: csharp
+
+    var pointInPlane = N * D;
+
 This will stretch (resize) the normal vector and make it touch the
 This will stretch (resize) the normal vector and make it touch the
 plane. This math might seem confusing, but it's actually much simpler
 plane. This math might seem confusing, but it's actually much simpler
 than it seems. If we want to tell, again, the distance from the point to
 than it seems. If we want to tell, again, the distance from the point to
 the plane, we do the same but adjusting for distance:
 the plane, we do the same but adjusting for distance:
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     var distance = N.dot(point) - D
     var distance = N.dot(point) - D
 
 
+ .. code-tab:: csharp
+
+    var distance = N.Dot(point) - D;
+
 The same thing, using a built-in function:
 The same thing, using a built-in function:
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     var distance = plane.distance_to(point)
     var distance = plane.distance_to(point)
 
 
+ .. code-tab:: csharp
+
+    var distance = plane.DistanceTo(point);
+
 This will, again, return either a positive or negative distance.
 This will, again, return either a positive or negative distance.
 
 
 Flipping the polarity of the plane is also very simple, just negate both
 Flipping the polarity of the plane is also very simple, just negate both
 N and D. This will result in a plane in the same position, but with
 N and D. This will result in a plane in the same position, but with
 inverted negative and positive half spaces:
 inverted negative and positive half spaces:
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     N = -N
     N = -N
     D = -D
     D = -D
 
 
+ .. code-tab:: csharp
+
+    N = -N;
+    D = -D;
+
 Of course, Godot also implements this operator in :ref:`Plane <class_Plane>`,
 Of course, Godot also implements this operator in :ref:`Plane <class_Plane>`,
 so doing:
 so doing:
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     var inverted_plane = -plane
     var inverted_plane = -plane
 
 
+ .. code-tab:: csharp
+
+    var invertedPlane = -plane;
+
 Will work as expected.
 Will work as expected.
 
 
 So, remember, a plane is just that and its main practical use is
 So, remember, a plane is just that and its main practical use is
@@ -129,18 +160,25 @@ In the case of a normal and a point, most of the work is done, as the
 normal is already computed, so just calculate D from the dot product of
 normal is already computed, so just calculate D from the dot product of
 the normal and the point.
 the normal and the point.
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     var N = normal
     var N = normal
     var D = normal.dot(point)
     var D = normal.dot(point)
 
 
+ .. code-tab:: csharp
+
+    var N = normal;
+    var D = normal.Dot(point);
+
 For two points in space, there are actually two planes that pass through
 For two points in space, there are actually two planes that pass through
 them, sharing the same space but with normal pointing to the opposite
 them, sharing the same space but with normal pointing to the opposite
 directions. To compute the normal from the two points, the direction
 directions. To compute the normal from the two points, the direction
 vector must be obtained first, and then it needs to be rotated 90°
 vector must be obtained first, and then it needs to be rotated 90°
 degrees to either side:
 degrees to either side:
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     # calculate vector from a to b
     # calculate vector from a to b
     var dvec = (point_b - point_a).normalized()
     var dvec = (point_b - point_a).normalized()
@@ -150,16 +188,34 @@ degrees to either side:
     # var normal = Vector2(-dvec.y, dvec.x)
     # var normal = Vector2(-dvec.y, dvec.x)
     # depending the desired side of the normal
     # depending the desired side of the normal
 
 
+ .. code-tab:: csharp
+
+    // calculate vector from a to b
+    var dvec = (pointB - pointA).Normalized();
+    // rotate 90 degrees
+    var normal = new Vector2(dvec.y, -dvec.x);
+    // or alternatively
+    // var normal = new Vector2(-dvec.y, dvec.x);
+    // depending the desired side of the normal
+
 The rest is the same as the previous example, either point_a or
 The rest is the same as the previous example, either point_a or
 point_b will work since they are in the same plane:
 point_b will work since they are in the same plane:
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     var N = normal
     var N = normal
     var D = normal.dot(point_a)
     var D = normal.dot(point_a)
     # this works the same
     # this works the same
     # var D = normal.dot(point_b)
     # var D = normal.dot(point_b)
 
 
+ .. code-tab:: csharp
+
+    var N = normal;
+    var D = normal.Dot(pointA);
+    // this works the same
+    // var D = normal.Dot(pointB);
+
 Doing the same in 3D is a little more complex and will be explained
 Doing the same in 3D is a little more complex and will be explained
 further down.
 further down.
 
 
@@ -183,15 +239,29 @@ can't, then the point is inside.
 
 
 Code should be something like this:
 Code should be something like this:
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     var inside = true
     var inside = true
     for p in planes:
     for p in planes:
         # check if distance to plane is positive
         # check if distance to plane is positive
-        if (N.dot(point) - D > 0):
+        if (p.distance_to(point) > 0):
             inside = false
             inside = false
             break # with one that fails, it's enough
             break # with one that fails, it's enough
 
 
+ .. code-tab:: csharp
+
+    var inside = true;
+    foreach (var p in planes)
+    {
+        // check if distance to plane is positive
+        if (p.DistanceTo(point) > 0)
+        {
+            inside = false;
+            break; // with one that fails, it's enough
+        }
+    }
+ 
 Pretty cool, huh? But this gets much better! With a little more effort,
 Pretty cool, huh? But this gets much better! With a little more effort,
 similar logic will let us know when two convex polygons are overlapping
 similar logic will let us know when two convex polygons are overlapping
 too. This is called the Separating Axis Theorem (or SAT) and most
 too. This is called the Separating Axis Theorem (or SAT) and most
@@ -199,7 +269,7 @@ physics engines use this to detect collision.
 
 
 The idea is really simple! With a point, just checking if a plane
 The idea is really simple! With a point, just checking if a plane
 returns a positive distance is enough to tell if the point is outside.
 returns a positive distance is enough to tell if the point is outside.
-With another polygon, we must find a plane where *all* *the* ***other***
+With another polygon, we must find a plane where *all* *the* *other*
 *polygon* *points* return a positive distance to it. This check is
 *polygon* *points* return a positive distance to it. This check is
 performed with the planes of A against the points of B, and then with
 performed with the planes of A against the points of B, and then with
 the planes of B against the points of A:
 the planes of B against the points of A:
@@ -208,7 +278,8 @@ the planes of B against the points of A:
 
 
 Code should be something like this:
 Code should be something like this:
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     var overlapping = true
     var overlapping = true
 
 
@@ -242,6 +313,60 @@ Code should be something like this:
     if (overlapping):
     if (overlapping):
         print("Polygons Collided!")
         print("Polygons Collided!")
 
 
+ .. code-tab:: csharp
+
+        var overlapping = true;
+
+        foreach (Plane plane in planesOfA)
+        {
+            var allOut = true;
+            foreach (Vector3 point in pointsOfB)
+            {
+                if (plane.DistanceTo(point) < 0)
+                {
+                    allOut = false;
+                    break;
+                }
+            }
+            
+            if (allOut)
+            {
+                // a separating plane was found
+                // do not continue testing
+                overlapping = false;
+                break;
+            }
+        }
+
+        if (overlapping)
+        {
+            // only do this check if no separating plane
+            // was found in planes of A
+            foreach (Plane plane in planesOfB)
+            {
+                var allOut = true;
+                foreach (Vector3 point in pointsOfA)
+                {
+                    if (plane.DistanceTo(point) < 0)
+                    {
+                        allOut = false;
+                        break;
+                    }
+                }
+                
+                if (allOut)
+                {
+                    overlapping = false;
+                    break;
+                }
+            }
+        }
+
+        if (overlapping)
+        {
+            GD.Print("Polygons Collided!");
+        }
+
 As you can see, planes are quite useful, and this is the tip of the
 As you can see, planes are quite useful, and this is the tip of the
 iceberg. You might be wondering what happens with non convex polygons.
 iceberg. You might be wondering what happens with non convex polygons.
 This is usually just handled by splitting the concave polygon into
 This is usually just handled by splitting the concave polygon into
@@ -285,7 +410,8 @@ edges of polygon B
 
 
 So the final algorithm is something like:
 So the final algorithm is something like:
 
 
-::
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
 
     var overlapping = true
     var overlapping = true
 
 
@@ -333,20 +459,16 @@ So the final algorithm is something like:
 
 
                 for v in points_of_A:
                 for v in points_of_A:
                     var d = n.dot(v)
                     var d = n.dot(v)
-                    if (d > max_A):
-                        max_A = d
-                    if (d < min_A):
-                        min_A = d
+                    max_A = max(max_A, d)
+                    min_A = min(min_A, d)
 
 
                 var max_B = -1e20 # tiny number
                 var max_B = -1e20 # tiny number
                 var min_B = 1e20 # huge number
                 var min_B = 1e20 # huge number
 
 
                 for v in points_of_B:
                 for v in points_of_B:
                     var d = n.dot(v)
                     var d = n.dot(v)
-                    if (d > max_B):
-                        max_B = d
-                    if (d < min_B):
-                        min_B = d
+                    max_B = max(max_B, d)
+                    min_B = min(min_B, d)
 
 
                 if (min_A > max_B or min_B > max_A):
                 if (min_A > max_B or min_B > max_A):
                     # not overlapping!
                     # not overlapping!
@@ -358,3 +480,110 @@ So the final algorithm is something like:
 
 
     if (overlapping):
     if (overlapping):
        print("Polygons collided!")
        print("Polygons collided!")
+
+ .. code-tab:: csharp
+ 
+    var overlapping = true;
+
+    foreach (Plane plane in planesOfA)
+    {
+        var allOut = true;
+        foreach (Vector3 point in pointsOfB)
+        {
+            if (plane.DistanceTo(point) < 0)
+            {
+                allOut = false;
+                break;
+            }
+        }
+
+        if (allOut)
+        {
+            // a separating plane was found
+            // do not continue testing
+            overlapping = false;
+            break;
+        }
+    }
+
+    if (overlapping)
+    {
+        // only do this check if no separating plane
+        // was found in planes of A
+        foreach (Plane plane in planesOfB)
+        {
+            var allOut = true;
+            foreach (Vector3 point in pointsOfA)
+            {
+                if (plane.DistanceTo(point) < 0)
+                {
+                    allOut = false;
+                    break;
+                }
+            }
+            
+            if (allOut)
+            {
+                overlapping = false;
+                break;
+            }
+        }
+    }
+
+    if (overlapping)
+    {
+        foreach (Vector3 edgeA in edgesOfA)
+        {
+            foreach (Vector3 edgeB in edgesOfB)
+            {
+                var normal = edgeA.Cross(edgeB);
+                if (normal.Length() == 0)
+                {
+                    continue;
+                }
+
+                var maxA = float.MinValue; // tiny number
+                var minA = float.MaxValue; // huge number
+
+                // we are using the dot product directly
+                // so we can map a maximum and minimum range
+                // for each polygon, then check if they
+                // overlap.
+
+                foreach (Vector3 point in pointsOfA)
+                {
+                    var distance = normal.Dot(point);
+                    maxA = Mathf.Max(maxA, distance);
+                    minA = Mathf.Min(minA, distance);
+                }
+
+                var maxB = float.MinValue; // tiny number
+                var minB = float.MaxValue; // huge number
+
+                foreach (Vector3 point in pointsOfB)
+                {
+                    var distance = normal.Dot(point);
+                    maxB = Mathf.Max(maxB, distance);
+                    minB = Mathf.Min(minB, distance);
+                }
+
+                if (minA > maxB || minB > maxA)
+                {
+                    // not overlapping!
+                    overlapping = false;
+                    break;
+                }
+            }
+
+            if (!overlapping)
+            {
+                break;
+            }
+
+        }
+    }
+
+    if (overlapping)
+    {
+        GD.Print("Polygons Collided!");
+    }