Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 2D navigation mesh baking #80796

Merged
merged 1 commit into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions COPYRIGHT.txt
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@ Comment: CA certificates
Copyright: Mozilla Contributors
License: MPL-2.0

Files: ./thirdparty/clipper2/
Comment: Clipper2
Copyright: 2010-2013, Angus Johnson
License: BSL-1.0

Files: ./thirdparty/cvtt/
Comment: Convection Texture Tools Stand-Alone Kernels
Copyright: 2018, Eric Lasota
Expand Down
1 change: 1 addition & 0 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ opts.Add("scu_limit", "Max includes per SCU file when using scu_build (determine
# Thirdparty libraries
opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True))
opts.Add(BoolVariable("builtin_certs", "Use the built-in SSL certificates bundles", True))
opts.Add(BoolVariable("builtin_clipper2", "Use the built-in Clipper2 library", True))
opts.Add(BoolVariable("builtin_embree", "Use the built-in Embree library", True))
opts.Add(BoolVariable("builtin_enet", "Use the built-in ENet library", True))
opts.Add(BoolVariable("builtin_freetype", "Use the built-in FreeType library", True))
Expand Down
18 changes: 18 additions & 0 deletions core/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,24 @@ if env["brotli"] and env["builtin_brotli"]:

env_thirdparty.add_source_files(thirdparty_obj, thirdparty_brotli_sources)

# Clipper2 Thirdparty source files used for polygon and polyline boolean operations.
if env["builtin_clipper2"]:
thirdparty_clipper_dir = "#thirdparty/clipper2/"
thirdparty_clipper_sources = [
"src/clipper.engine.cpp",
"src/clipper.offset.cpp",
"src/clipper.rectclip.cpp",
]
thirdparty_clipper_sources = [thirdparty_clipper_dir + file for file in thirdparty_clipper_sources]

env_thirdparty.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"])
env.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"])

env_thirdparty.Append(CPPDEFINES=["CLIPPER2_ENABLED"])
env.Append(CPPDEFINES=["CLIPPER2_ENABLED"])

env_thirdparty.add_source_files(thirdparty_obj, thirdparty_clipper_sources)

