Browse Source

Simplify and fix Rect2/AABB get_support function

Aaron Franke 1 year ago
parent
commit
7db24a9ad5

+ 13 - 10
core/math/aabb.h

@@ -85,7 +85,7 @@ struct [[nodiscard]] AABB {
 	bool intersects_plane(const Plane &p_plane) const;
 	bool intersects_plane(const Plane &p_plane) const;
 
 
 	_FORCE_INLINE_ bool has_point(const Vector3 &p_point) const;
 	_FORCE_INLINE_ bool has_point(const Vector3 &p_point) const;
-	_FORCE_INLINE_ Vector3 get_support(const Vector3 &p_normal) const;
+	_FORCE_INLINE_ Vector3 get_support(const Vector3 &p_direction) const;
 
 
 	Vector3 get_longest_axis() const;
 	Vector3 get_longest_axis() const;
 	int get_longest_axis_index() const;
 	int get_longest_axis_index() const;
@@ -212,15 +212,18 @@ inline bool AABB::encloses(const AABB &p_aabb) const {
 			(src_max.z >= dst_max.z));
 			(src_max.z >= dst_max.z));
 }
 }
 
 
-Vector3 AABB::get_support(const Vector3 &p_normal) const {
-	Vector3 half_extents = size * 0.5f;
-	Vector3 ofs = position + half_extents;
-
-	return Vector3(
-				   (p_normal.x > 0) ? half_extents.x : -half_extents.x,
-				   (p_normal.y > 0) ? half_extents.y : -half_extents.y,
-				   (p_normal.z > 0) ? half_extents.z : -half_extents.z) +
-			ofs;
+Vector3 AABB::get_support(const Vector3 &p_direction) const {
+	Vector3 support = position;
+	if (p_direction.x > 0.0f) {
+		support.x += size.x;
+	}
+	if (p_direction.y > 0.0f) {
+		support.y += size.y;
+	}
+	if (p_direction.z > 0.0f) {
+		support.z += size.z;
+	}
+	return support;
 }
 }
 
 
 Vector3 AABB::get_endpoint(int p_point) const {
 Vector3 AABB::get_endpoint(int p_point) const {

+ 9 - 7
core/math/rect2.h

@@ -285,13 +285,15 @@ struct [[nodiscard]] Rect2 {
 		return Rect2(position.round(), size.round());
 		return Rect2(position.round(), size.round());
 	}
 	}
 
 
-	Vector2 get_support(const Vector2 &p_normal) const {
-		Vector2 half_extents = size * 0.5f;
-		Vector2 ofs = position + half_extents;
-		return Vector2(
-					   (p_normal.x > 0) ? -half_extents.x : half_extents.x,
-					   (p_normal.y > 0) ? -half_extents.y : half_extents.y) +
-				ofs;
+	Vector2 get_support(const Vector2 &p_direction) const {
+		Vector2 support = position;
+		if (p_direction.x > 0.0f) {
+			support.x += size.x;
+		}
+		if (p_direction.y > 0.0f) {
+			support.y += size.y;
+		}
+		return support;
 	}
 	}
 
 
 	_FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const {
 	_FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const {

+ 2 - 1
core/variant/variant_call.cpp

@@ -1849,6 +1849,7 @@ static void _register_variant_builtin_methods_math() {
 	bind_method(Rect2, intersection, sarray("b"), varray());
 	bind_method(Rect2, intersection, sarray("b"), varray());
 	bind_method(Rect2, merge, sarray("b"), varray());
 	bind_method(Rect2, merge, sarray("b"), varray());
 	bind_method(Rect2, expand, sarray("to"), varray());
 	bind_method(Rect2, expand, sarray("to"), varray());
+	bind_method(Rect2, get_support, sarray("direction"), varray());
 	bind_method(Rect2, grow, sarray("amount"), varray());
 	bind_method(Rect2, grow, sarray("amount"), varray());
 	bind_methodv(Rect2, grow_side, &Rect2::grow_side_bind, sarray("side", "amount"), varray());
 	bind_methodv(Rect2, grow_side, &Rect2::grow_side_bind, sarray("side", "amount"), varray());
 	bind_method(Rect2, grow_individual, sarray("left", "top", "right", "bottom"), varray());
 	bind_method(Rect2, grow_individual, sarray("left", "top", "right", "bottom"), varray());
@@ -2185,7 +2186,7 @@ static void _register_variant_builtin_methods_misc() {
 	bind_method(AABB, merge, sarray("with"), varray());
 	bind_method(AABB, merge, sarray("with"), varray());
 	bind_method(AABB, expand, sarray("to_point"), varray());
 	bind_method(AABB, expand, sarray("to_point"), varray());
 	bind_method(AABB, grow, sarray("by"), varray());
 	bind_method(AABB, grow, sarray("by"), varray());
-	bind_method(AABB, get_support, sarray("dir"), varray());
+	bind_method(AABB, get_support, sarray("direction"), varray());
 	bind_method(AABB, get_longest_axis, sarray(), varray());
 	bind_method(AABB, get_longest_axis, sarray(), varray());
 	bind_method(AABB, get_longest_axis_index, sarray(), varray());
 	bind_method(AABB, get_longest_axis_index, sarray(), varray());
 	bind_method(AABB, get_longest_axis_size, sarray(), varray());
 	bind_method(AABB, get_longest_axis_size, sarray(), varray());

+ 1 - 1
doc/classes/AABB.xml

@@ -206,7 +206,7 @@
 		</method>
 		</method>
 		<method name="get_support" qualifiers="const">
 		<method name="get_support" qualifiers="const">
 			<return type="Vector3" />
 			<return type="Vector3" />
-			<param index="0" name="dir" type="Vector3" />
+			<param index="0" name="direction" type="Vector3" />
 			<description>
 			<description>
 				Returns the vertex's position of this bounding box that's the farthest in the given direction. This point is commonly known as the support point in collision detection algorithms.
 				Returns the vertex's position of this bounding box that's the farthest in the given direction. This point is commonly known as the support point in collision detection algorithms.
 			</description>
 			</description>

+ 7 - 0
doc/classes/Rect2.xml

@@ -112,6 +112,13 @@
 				Returns the center point of the rectangle. This is the same as [code]position + (size / 2.0)[/code].
 				Returns the center point of the rectangle. This is the same as [code]position + (size / 2.0)[/code].
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="get_support" qualifiers="const">
+			<return type="Vector2" />
+			<param index="0" name="direction" type="Vector2" />
+			<description>
+				Returns the vertex's position of this rect that's the farthest in the given direction. This point is commonly known as the support point in collision detection algorithms.
+			</description>
+		</method>
 		<method name="grow" qualifiers="const">
 		<method name="grow" qualifiers="const">
 			<return type="Rect2" />
 			<return type="Rect2" />
 			<param index="0" name="amount" type="float" />
 			<param index="0" name="amount" type="float" />

+ 1 - 1
drivers/gles3/rasterizer_canvas_gles3.cpp

@@ -1734,7 +1734,7 @@ void RasterizerCanvasGLES3::light_update_directional_shadow(RID p_rid, int p_sha
 
 
 	Vector2 center = p_clip_rect.get_center();
 	Vector2 center = p_clip_rect.get_center();
 
 
-	float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center));
+	float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(-light_dir)) - light_dir.dot(center));
 
 
 	Vector2 from_pos = center - light_dir * (to_edge_distance + p_cull_distance);
 	Vector2 from_pos = center - light_dir * (to_edge_distance + p_cull_distance);
 	float distance = to_edge_distance * 2.0 + p_cull_distance;
 	float distance = to_edge_distance * 2.0 + p_cull_distance;

+ 14 - 7
modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs

@@ -314,13 +314,20 @@ namespace Godot
         /// <returns>A vector representing the support.</returns>
         /// <returns>A vector representing the support.</returns>
         public readonly Vector3 GetSupport(Vector3 dir)
         public readonly Vector3 GetSupport(Vector3 dir)
         {
         {
-            Vector3 halfExtents = _size * 0.5f;
-            Vector3 ofs = _position + halfExtents;
-
-            return ofs + new Vector3(
-                dir.X > 0f ? halfExtents.X : -halfExtents.X,
-                dir.Y > 0f ? halfExtents.Y : -halfExtents.Y,
-                dir.Z > 0f ? halfExtents.Z : -halfExtents.Z);
+            Vector3 support = _position;
+            if (dir.X > 0.0f)
+            {
+                support.X += _size.X;
+            }
+            if (dir.Y > 0.0f)
+            {
+                support.Y += _size.Y;
+            }
+            if (dir.Z > 0.0f)
+            {
+                support.Z += _size.Z;
+            }
+            return support;
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 20 - 0
modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs

@@ -171,6 +171,26 @@ namespace Godot
             return _position + (_size * 0.5f);
             return _position + (_size * 0.5f);
         }
         }
 
 
+        /// <summary>
+        /// Returns the support point in a given direction.
+        /// This is useful for collision detection algorithms.
+        /// </summary>
+        /// <param name="direction">The direction to find support for.</param>
+        /// <returns>A vector representing the support.</returns>
+        public readonly Vector2 GetSupport(Vector2 direction)
+        {
+            Vector2 support = _position;
+            if (direction.X > 0.0f)
+            {
+                support.X += _size.X;
+            }
+            if (direction.Y > 0.0f)
+            {
+                support.Y += _size.Y;
+            }
+            return support;
+        }
+
         /// <summary>
         /// <summary>
         /// Returns a copy of the <see cref="Rect2"/> grown by the specified amount
         /// Returns a copy of the <see cref="Rect2"/> grown by the specified amount
         /// on all sides.
         /// on all sides.

+ 1 - 1
servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp

@@ -1823,7 +1823,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh
 
 
 	Vector2 center = p_clip_rect.get_center();
 	Vector2 center = p_clip_rect.get_center();
 
 
-	float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center));
+	float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(-light_dir)) - light_dir.dot(center));
 
 
 	Vector2 from_pos = center - light_dir * (to_edge_distance + p_cull_distance);
 	Vector2 from_pos = center - light_dir * (to_edge_distance + p_cull_distance);
 	float distance = to_edge_distance * 2.0 + p_cull_distance;
 	float distance = to_edge_distance * 2.0 + p_cull_distance;

