Browse Source

Add triangulation partition option to 2D navigation mesh baking

Adds triangulation partition option to 2D navigation mesh baking as an alternative to the existing convex partition option.
smix8 1 year ago
parent
commit
110b2dc61a

+ 12 - 0
doc/classes/NavigationPolygon.xml

@@ -193,6 +193,9 @@
 		<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="sample_partition_type" type="int" setter="set_sample_partition_type" getter="get_sample_partition_type" enum="NavigationPolygon.SamplePartitionType" default="0">
+			Partitioning algorithm for creating the navigation mesh polys. See [enum SamplePartitionType] 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].
@@ -202,6 +205,15 @@
 		</member>
 	</members>
 	<constants>
+		<constant name="SAMPLE_PARTITION_CONVEX_PARTITION" value="0" enum="SamplePartitionType">
+			Convex partitioning that yields navigation mesh with convex polygons.
+		</constant>
+		<constant name="SAMPLE_PARTITION_TRIANGULATE" value="1" enum="SamplePartitionType">
+			Triangulation partitioning that yields navigation mesh with triangle polygons.
+		</constant>
+		<constant name="SAMPLE_PARTITION_MAX" value="2" enum="SamplePartitionType">
+			Represents the size of the [enum SamplePartitionType] enum.
+		</constant>
 		<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.

+ 26 - 4
modules/navigation/2d/nav_mesh_generator_2d.cpp

@@ -1042,10 +1042,32 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
 	}
 
 	TPPLPartition tpart;
-	if (tpart.ConvexPartition_HM(&tppl_in_polygon, &tppl_out_polygon) == 0) { //failed!
-		ERR_PRINT("NavigationPolygon Convex partition failed. Unable to create a valid NavigationMesh from defined polygon outline paths.");
-		p_navigation_mesh->clear();
-		return;
+
+	NavigationPolygon::SamplePartitionType sample_partition_type = p_navigation_mesh->get_sample_partition_type();
+
+	switch (sample_partition_type) {
+		case NavigationPolygon::SamplePartitionType::SAMPLE_PARTITION_CONVEX_PARTITION:
+			if (tpart.ConvexPartition_HM(&tppl_in_polygon, &tppl_out_polygon) == 0) {
+				ERR_PRINT("NavigationPolygon polygon convex partition failed. Unable to create a valid navigation mesh polygon layout from provided source geometry.");
+				p_navigation_mesh->set_vertices(Vector<Vector2>());
+				p_navigation_mesh->clear_polygons();
+				return;
+			}
+			break;
+		case NavigationPolygon::SamplePartitionType::SAMPLE_PARTITION_TRIANGULATE:
+			if (tpart.Triangulate_EC(&tppl_in_polygon, &tppl_out_polygon) == 0) {
+				ERR_PRINT("NavigationPolygon polygon triangulation failed. Unable to create a valid navigation mesh polygon layout from provided source geometry.");
+				p_navigation_mesh->set_vertices(Vector<Vector2>());
+				p_navigation_mesh->clear_polygons();
+				return;
+			}
+			break;
+		default: {
+			ERR_PRINT("NavigationPolygon polygon partitioning failed. Unrecognized partition type.");
+			p_navigation_mesh->set_vertices(Vector<Vector2>());
+			p_navigation_mesh->clear_polygons();
+			return;
+		}
 	}
 
 	Vector<Vector2> new_vertices;

+ 18 - 0
scene/resources/2d/navigation_polygon.cpp

@@ -400,6 +400,15 @@ real_t NavigationPolygon::get_border_size() const {
 	return border_size;
 }
 
+void NavigationPolygon::set_sample_partition_type(SamplePartitionType p_value) {
+	ERR_FAIL_INDEX(p_value, SAMPLE_PARTITION_MAX);
+	partition_type = p_value;
+}
+
+NavigationPolygon::SamplePartitionType NavigationPolygon::get_sample_partition_type() const {
+	return partition_type;
+}
+
 void NavigationPolygon::set_parsed_geometry_type(ParsedGeometryType p_geometry_type) {
 	ERR_FAIL_INDEX(p_geometry_type, PARSED_GEOMETRY_MAX);
 	parsed_geometry_type = p_geometry_type;
@@ -514,6 +523,9 @@ void NavigationPolygon::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_border_size", "border_size"), &NavigationPolygon::set_border_size);
 	ClassDB::bind_method(D_METHOD("get_border_size"), &NavigationPolygon::get_border_size);
 
+	ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationPolygon::set_sample_partition_type);
+	ClassDB::bind_method(D_METHOD("get_sample_partition_type"), &NavigationPolygon::get_sample_partition_type);
+
 	ClassDB::bind_method(D_METHOD("set_parsed_geometry_type", "geometry_type"), &NavigationPolygon::set_parsed_geometry_type);
 	ClassDB::bind_method(D_METHOD("get_parsed_geometry_type"), &NavigationPolygon::get_parsed_geometry_type);
 
@@ -543,6 +555,8 @@ void NavigationPolygon::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
 	ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines");
 
+	ADD_GROUP("Sampling", "sample_");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type", PROPERTY_HINT_ENUM, "Convex Partition,Triangulate"), "set_sample_partition_type", "get_sample_partition_type");
 	ADD_GROUP("Geometry", "");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Meshes and Static Colliders"), "set_parsed_geometry_type", "get_parsed_geometry_type");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "parsed_collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_parsed_collision_mask", "get_parsed_collision_mask");
@@ -559,6 +573,10 @@ void NavigationPolygon::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::RECT2, "baking_rect"), "set_baking_rect", "get_baking_rect");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "baking_rect_offset"), "set_baking_rect_offset", "get_baking_rect_offset");
 
