Merge pull request #95790 from aaronfranke/rect-aabb-support

Simplify Rect2/AABB `get_support` function
This commit is contained in:
Rémi Verschelde 2024-08-22 00:10:39 +02:00
commit 39b77ea04e
No known key found for this signature in database
GPG Key ID: C3336907360768E1
11 changed files with 97 additions and 35 deletions

View File

@ -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 AABB::get_support(const Vector3 &p_direction) const {
Vector3 half_extents = size * 0.5f; Vector3 support = position;
Vector3 ofs = position + half_extents; if (p_direction.x > 0.0f) {
support.x += size.x;
return Vector3( }
(p_normal.x > 0) ? half_extents.x : -half_extents.x, if (p_direction.y > 0.0f) {
(p_normal.y > 0) ? half_extents.y : -half_extents.y, support.y += size.y;
(p_normal.z > 0) ? half_extents.z : -half_extents.z) + }
ofs; 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 {

View File

@ -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 get_support(const Vector2 &p_direction) const {
Vector2 half_extents = size * 0.5f; Vector2 support = position;
Vector2 ofs = position + half_extents; if (p_direction.x > 0.0f) {
return Vector2( support.x += size.x;
(p_normal.x > 0) ? -half_extents.x : half_extents.x, }
(p_normal.y > 0) ? -half_extents.y : half_extents.y) + if (p_direction.y > 0.0f) {
ofs; 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 {

View File

@ -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());

View File

@ -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>

View File

@ -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" />

View File

@ -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;

View File

@ -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 support = _position;
Vector3 ofs = _position + halfExtents; if (dir.X > 0.0f)
{
return ofs + new Vector3( support.X += _size.X;
dir.X > 0f ? halfExtents.X : -halfExtents.X, }
dir.Y > 0f ? halfExtents.Y : -halfExtents.Y, if (dir.Y > 0.0f)
dir.Z > 0f ? halfExtents.Z : -halfExtents.Z); {
support.Y += _size.Y;
}
if (dir.Z > 0.0f)
{
support.Z += _size.Z;
}
return support;
} }
/// <summary> /// <summary>

View File

@ -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.

View File

@ -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;

View File

@ -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)), aabb.get_support(Vector3()) == Vector3(-1.5, 2, -2.5),
"get_support() should return the expected value with a null vector."); "get_support() should return the AABB position when given a zero vector.");
} }
TEST_CASE("[AABB] Grow") { TEST_CASE("[AABB] Grow") {

View File

@ -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)),