+ 7 - 7
tests/core/math/test_aabb.h

@@ -377,23 +377,23 @@ TEST_CASE("[AABB] Get longest/shortest axis") {
 TEST_CASE("[AABB] Get support") {
 TEST_CASE("[AABB] Get support") {
 	const AABB aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6));
 	const AABB aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6));
 	CHECK_MESSAGE(
 	CHECK_MESSAGE(
-			aabb.get_support(Vector3(1, 0, 0)).is_equal_approx(Vector3(2.5, 2, -2.5)),
+			aabb.get_support(Vector3(1, 0, 0)) == Vector3(2.5, 2, -2.5),
 			"get_support() should return the expected value.");
 			"get_support() should return the expected value.");
 	CHECK_MESSAGE(
 	CHECK_MESSAGE(
-			aabb.get_support(Vector3(0.5, 1, 0)).is_equal_approx(Vector3(2.5, 7, -2.5)),
+			aabb.get_support(Vector3(0.5, 1, 1)) == Vector3(2.5, 7, 3.5),
 			"get_support() should return the expected value.");
 			"get_support() should return the expected value.");
 	CHECK_MESSAGE(
 	CHECK_MESSAGE(
-			aabb.get_support(Vector3(0.5, 1, -400)).is_equal_approx(Vector3(2.5, 7, -2.5)),
+			aabb.get_support(Vector3(0.5, 1, -400)) == Vector3(2.5, 7, -2.5),
 			"get_support() should return the expected value.");
 			"get_support() should return the expected value.");
 	CHECK_MESSAGE(
 	CHECK_MESSAGE(
-			aabb.get_support(Vector3(0, -1, 0)).is_equal_approx(Vector3(-1.5, 2, -2.5)),
+			aabb.get_support(Vector3(0, -1, 0)) == Vector3(-1.5, 2, -2.5),
 			"get_support() should return the expected value.");
 			"get_support() should return the expected value.");
 	CHECK_MESSAGE(
 	CHECK_MESSAGE(
-			aabb.get_support(Vector3(0, -0.1, 0)).is_equal_approx(Vector3(-1.5, 2, -2.5)),
+			aabb.get_support(Vector3(0, -0.1, 0)) == Vector3(-1.5, 2, -2.5),
 			"get_support() should return the expected value.");
 			"get_support() should return the expected value.");
 	CHECK_MESSAGE(
 	CHECK_MESSAGE(
-			aabb.get_support(Vector3()).is_equal_approx(Vector3(-1.5, 2, -2.5)),
-			"get_support() should return the expected value with a null vector.");
+			aabb.get_support(Vector3()) == Vector3(-1.5, 2, -2.5),
+			"get_support() should return the AABB position when given a zero vector.");
 }
 }
 
 
 TEST_CASE("[AABB] Grow") {
 TEST_CASE("[AABB] Grow") {

+ 22 - 0
tests/core/math/test_rect2.h

@@ -180,6 +180,28 @@ TEST_CASE("[Rect2] Expanding") {
 			"expand() with non-contained Vector2 should return the expected result.");
 			"expand() with non-contained Vector2 should return the expected result.");
 }
 }
 
 
+TEST_CASE("[Rect2] Get support") {
+	const Rect2 rect = Rect2(Vector2(-1.5, 2), Vector2(4, 5));
+	CHECK_MESSAGE(
+			rect.get_support(Vector2(1, 0)) == Vector2(2.5, 2),
+			"get_support() should return the expected value.");
+	CHECK_MESSAGE(
+			rect.get_support(Vector2(0.5, 1)) == Vector2(2.5, 7),
+			"get_support() should return the expected value.");
+	CHECK_MESSAGE(
+			rect.get_support(Vector2(0.5, 1)) == Vector2(2.5, 7),
+			"get_support() should return the expected value.");
+	CHECK_MESSAGE(
+			rect.get_support(Vector2(0, -1)) == Vector2(-1.5, 2),
+			"get_support() should return the expected value.");
+	CHECK_MESSAGE(
+			rect.get_support(Vector2(0, -0.1)) == Vector2(-1.5, 2),
+			"get_support() should return the expected value.");
+	CHECK_MESSAGE(
+			rect.get_support(Vector2()) == Vector2(-1.5, 2),
+			"get_support() should return the Rect2 position when given a zero vector.");
+}
+
 TEST_CASE("[Rect2] Growing") {
 TEST_CASE("[Rect2] Growing") {
 	CHECK_MESSAGE(
 	CHECK_MESSAGE(
 			Rect2(0, 100, 1280, 720).grow(100).is_equal_approx(Rect2(-100, 0, 1480, 920)),
 			Rect2(0, 100, 1280, 720).grow(100).is_equal_approx(Rect2(-100, 0, 1480, 920)),