+	BIND_ENUM_CONSTANT(SAMPLE_PARTITION_CONVEX_PARTITION);
+	BIND_ENUM_CONSTANT(SAMPLE_PARTITION_TRIANGULATE);
+	BIND_ENUM_CONSTANT(SAMPLE_PARTITION_MAX);
+
 	BIND_ENUM_CONSTANT(PARSED_GEOMETRY_MESH_INSTANCES);
 	BIND_ENUM_CONSTANT(PARSED_GEOMETRY_STATIC_COLLIDERS);
 	BIND_ENUM_CONSTANT(PARSED_GEOMETRY_BOTH);

+ 10 - 0
scene/resources/2d/navigation_polygon.h

@@ -74,6 +74,11 @@ public:
 	Rect2 _edit_get_rect() const;
 	bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
 #endif
+	enum SamplePartitionType {
+		SAMPLE_PARTITION_CONVEX_PARTITION = 0,
+		SAMPLE_PARTITION_TRIANGULATE,
+		SAMPLE_PARTITION_MAX
+	};
 
 	enum ParsedGeometryType {
 		PARSED_GEOMETRY_MESH_INSTANCES = 0,
@@ -91,6 +96,7 @@ public:
 
 	real_t agent_radius = 10.0f;
 
+	SamplePartitionType partition_type = SAMPLE_PARTITION_CONVEX_PARTITION;
 	ParsedGeometryType parsed_geometry_type = PARSED_GEOMETRY_BOTH;
 	uint32_t parsed_collision_mask = 0xFFFFFFFF;
 
@@ -120,6 +126,9 @@ public:
 	Vector<int> get_polygon(int p_idx);
 	void clear_polygons();
 
+	void set_sample_partition_type(SamplePartitionType p_value);
+	SamplePartitionType get_sample_partition_type() const;
+
 	void set_parsed_geometry_type(ParsedGeometryType p_geometry_type);
 	ParsedGeometryType get_parsed_geometry_type() const;
 
@@ -161,6 +170,7 @@ public:
 	~NavigationPolygon() {}
 };
 
+VARIANT_ENUM_CAST(NavigationPolygon::SamplePartitionType);
 VARIANT_ENUM_CAST(NavigationPolygon::ParsedGeometryType);
 VARIANT_ENUM_CAST(NavigationPolygon::SourceGeometryMode);