Skip to content

Commit 4f17a74

Browse files
committedNov 29, 2024·
polygons_get_closest_point_info use edge check instead of triangulation
1 parent db66bd3 commit 4f17a74

File tree

1 file changed

+58
-8
lines changed

1 file changed

+58
-8
lines changed
 

‎modules/navigation/3d/nav_mesh_queries_3d.cpp

+58-8
Original file line numberDiff line numberDiff line change
@@ -657,15 +657,65 @@ gd::ClosestPointQueryResult NavMeshQueries3D::polygons_get_closest_point_info(co
657657
real_t closest_point_distance_squared = FLT_MAX;
658658

659659
for (const gd::Polygon &polygon : p_polygons) {
660-
for (size_t point_id = 2; point_id < polygon.points.size(); point_id += 1) {
661-
const Face3 face(polygon.points[0].pos, polygon.points[point_id - 1].pos, polygon.points[point_id].pos);
662-
const Vector3 closest_point_on_face = face.get_closest_point_to(p_point);
663-
const real_t distance_squared_to_point = closest_point_on_face.distance_squared_to(p_point);
664-
if (distance_squared_to_point < closest_point_distance_squared) {
665-
result.point = closest_point_on_face;
666-
result.normal = face.get_plane().normal;
660+
Vector3 plane_normal = (polygon.points[1].pos - polygon.points[0].pos).cross(polygon.points[2].pos - polygon.points[0].pos);
661+
Vector3 closest_on_polygon;
662+
real_t closest = FLT_MAX;
663+
bool inside = true;
664+
Vector3 previous = polygon.points[polygon.points.size() - 1].pos;
665+
for (size_t point_id = 0; point_id < polygon.points.size(); ++point_id) {
666+
Vector3 edge = polygon.points[point_id].pos - previous;
667+
Vector3 to_point = p_point - previous;
668+
Vector3 edge_to_point_pormal = edge.cross(to_point);
669+
bool clockwise = edge_to_point_pormal.dot(plane_normal) > 0;
670+
// If we are not clockwise, the point will never be inside the polygon and so the closest point will be on an edge.
671+
if (!clockwise) {
672+
inside = false;
673+
real_t point_projected_on_edge = edge.dot(to_point);
674+
real_t edge_square = edge.length_squared();
675+
676+
if (point_projected_on_edge > edge_square) {
677+
real_t distance = polygon.points[point_id].pos.distance_squared_to(p_point);
678+
if (distance < closest) {
679+
closest_on_polygon = polygon.points[point_id].pos;
680+
closest = distance;
681+
}
682+
} else if (point_projected_on_edge < 0.f) {
683+
real_t distance = previous.distance_squared_to(p_point);
684+
if (distance < closest) {
685+
closest_on_polygon = previous;
686+
closest = distance;
687+
}
688+
} else {
689+
// If we project on this edge, this will be the closest point.
690+
real_t percent = point_projected_on_edge / edge_square;
691+
closest_on_polygon = previous + percent * edge;
692+
break;
693+
}
694+
}
695+
previous = polygon.points[point_id].pos;
696+
}
697+
698+
if (inside) {
699+
Vector3 plane_normalized = plane_normal.normalized();
700+
real_t distance = plane_normalized.dot(p_point - polygon.points[0].pos);
701+
real_t distance_squared = distance * distance;
702+
if (distance_squared < closest_point_distance_squared) {
703+
closest_point_distance_squared = distance_squared;
704+
result.point = p_point - plane_normalized * distance;
705+
result.normal = plane_normal;
706+
result.owner = polygon.owner->get_self();
707+
708+
if (Math::is_zero_approx(distance)) {
709+
break;
710+
}
711+
}
712+
} else {
713+
real_t distance = closest_on_polygon.distance_squared_to(p_point);
714+
if (distance < closest_point_distance_squared) {
715+
closest_point_distance_squared = distance;
716+
result.point = closest_on_polygon;
717+
result.normal = plane_normal;
667718
result.owner = polygon.owner->get_self();
668-
closest_point_distance_squared = distance_squared_to_point;
669719
}
670720
}
671721
}

0 commit comments

Comments
 (0)
Please sign in to comment.