# Zlib library, can be unbundled
if env["builtin_zlib"]:
thirdparty_zlib_dir = "#thirdparty/zlib/"
Expand Down
65 changes: 65 additions & 0 deletions doc/classes/NavigationMeshSourceGeometryData2D.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="NavigationMeshSourceGeometryData2D" inherits="Resource" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Container for parsed source geometry data used in navigation mesh baking.
</brief_description>
<description>
Container for parsed source geometry data used in navigation mesh baking.
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_obstruction_outline">
<return type="void" />
<param index="0" name="shape_outline" type="PackedVector2Array" />
<description>
Adds the outline points of a shape as obstructed area.
</description>
</method>
<method name="add_traversable_outline">
<return type="void" />
<param index="0" name="shape_outline" type="PackedVector2Array" />
<description>
Adds the outline points of a shape as traversable area.
</description>
</method>
<method name="clear">
<return type="void" />
<description>
Clears the internal data.
</description>
</method>
<method name="get_obstruction_outlines" qualifiers="const">
<return type="PackedVector2Array[]" />
<description>
Returns all the obstructed area outlines arrays.
</description>
</method>
<method name="get_traversable_outlines" qualifiers="const">
<return type="PackedVector2Array[]" />
<description>
Returns all the traversable area outlines arrays.
</description>
</method>
<method name="has_data">
<return type="bool" />
<description>
Returns [code]true[/code] when parsed source geometry data exists.
</description>
</method>
<method name="set_obstruction_outlines">
<return type="void" />
<param index="0" name="obstruction_outlines" type="PackedVector2Array[]" />
<description>
Sets all the obstructed area outlines arrays.
</description>
</method>
<method name="set_traversable_outlines">
<return type="void" />
<param index="0" name="traversable_outlines" type="PackedVector2Array[]" />
<description>
Sets all the traversable area outlines arrays.
</description>
</method>
</methods>
</class>
118 changes: 89 additions & 29 deletions doc/classes/NavigationPolygon.xml
Original file line number Diff line number Diff line change
@@ -1,44 +1,44 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="NavigationPolygon" inherits="Resource" is_experimental="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A navigation polygon that defines traversable areas and obstacles.
A 2D navigation mesh that describes a traversable surface for pathfinding.
</brief_description>
<description>
There are two ways to create polygons. Either by using the [method add_outline] method, or using the [method add_polygon] method.
Using [method add_outline]:
A navigation mesh can be created either by baking it with the help of the [NavigationServer2D], or by adding vertices and convex polygon indices arrays manually.
To bake a navigation mesh at least one outline needs to be added that defines the outer bounds of the baked area.
[codeblocks]
[gdscript]
var polygon = NavigationPolygon.new()
var outline = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
polygon.add_outline(outline)
polygon.make_polygons_from_outlines()
$NavigationRegion2D.navigation_polygon = polygon
var new_navigation_mesh = NavigationPolygon.new()
var bounding_outline = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
new_navigation_mesh.add_outline(bounding_outline)
NavigationServer2D.bake_from_source_geometry_data(new_navigation_mesh, NavigationMeshSourceGeometryData2D.new());
$NavigationRegion2D.navigation_polygon = new_navigation_mesh
[/gdscript]
[csharp]
var polygon = new NavigationPolygon();
var outline = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) };
polygon.AddOutline(outline);
polygon.MakePolygonsFromOutlines();
GetNode&lt;NavigationRegion2D&gt;("NavigationRegion2D").NavigationPolygon = polygon;
var newNavigationMesh = new NavigationPolygon();
var boundingOutline = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) };
newNavigationMesh.AddOutline(boundingOutline);
NavigationServer2D.BakeFromSourceGeometryData(newNavigationMesh, new NavigationMeshSourceGeometryData2D());
GetNode&lt;NavigationRegion2D&gt;("NavigationRegion2D").NavigationPolygon = newNavigationMesh;
[/csharp]
[/codeblocks]
Using [method add_polygon] and indices of the vertices array.
Adding vertices and polygon indices manually.
[codeblocks]
[gdscript]
var polygon = NavigationPolygon.new()
var vertices = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
polygon.vertices = vertices
var indices = PackedInt32Array([0, 1, 2, 3])
polygon.add_polygon(indices)
$NavigationRegion2D.navigation_polygon = polygon
var new_navigation_mesh = NavigationPolygon.new()
var new_vertices = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
new_navigation_mesh.vertices = new_vertices
var new_polygon_indices = PackedInt32Array([0, 1, 2, 3])
new_navigation_mesh.add_polygon(new_polygon_indices)
$NavigationRegion2D.navigation_polygon = new_navigation_mesh
[/gdscript]
[csharp]
var polygon = new NavigationPolygon();
var vertices = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) };
polygon.Vertices = vertices;
var indices = new int[] { 0, 1, 2, 3 };
polygon.AddPolygon(indices);
GetNode&lt;NavigationRegion2D&gt;("NavigationRegion2D").NavigationPolygon = polygon;
var newNavigationMesh = new NavigationPolygon();
var newVertices = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) };
newNavigationMesh.Vertices = newVertices;
var newPolygonIndices = new int[] { 0, 1, 2, 3 };
newNavigationMesh.AddPolygon(newPolygonIndices);
GetNode&lt;NavigationRegion2D&gt;("NavigationRegion2D").NavigationPolygon = newNavigationMesh;
[/csharp]
[/codeblocks]
</description>
Expand All @@ -51,15 +51,15 @@
<return type="void" />
<param index="0" name="outline" type="PackedVector2Array" />
<description>
Appends a [PackedVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines. You have to call [method make_polygons_from_outlines] in order for this array to be converted to polygons that the engine will use.
Appends a [PackedVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines.
</description>
</method>
<method name="add_outline_at_index">
<return type="void" />
<param index="0" name="outline" type="PackedVector2Array" />
<param index="1" name="index" type="int" />
<description>
Adds a [PackedVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines at a fixed position. You have to call [method make_polygons_from_outlines] in order for this array to be converted to polygons that the engine will use.
Adds a [PackedVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines at a fixed position.
</description>
</method>
<method name="add_polygon">
Expand Down Expand Up @@ -106,6 +106,13 @@
Returns the number of outlines that were created in the editor or by script.
</description>
</method>
<method name="get_parsed_collision_mask_value" qualifiers="const">
<return type="bool" />
<param index="0" name="layer_number" type="int" />
<description>
Returns whether or not the specified layer of the [member parsed_collision_mask] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_polygon">
<return type="PackedInt32Array" />
<param index="0" name="idx" type="int" />
Expand All @@ -125,10 +132,11 @@
Returns a [PackedVector2Array] containing all the vertices being used to create the polygons.
</description>
</method>
<method name="make_polygons_from_outlines">
<method name="make_polygons_from_outlines" is_deprecated="true">
<return type="void" />
<description>
Creates polygons from the outlines added in the editor or by script.
[i]Deprecated.[/i] This function is deprecated, and might be removed in a future release. Use [method NavigationServer2D.parse_source_geometry_data] and [method NavigationServer2D.bake_from_source_geometry_data] instead.
</description>
</method>
<method name="remove_outline">
Expand All @@ -146,6 +154,14 @@
Changes an outline created in the editor or by script. You have to call [method make_polygons_from_outlines] for the polygons to update.
</description>
</method>
<method name="set_parsed_collision_mask_value">
<return type="void" />
<param index="0" name="layer_number" type="int" />
<param index="1" name="value" type="bool" />
<description>
Based on [param value], enables or disables the specified layer in the [member parsed_collision_mask], given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="set_vertices">
<return type="void" />
<param index="0" name="vertices" type="PackedVector2Array" />
Expand All @@ -155,8 +171,52 @@
</method>
</methods>
<members>
<member name="agent_radius" type="float" setter="set_agent_radius" getter="get_agent_radius" default="10.0">
The distance to erode/shrink the walkable surface when baking the navigation mesh.
</member>
<member name="cell_size" type="float" setter="set_cell_size" getter="get_cell_size" default="1.0">
The cell size used to rasterize the navigation mesh vertices. Must match with the cell size on the navigation map.
</member>
<member name="parsed_collision_mask" type="int" setter="set_parsed_collision_mask" getter="get_parsed_collision_mask" default="4294967295">
The physics layers to scan for static colliders.
Only used when [member parsed_geometry_type] is [constant PARSED_GEOMETRY_STATIC_COLLIDERS] or [constant PARSED_GEOMETRY_BOTH].
</member>
<member name="parsed_geometry_type" type="int" setter="set_parsed_geometry_type" getter="get_parsed_geometry_type" enum="NavigationPolygon.ParsedGeometryType" default="2">
Determines which type of nodes will be parsed as geometry. See [enum ParsedGeometryType] for possible values.
</member>
<member name="source_geometry_group_name" type="StringName" setter="set_source_geometry_group_name" getter="get_source_geometry_group_name" default="&amp;&quot;navigation_polygon_source_geometry_group&quot;">
The group name of nodes that should be parsed for baking source geometry.
Only used when [member source_geometry_mode] is [constant SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN] or [constant SOURCE_GEOMETRY_GROUPS_EXPLICIT].
</member>
<member name="source_geometry_mode" type="int" setter="set_source_geometry_mode" getter="get_source_geometry_mode" enum="NavigationPolygon.SourceGeometryMode" default="0">
The source of the geometry used when baking. See [enum SourceGeometryMode] for possible values.
</member>
</members>
<constants>
<constant name="PARSED_GEOMETRY_MESH_INSTANCES" value="0" enum="ParsedGeometryType">
Parses mesh instances as obstruction geometry. This includes [Polygon2D], [MeshInstance2D], [MultiMeshInstance2D], and [TileMap] nodes.
Meshes are only parsed when they use a 2D vertices surface format.
</constant>
<constant name="PARSED_GEOMETRY_STATIC_COLLIDERS" value="1" enum="ParsedGeometryType">
Parses [StaticBody2D] and [TileMap] colliders as obstruction geometry. The collider should be in any of the layers specified by [member parsed_collision_mask].
</constant>
<constant name="PARSED_GEOMETRY_BOTH" value="2" enum="ParsedGeometryType">
Both [constant PARSED_GEOMETRY_MESH_INSTANCES] and [constant PARSED_GEOMETRY_STATIC_COLLIDERS].
</constant>
<constant name="PARSED_GEOMETRY_MAX" value="3" enum="ParsedGeometryType">
Represents the size of the [enum ParsedGeometryType] enum.
</constant>
<constant name="SOURCE_GEOMETRY_ROOT_NODE_CHILDREN" value="0" enum="SourceGeometryMode">
Scans the child nodes of the root node recursively for geometry.
</constant>
<constant name="SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN" value="1" enum="SourceGeometryMode">
Scans nodes in a group and their child nodes recursively for geometry. The group is specified by [member source_geometry_group_name].
</constant>
<constant name="SOURCE_GEOMETRY_GROUPS_EXPLICIT" value="2" enum="SourceGeometryMode">
Uses nodes in a group for geometry. The group is specified by [member source_geometry_group_name].
</constant>
<constant name="SOURCE_GEOMETRY_MAX" value="3" enum="SourceGeometryMode">
Represents the size of the [enum SourceGeometryMode] enum.
</constant>
</constants>
</class>
19 changes: 19 additions & 0 deletions doc/classes/NavigationRegion2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
<link title="Using NavigationRegions">$DOCS_URL/tutorials/navigation/navigation_using_navigationregions.html</link>
</tutorials>
<methods>
<method name="bake_navigation_polygon">
<return type="void" />
<param index="0" name="on_thread" type="bool" default="true" />
<description>
Bakes the [NavigationPolygon]. If [param on_thread] is set to [code]true[/code] (default), the baking is done on a separate thread.
</description>
</method>
<method name="get_avoidance_layer_value" qualifiers="const">
<return type="bool" />
<param index="0" name="layer_number" type="int" />
Expand Down Expand Up @@ -93,4 +100,16 @@
If enabled the navigation region will use edge connections to connect with other navigation regions within proximity of the navigation map edge connection margin.
</member>
</members>
<signals>
<signal name="bake_finished">
<description>
Emitted when a navigation polygon bake operation is completed.
</description>
</signal>
<signal name="navigation_polygon_changed">
<description>
Emitted when the used navigation polygon is replaced or changes to the internals of the current navigation polygon are committed.
</description>
</signal>
</signals>
</class>
30 changes: 30 additions & 0 deletions doc/classes/NavigationServer2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,24 @@
Replaces the internal velocity in the collision avoidance simulation with [param velocity] for the specified [param agent]. When an agent is teleported to a new position far away this function should be used in the same frame. If called frequently this function can get agents stuck.
</description>
</method>
<method name="bake_from_source_geometry_data">
<return type="void" />
<param index="0" name="navigation_polygon" type="NavigationPolygon" />
<param index="1" name="source_geometry_data" type="NavigationMeshSourceGeometryData2D" />
<param index="2" name="callback" type="Callable" default="Callable()" />
<description>
Bakes the provided [param navigation_polygon] with the data from the provided [param source_geometry_data]. After the process is finished the optional [param callback] will be called.
</description>
</method>
<method name="bake_from_source_geometry_data_async">
<return type="void" />
<param index="0" name="navigation_polygon" type="NavigationPolygon" />
<param index="1" name="source_geometry_data" type="NavigationMeshSourceGeometryData2D" />
<param index="2" name="callback" type="Callable" default="Callable()" />
<description>
Bakes the provided [param navigation_polygon] with the data from the provided [param source_geometry_data] as an async task running on a background thread. After the process is finished the optional [param callback] will be called.
</description>
</method>
<method name="free_rid">
<return type="void" />
<param index="0" name="rid" type="RID" />
Expand Down Expand Up @@ -579,6 +597,18 @@
Sets the outline vertices for the obstacle. If the vertices are winded in clockwise order agents will be pushed in by the obstacle, else they will be pushed out.
</description>
</method>
<method name="parse_source_geometry_data">
<return type="void" />
<param index="0" name="navigation_polygon" type="NavigationPolygon" />
<param index="1" name="source_geometry_data" type="NavigationMeshSourceGeometryData2D" />
<param index="2" name="root_node" type="Node" />
<param index="3" name="callback" type="Callable" default="Callable()" />
<description>
Parses the [SceneTree] for source geometry according to the properties of [param navigation_polygon]. Updates the provided [param source_geometry_data] resource with the resulting data. The resource can then be used to bake a navigation mesh with [method bake_from_source_geometry_data]. After the process is finished the optional [param callback] will be called.
[b]Note:[/b] This function needs to run on the main thread or with a deferred call as the SceneTree is not thread-safe.
[b]Performance:[/b] While convenient, reading data arrays from [Mesh] resources can affect the frame rate negatively. The data needs to be received from the GPU, stalling the [RenderingServer] in the process. For performance prefer the use of e.g. collision shapes or creating the data arrays entirely in code.
</description>
</method>
<method name="query_path" qualifiers="const">
<return type="void" />
<param index="0" name="parameters" type="NavigationPathQueryParameters2D" />
Expand Down
Loading