Ver código fonte

Merge pull request #87961 from smix8/navmesh2d_bordersize

Add NavigationPolygon `border_size` property for tile baking
Rémi Verschelde 1 ano atrás
pai
commit
8daa633d0d

+ 10 - 0
doc/classes/NavigationPolygon.xml

@@ -174,6 +174,16 @@
 		<member name="agent_radius" type="float" setter="set_agent_radius" getter="get_agent_radius" default="10.0">
 		<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.
 			The distance to erode/shrink the walkable surface when baking the navigation mesh.
 		</member>
 		</member>
+		<member name="baking_rect" type="Rect2" setter="set_baking_rect" getter="get_baking_rect" default="Rect2(0, 0, 0, 0)">
+			If the baking [Rect2] has an area the navigation mesh baking will be restricted to its enclosing area.
+		</member>
+		<member name="baking_rect_offset" type="Vector2" setter="set_baking_rect_offset" getter="get_baking_rect_offset" default="Vector2(0, 0)">
+			The position offset applied to the [member baking_rect] [Rect2].
+		</member>
+		<member name="border_size" type="float" setter="set_border_size" getter="get_border_size" default="0.0">
+			The size of the non-navigable border around the bake bounding area defined by the [member baking_rect] [Rect2].
+			In conjunction with the [member baking_rect] the border size can be used to bake tile aligned navigation meshes without the tile edges being shrunk by [member agent_radius].
+		</member>
 		<member name="cell_size" type="float" setter="set_cell_size" getter="get_cell_size" default="1.0">
 		<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.
 			The cell size used to rasterize the navigation mesh vertices. Must match with the cell size on the navigation map.
 		</member>
 		</member>

+ 38 - 0
modules/navigation/nav_mesh_generator_2d.cpp

@@ -743,9 +743,13 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
 	Paths64 traversable_polygon_paths;
 	Paths64 traversable_polygon_paths;
 	Paths64 obstruction_polygon_paths;
 	Paths64 obstruction_polygon_paths;
 
 
+	traversable_polygon_paths.reserve(outline_count + traversable_outlines.size());
+	obstruction_polygon_paths.reserve(obstruction_outlines.size());
+
 	for (int i = 0; i < outline_count; i++) {
 	for (int i = 0; i < outline_count; i++) {
 		const Vector<Vector2> &traversable_outline = p_navigation_mesh->get_outline(i);
 		const Vector<Vector2> &traversable_outline = p_navigation_mesh->get_outline(i);
 		Path64 subject_path;
 		Path64 subject_path;
+		subject_path.reserve(traversable_outline.size());
 		for (const Vector2 &traversable_point : traversable_outline) {
 		for (const Vector2 &traversable_point : traversable_outline) {
 			const Point64 &point = Point64(traversable_point.x, traversable_point.y);
 			const Point64 &point = Point64(traversable_point.x, traversable_point.y);
 			subject_path.push_back(point);
 			subject_path.push_back(point);
@@ -755,6 +759,7 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
 
 
 	for (const Vector<Vector2> &traversable_outline : traversable_outlines) {
 	for (const Vector<Vector2> &traversable_outline : traversable_outlines) {
 		Path64 subject_path;
 		Path64 subject_path;
+		subject_path.reserve(traversable_outline.size());
 		for (const Vector2 &traversable_point : traversable_outline) {
 		for (const Vector2 &traversable_point : traversable_outline) {
 			const Point64 &point = Point64(traversable_point.x, traversable_point.y);
 			const Point64 &point = Point64(traversable_point.x, traversable_point.y);
 			subject_path.push_back(point);
 			subject_path.push_back(point);
@@ -764,6 +769,7 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
 
 
 	for (const Vector<Vector2> &obstruction_outline : obstruction_outlines) {
 	for (const Vector<Vector2> &obstruction_outline : obstruction_outlines) {
 		Path64 clip_path;
 		Path64 clip_path;
+		clip_path.reserve(obstruction_outline.size());
 		for (const Vector2 &obstruction_point : obstruction_outline) {
 		for (const Vector2 &obstruction_point : obstruction_outline) {
 			const Point64 &point = Point64(obstruction_point.x, obstruction_point.y);
 			const Point64 &point = Point64(obstruction_point.x, obstruction_point.y);
 			clip_path.push_back(point);
 			clip_path.push_back(point);
@@ -771,6 +777,22 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
 		obstruction_polygon_paths.push_back(clip_path);
 		obstruction_polygon_paths.push_back(clip_path);
 	}
 	}
 
 
+	Rect2 baking_rect = p_navigation_mesh->get_baking_rect();
+	if (baking_rect.has_area()) {
+		Vector2 baking_rect_offset = p_navigation_mesh->get_baking_rect_offset();
+
+		const int rect_begin_x = baking_rect.position[0] + baking_rect_offset.x;
+		const int rect_begin_y = baking_rect.position[1] + baking_rect_offset.y;
+		const int rect_end_x = baking_rect.position[0] + baking_rect.size[0] + baking_rect_offset.x;
+		const int rect_end_y = baking_rect.position[1] + baking_rect.size[1] + baking_rect_offset.y;
+
+		Rect64 clipper_rect = Rect64(rect_begin_x, rect_begin_y, rect_end_x, rect_end_y);
+		RectClip rect_clip = RectClip(clipper_rect);
+
+		traversable_polygon_paths = rect_clip.Execute(traversable_polygon_paths);
+		obstruction_polygon_paths = rect_clip.Execute(obstruction_polygon_paths);
+	}
+
 	Paths64 path_solution;
 	Paths64 path_solution;
 
 
 	// first merge all traversable polygons according to user specified fill rule
 	// first merge all traversable polygons according to user specified fill rule
@@ -787,6 +809,21 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
 	}
 	}
 	//path_solution = RamerDouglasPeucker(path_solution, 0.025); //
 	//path_solution = RamerDouglasPeucker(path_solution, 0.025); //
 
 
+	real_t border_size = p_navigation_mesh->get_border_size();
+	if (baking_rect.has_area() && border_size > 0.0) {
+		Vector2 baking_rect_offset = p_navigation_mesh->get_baking_rect_offset();
+
+		const int rect_begin_x = baking_rect.position[0] + baking_rect_offset.x + border_size;
+		const int rect_begin_y = baking_rect.position[1] + baking_rect_offset.y + border_size;
+		const int rect_end_x = baking_rect.position[0] + baking_rect.size[0] + baking_rect_offset.x - border_size;
+		const int rect_end_y = baking_rect.position[1] + baking_rect.size[1] + baking_rect_offset.y - border_size;
+
+		Rect64 clipper_rect = Rect64(rect_begin_x, rect_begin_y, rect_end_x, rect_end_y);
+		RectClip rect_clip = RectClip(clipper_rect);
+
+		path_solution = rect_clip.Execute(path_solution);
+	}
+
 	Vector<Vector<Vector2>> new_baked_outlines;
 	Vector<Vector<Vector2>> new_baked_outlines;
 
 
 	for (const Path64 &scaled_path : path_solution) {
 	for (const Path64 &scaled_path : path_solution) {
@@ -804,6 +841,7 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
 	}
 	}
 
 
 	Paths64 polygon_paths;
 	Paths64 polygon_paths;
+	polygon_paths.reserve(new_baked_outlines.size());
 
 
 	for (const Vector<Vector2> &baked_outline : new_baked_outlines) {
 	for (const Vector<Vector2> &baked_outline : new_baked_outlines) {
 		Path64 polygon_path;
 		Path64 polygon_path;

+ 39 - 0
scene/resources/navigation_polygon.cpp

@@ -347,6 +347,15 @@ real_t NavigationPolygon::get_cell_size() const {
 	return cell_size;
 	return cell_size;
 }
 }
 
 
+void NavigationPolygon::set_border_size(real_t p_value) {
+	ERR_FAIL_COND(p_value < 0.0);
+	border_size = p_value;
+}
+
+real_t NavigationPolygon::get_border_size() const {
+	return border_size;
+}
+
 void NavigationPolygon::set_parsed_geometry_type(ParsedGeometryType p_geometry_type) {
 void NavigationPolygon::set_parsed_geometry_type(ParsedGeometryType p_geometry_type) {
 	ERR_FAIL_INDEX(p_geometry_type, PARSED_GEOMETRY_MAX);
 	ERR_FAIL_INDEX(p_geometry_type, PARSED_GEOMETRY_MAX);
 	parsed_geometry_type = p_geometry_type;
 	parsed_geometry_type = p_geometry_type;
@@ -410,6 +419,24 @@ real_t NavigationPolygon::get_agent_radius() const {
 	return agent_radius;
 	return agent_radius;
 }
 }
 
 
+void NavigationPolygon::set_baking_rect(const Rect2 &p_rect) {
+	baking_rect = p_rect;
+	emit_changed();
+}
+
+Rect2 NavigationPolygon::get_baking_rect() const {
+	return baking_rect;
+}
+
+void NavigationPolygon::set_baking_rect_offset(const Vector2 &p_rect_offset) {
+	baking_rect_offset = p_rect_offset;
+	emit_changed();
+}
+
+Vector2 NavigationPolygon::get_baking_rect_offset() const {
+	return baking_rect_offset;
+}
+
 void NavigationPolygon::_bind_methods() {
 void NavigationPolygon::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices);
 	ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices);
 	ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices);
 	ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices);
@@ -440,6 +467,9 @@ void NavigationPolygon::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationPolygon::set_cell_size);
 	ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationPolygon::set_cell_size);
 	ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationPolygon::get_cell_size);
 	ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationPolygon::get_cell_size);
 
 
+	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_parsed_geometry_type", "geometry_type"), &NavigationPolygon::set_parsed_geometry_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);
 	ClassDB::bind_method(D_METHOD("get_parsed_geometry_type"), &NavigationPolygon::get_parsed_geometry_type);
 
 
@@ -458,6 +488,11 @@ void NavigationPolygon::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_agent_radius", "agent_radius"), &NavigationPolygon::set_agent_radius);
 	ClassDB::bind_method(D_METHOD("set_agent_radius", "agent_radius"), &NavigationPolygon::set_agent_radius);
 	ClassDB::bind_method(D_METHOD("get_agent_radius"), &NavigationPolygon::get_agent_radius);
 	ClassDB::bind_method(D_METHOD("get_agent_radius"), &NavigationPolygon::get_agent_radius);
 
 
+	ClassDB::bind_method(D_METHOD("set_baking_rect", "rect"), &NavigationPolygon::set_baking_rect);
+	ClassDB::bind_method(D_METHOD("get_baking_rect"), &NavigationPolygon::get_baking_rect);
+	ClassDB::bind_method(D_METHOD("set_baking_rect_offset", "rect_offset"), &NavigationPolygon::set_baking_rect_offset);
+	ClassDB::bind_method(D_METHOD("get_baking_rect_offset"), &NavigationPolygon::get_baking_rect_offset);
+
 	ClassDB::bind_method(D_METHOD("clear"), &NavigationPolygon::clear);
 	ClassDB::bind_method(D_METHOD("clear"), &NavigationPolygon::clear);
 
 
 	ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
 	ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
@@ -473,8 +508,12 @@ void NavigationPolygon::_bind_methods() {
 	ADD_PROPERTY_DEFAULT("source_geometry_group_name", StringName("navigation_polygon_source_geometry_group"));
 	ADD_PROPERTY_DEFAULT("source_geometry_group_name", StringName("navigation_polygon_source_geometry_group"));
 	ADD_GROUP("Cells", "");
 	ADD_GROUP("Cells", "");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "1.0,50.0,1.0,or_greater,suffix:px"), "set_cell_size", "get_cell_size");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "1.0,50.0,1.0,or_greater,suffix:px"), "set_cell_size", "get_cell_size");
+	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "border_size", PROPERTY_HINT_RANGE, "0.0,500.0,1.0,or_greater,suffix:px"), "set_border_size", "get_border_size");
 	ADD_GROUP("Agents", "agent_");
 	ADD_GROUP("Agents", "agent_");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_radius", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater,suffix:px"), "set_agent_radius", "get_agent_radius");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_radius", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater,suffix:px"), "set_agent_radius", "get_agent_radius");
+	ADD_GROUP("Filters", "");
+	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(PARSED_GEOMETRY_MESH_INSTANCES);
 	BIND_ENUM_CONSTANT(PARSED_GEOMETRY_MESH_INSTANCES);
 	BIND_ENUM_CONSTANT(PARSED_GEOMETRY_STATIC_COLLIDERS);
 	BIND_ENUM_CONSTANT(PARSED_GEOMETRY_STATIC_COLLIDERS);

+ 13 - 0
scene/resources/navigation_polygon.h

@@ -53,6 +53,10 @@ class NavigationPolygon : public Resource {
 	Ref<NavigationMesh> navigation_mesh;
 	Ref<NavigationMesh> navigation_mesh;
 
 
 	real_t cell_size = 1.0f; // Must match ProjectSettings default 2D cell_size.
 	real_t cell_size = 1.0f; // Must match ProjectSettings default 2D cell_size.
+	real_t border_size = 0.0f;
+
+	Rect2 baking_rect;
+	Vector2 baking_rect_offset;
 
 
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
@@ -138,6 +142,15 @@ public:
 	void set_cell_size(real_t p_cell_size);
 	void set_cell_size(real_t p_cell_size);
 	real_t get_cell_size() const;
 	real_t get_cell_size() const;
 
 
+	void set_border_size(real_t p_value);
+	real_t get_border_size() const;
+
+	void set_baking_rect(const Rect2 &p_rect);
+	Rect2 get_baking_rect() const;
+
+	void set_baking_rect_offset(const Vector2 &p_rect_offset);
+	Vector2 get_baking_rect_offset() const;
+
 	void clear();
 	void clear();
 
 
 	NavigationPolygon();
 	NavigationPolygon();