Skip to content

Add checks to NavigationAgent*D to account for overshoots#114195

Open
SourceOfHTML wants to merge 1 commit intogodotengine:masterfrom
SourceOfHTML:nav_agent_overshoot
Open

Add checks to NavigationAgent*D to account for overshoots#114195
SourceOfHTML wants to merge 1 commit intogodotengine:masterfrom
SourceOfHTML:nav_agent_overshoot

Conversation

@SourceOfHTML
Copy link
Copy Markdown
Contributor

resolves #114006

Between a sphere-line segment check and this point-line segment check, the latter was faster (it certainly uses fewer square root options), so I went with that one.

I do have one hang-up about this PR: I had to add new variables to NavigationAgent*D, which I don't think is good design, but I can't come up with any other solution.

@AThousandShips AThousandShips added this to the 4.7 milestone Dec 19, 2025
@SourceOfHTML SourceOfHTML marked this pull request as ready for review December 19, 2025 12:48
@SourceOfHTML SourceOfHTML requested review from a team as code owners December 19, 2025 12:48
return p_origin.distance_to(navigation_path[navigation_path_index]) < path_desired_distance;
Vector2 waypoint = navigation_path[navigation_path_index];
return p_origin.distance_to(waypoint) < path_desired_distance ||
waypoint.distance_squared_to(Geometry2D::get_closest_point_to_segment(waypoint, previous_origin, p_origin)) < path_desired_distance * path_desired_distance;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these changes need to be benchmarked to make sure this doesn't create any regressions, depending on how heavily this method is called this could be a problem, for 2D and 3D

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, makes sense. Should I benchmark with multiple agents + avoidance, or just one? I should note that I haven't had to use pathfinding in any of my projects so far, so I'm very unfamiliar with the setup of it and how it's done (and tutorials on the subject are bare at best)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure exactly how the method is used, a good starting point is probably the benchmark project, building with the exact same build set up with and without these changes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did the benchmarks, and the results are:

 			"name": "1000 Moving Agents",
 			"results": {
-				"render_cpu": 0.06149,
-				"time": 0.021
+				"render_cpu": 0.07324,
+				"time": 2.237
 			}
 		},
@@ -13,6 +13,6 @@
 			"name": "1000 Moving Agents",
 			"results": {
-				"render_cpu": 0.01894,
-				"time": 0.154
+				"render_cpu": 0.02224,
+				"time": 0.65
 			}
 		},
@@ -21,5 +21,5 @@
 			"name": "Navigation 10 000 Random Paths",
 			"results": {
-				"time": 7.075
+				"time": 7.809
 			}
 		},
@@ -28,5 +28,5 @@
 			"name": "Navigation 10 000 Random Paths",
 			"results": {
-				"time": 8.078
+				"time": 8.04
 			}
 		}

The lines prepended with a - were done in the master branch.

Apparently my version performs 100x worse in 2D, but only ~4 times worse in 3D?

Copy link
Copy Markdown
Member

@AThousandShips AThousandShips Dec 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That might be due to differences in get_closest_point_to_segment (something to evaluate separately perhaps, but in this case far more time is probably spent in other parts of the code making this change have less of an impact), but this indicates that more detailed benchmarking might be needed to check the impact to have that data available for evaluating this PR

To be clear a loss of performance isn't a reason alone to stop this change, but it's important information to evaluate, especially as this might be an edge case but would affect all users for no benefit for most

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Point taken, I'll see how I can perf the moving agents benchmark. Hopefully this time it won't take forever to... Do whatever it is perf does below the hood.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The performance metrics are in!

The sample costs in the master branch (more specifically, v4.6.beta.custom_build [551ce8d]) are thus:

_is_within_waypoint_distance: 0% of cycles for self, 0.00426% cycles aggregate
_is_within_target_distance: 0% of cycles for self, 0.0197% cycles aggregate

Sample costs for this PR:

_is_within_waypoint_distance: 0.0217% of cycles for self, 0.0748% cycles aggregate
_is_within_target_distance: 0.0147% of cycles for self, 0.0578% aggregate.

This is the result of running the godot-benchmarks project for only the 2D version of the 1,000 moving agents (only once, I am still new to perf record) benchmark test, as that one seems to have been hit harder for performance.

It doesn't seem particularly close to the results given by godot-benchmarks itself (Less than 100 times increase from the cycle costs themselves. Still, it's a very strange difference between the two), but it is data.

@AThousandShips
Copy link
Copy Markdown
Member

So to clarify the thing above about performance I'd say the following should be considered:

  1. How many users are affected by the issue this fixes, and can that be improved/fixed by other means such as tweaking settings etc., i.e. how many users would be helped by this fix and how much
  2. How much would this affect the average user of navigation, the performance difference in the benchmark above isn't necessarily an indication that usual navigation is affected at all, so would be good to find ways to evaluate (like time per frame/frame rate with and without for the same setup)
  3. Compared with 1, how likely are edge cases with a lot of agents and how much does this affect the performance in those cases, if more users use a lot of agents and face performance drops from this compared with the number of users running very fast agents

Nothing to prevent this but it'd be important information to evaluate this change

@SourceOfHTML
Copy link
Copy Markdown
Contributor Author

I am still in the process of setting things up for a proper look at the specifics of performance, but while I do that, I'd like to throw in my two cents:

I don't believe that this fix/change is worth merging (at least, not as I've implemented it, costly as it looks to be). The problem is too specific (High Speed with requirements of low path_desired_distance) for me to believe that it is a change many need/want to see. I implemented it partially out of curiosity, and partially because maybe I'm wrong, and maybe this change is actually desired by many I also implemented it to spark discussion, because it seems like there hasn't been one regarding it before (or if it has, I haven't found its result).

If it is decided that we want to merge this change, I believe it would be better if the user could control whether or not this extra check is performed. Though, even now the Inspector tab for NavigationAgent*D is already rather clustered, we might not want to add to it.

@EricDeng1001
Copy link
Copy Markdown

  1. I believe this modification is essential as it directly impacts the correctness of numerous NavigationAgent APIs.
  2. Since we are performing additional computations, a certain degree of performance overhead is inevitable.
  3. Typically, we employ CCD (Continuous Collision Detection) to mitigate tunneling issues.
  4. CCD is usually an optional setting in UE5. They now also support MACD.
  5. A more heuristic approach is to conditionally enable this calculation by comparing the product of velocity * time against the target distance—provided that the framerate is stable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NavigationAgent3D: High velocity causes tunneling effect on waypoints, breaking path traversal logic

3 participants