Skip to content

Conversation

smix8
Copy link
Contributor

@smix8 smix8 commented Sep 23, 2025

Make navmesh rasterization on the navigation regions and map more lenient by starting out with a lower internal cell scale by default and changing the merge error to just warning that can be toggled.

Closes #110686
Closes #109311
Closes #110831
Closes #108263

Many projects in Godot have navmesh rasterization problems one way or another and this PR mitigates some of those problems.

Changes:

  • Adds project settings toggles to disable the warnings for projects that just want to live with them.
  • Changes the default internal cell scale to a lower start value to avoid problems with (too late) physics step syncs.
  • Makes sure that the internal cell scale stays at a value <= 0.1 as so many projects have no margins of their own.
  • Changes the only-print-once per engine start errors to warnings that always print per navmesh build.
  • Tells the number of edge errors and how to solve / mitigate their causes or suppress the msg.
  • Continue to try to merge as much edges as possible even after an error with a navmesh geometry occurred.
  • Make navigation map cell size and navmesh cell size warnings only trigger when map has a larger cell size (as the other way around is less likely to cause problems).

To be clear, this PR is not truly a bug fix even if it might feel like one for some projects.
This is a "be more lenient and make users have the final decision if they want to live with bugs and unknowns or not".

Context:

In Godot navmesh on the NavigationServer gets merged by rasterizing the navmesh edges per edge key into a grid the size of the navigation map cell size / height.

If the input navigation mesh has geometry created and place in a way that it can not rasterize into that grid without causing edge overlaps in cells (only a pair is allowed) it creates errors, because the unique pairs of connections between navmesh edges can not be build. Aka the pathfinding on that edge will inevitable be broken, sometimes just subtle, sometimes very noticeable, depending on how important that edge was for the overall navmesh layout.

We can not avoid this rasterization step because everything in Godot about navmesh is flexible, in user hand, and can be added, removed and transformed, and even geometry modified all the time. Figuring such a geometry mess out does not work without rasterization and we can't do it super detailed and time consuming because it needs to run fast. We also can not set everything to a super tiny cell size by default as that will give other projects float precision problems early and for actual navmesh baking a small cell size is a major performance problem. We also can not just merge by mesh index because that just pushes the edge errors to a point later when they still do not fit the cell size of whatever navigation map they are used. There are proposals for having a less flexible but in turn more automated workflow godotengine/godot-proposals#12707

Changes from Godot 4.4.1 to 4.5:

While the actual rasterization has not changed between Godot 4.4.1 and 4.5 (it still uses the same cell size logic) some other things have that caused problems for some user projects.

  • The Godot 4.5 release changed the order of how navmesh edges are merged by regions and the navigation map with regions merging their internal navmesh first. This actually helped in cases of multiple regions overlapping navmesh which is why users rarely see a merge error from the map in 4.5 as the map only (re)merges the external edges of regions. The problem this causes is that all projects that already had errors might now have the errors on different polygons due to the order change. Where before it might be an edge broken that they could ignore it now came back haunting on an edge where they could no longer ignore the error.

  • In Godot 4.5 what also changed is that navigation regions are now cached until they need to change, e.g. navmesh or transform changes. In Godot 4.4.1 the navigation map and all regions would always update with every change. Due to the caching if a region was build with errors, without triggering an update for the actual region, the error and broken internal region edges would now persist. In old Godot it might have fixed itself at some point due to all the full updates, e.g. when users move geometry around to move the error causing geometry out of the way.

  • In Godot 4.5 the edge errors were treated as actual errors, because they are. It can break an entire projects pathfinding not fixing them and way too many users ignored the errors in the past. That could also be seen by all the issues that now show up, most of them being faulty rasterization settings or broken geometry related. So having this treated as actual hard errors might have created hard to solve problems for their upgrade to Godot 4.5. Having an actual error means that after an error occurred the edge loop would no longer continue trying to merge the rest of the (half) broken geometry. Some projects seem to have been very dependent on the fact that they could just ignore the errors while still getting whatever leftover navmesh managed to merge somehow.

  • Physics continues to mess everything it touches up.

Tbh at least I completely underestimated how many projects are totally willing to run with unsolved errors up to releasing games with them. For most projects ignoring the errors and not fixing settings or geometry is a path to (later) project damnation with pathfinding being constantly broken in places. In some cases it might be fine to ignore the errors and just run with them. The problem is I or the engine can not make that decision because we do not know what master plan the user is cooking in their project (sometimes the user does not know as well but that is a different issue). So lets change it in a way so users have more options how to run things, even if they might be dangerous or sub-optimal at their own responsibility.

Make navmesh rasterization on the navigation regions and map more lenient by starting out with a lower internal cell scale by default and changing the merge error to just warning that can be toggled.
@Repiteo Repiteo merged commit 1f7630f into godotengine:master Sep 25, 2025
20 checks passed
@Repiteo
Copy link
Contributor

Repiteo commented Sep 25, 2025

Thanks!

@smix8 smix8 deleted the raster_casual branch September 25, 2025 22:32
@Repiteo
Copy link
Contributor

Repiteo commented Sep 30, 2025

Cherry-picked to 4.5

@Repiteo Repiteo removed the cherrypick:4.5 Considered for cherry-picking into a future 4.5.x release label Sep 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment