@@ -657,15 +657,65 @@ gd::ClosestPointQueryResult NavMeshQueries3D::polygons_get_closest_point_info(co
657
657
real_t closest_point_distance_squared = FLT_MAX;
658
658
659
659
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;
667
718
result.owner = polygon.owner ->get_self ();
668
- closest_point_distance_squared = distance_squared_to_point;
669
719
}
670
720
}
671
721
}
0 commit comments