Skip to content

Commit 07b7f76

Browse files
kiroxasakien-mga
authored andcommitted
Improve NavMeshGenerator2D::generator_bake_from_source_geometry_data performance
Avoid copies and redundant work.
1 parent 0f5f3bc commit 07b7f76

File tree

2 files changed

+72
-123
lines changed

2 files changed

+72
-123
lines changed

modules/navigation/2d/nav_mesh_generator_2d.cpp

+70-123
Original file line numberDiff line numberDiff line change
@@ -760,16 +760,14 @@ void NavMeshGenerator2D::generator_parse_source_geometry_data(Ref<NavigationPoly
760760
static void generator_recursive_process_polytree_items(List<TPPLPoly> &p_tppl_in_polygon, const Clipper2Lib::PolyPathD *p_polypath_item) {
761761
using namespace Clipper2Lib;
762762

763-
Vector<Vector2> polygon_vertices;
763+
TPPLPoly tp;
764+
int size = p_polypath_item->Polygon().size();
765+
tp.Init(size);
764766

767+
int j = 0;
765768
for (const PointD &polypath_point : p_polypath_item->Polygon()) {
766-
polygon_vertices.push_back(Vector2(static_cast<real_t>(polypath_point.x), static_cast<real_t>(polypath_point.y)));
767-
}
768-
769-
TPPLPoly tp;
770-
tp.Init(polygon_vertices.size());
771-
for (int j = 0; j < polygon_vertices.size(); j++) {
772-
tp[j] = polygon_vertices[j];
769+
tp[j] = Vector2(static_cast<real_t>(polypath_point.x), static_cast<real_t>(polypath_point.y));
770+
++j;
773771
}
774772

775773
if (p_polypath_item->IsHole()) {
@@ -842,87 +840,79 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
842840
return;
843841
}
844842

845-
if (p_navigation_mesh->get_outline_count() == 0 && !p_source_geometry_data->has_data()) {
846-
return;
847-
}
848-
849-
int outline_count = p_navigation_mesh->get_outline_count();
850-
851-
Vector<Vector<Vector2>> traversable_outlines;
852-
Vector<Vector<Vector2>> obstruction_outlines;
853-
Vector<NavigationMeshSourceGeometryData2D::ProjectedObstruction> projected_obstructions;
854-
855-
p_source_geometry_data->get_data(
856-
traversable_outlines,
857-
obstruction_outlines,
858-
projected_obstructions);
859-
860-
if (outline_count == 0 && traversable_outlines.size() == 0) {
861-
return;
862-
}
863-
864843
using namespace Clipper2Lib;
865-
866844
PathsD traversable_polygon_paths;
867845
PathsD obstruction_polygon_paths;
846+
int obstruction_polygon_path_size = 0;
847+
{
848+
RWLockRead read_lock(p_source_geometry_data->geometry_rwlock);
868849

869-
traversable_polygon_paths.reserve(outline_count + traversable_outlines.size());
870-
obstruction_polygon_paths.reserve(obstruction_outlines.size());
850+
const Vector<Vector<Vector2>> &traversable_outlines = p_source_geometry_data->traversable_outlines;
851+
int outline_count = p_navigation_mesh->get_outline_count();
871852

872-
for (int i = 0; i < outline_count; i++) {
873-
const Vector<Vector2> &traversable_outline = p_navigation_mesh->get_outline(i);
874-
PathD subject_path;
875-
subject_path.reserve(traversable_outline.size());
876-
for (const Vector2 &traversable_point : traversable_outline) {
877-
const PointD &point = PointD(traversable_point.x, traversable_point.y);
878-
subject_path.push_back(point);
853+
if (outline_count == 0 && (!p_source_geometry_data->has_data() || (traversable_outlines.is_empty()))) {
854+
return;
879855
}
880-
traversable_polygon_paths.push_back(subject_path);
881-
}
882856

883-
for (const Vector<Vector2> &traversable_outline : traversable_outlines) {
884-
PathD subject_path;
885-
subject_path.reserve(traversable_outline.size());
886-
for (const Vector2 &traversable_point : traversable_outline) {
887-
const PointD &point = PointD(traversable_point.x, traversable_point.y);
888-
subject_path.push_back(point);
889-
}
890-
traversable_polygon_paths.push_back(subject_path);
891-
}
857+
const Vector<Vector<Vector2>> &obstruction_outlines = p_source_geometry_data->obstruction_outlines;
858+
const Vector<NavigationMeshSourceGeometryData2D::ProjectedObstruction> &projected_obstructions = p_source_geometry_data->_projected_obstructions;
859+
860+
traversable_polygon_paths.reserve(outline_count + traversable_outlines.size());
861+
obstruction_polygon_paths.reserve(obstruction_outlines.size());
892862

893-
for (const Vector<Vector2> &obstruction_outline : obstruction_outlines) {
894-
PathD clip_path;
895-
clip_path.reserve(obstruction_outline.size());
896-
for (const Vector2 &obstruction_point : obstruction_outline) {
897-
const PointD &point = PointD(obstruction_point.x, obstruction_point.y);
898-
clip_path.push_back(point);
863+
for (int i = 0; i < outline_count; i++) {
864+
const Vector<Vector2> &traversable_outline = p_navigation_mesh->get_outline(i);
865+
PathD subject_path;
866+
subject_path.reserve(traversable_outline.size());
867+
for (const Vector2 &traversable_point : traversable_outline) {
868+
subject_path.emplace_back(traversable_point.x, traversable_point.y);
869+
}
870+
traversable_polygon_paths.push_back(std::move(subject_path));
899871
}
900-
obstruction_polygon_paths.push_back(clip_path);
901-
}
902872

903-
if (!projected_obstructions.is_empty()) {
904-
for (const NavigationMeshSourceGeometryData2D::ProjectedObstruction &projected_obstruction : projected_obstructions) {
905-
if (projected_obstruction.carve) {
906-
continue;
873+
for (const Vector<Vector2> &traversable_outline : traversable_outlines) {
874+
PathD subject_path;
875+
subject_path.reserve(traversable_outline.size());
876+
for (const Vector2 &traversable_point : traversable_outline) {
877+
subject_path.emplace_back(traversable_point.x, traversable_point.y);
907878
}
908-
if (projected_obstruction.vertices.is_empty() || projected_obstruction.vertices.size() % 2 != 0) {
909-
continue;
879+
traversable_polygon_paths.push_back(std::move(subject_path));
880+
}
881+
882+
if (!projected_obstructions.is_empty()) {
883+
for (const NavigationMeshSourceGeometryData2D::ProjectedObstruction &projected_obstruction : projected_obstructions) {
884+
if (projected_obstruction.carve) {
885+
continue;
886+
}
887+
if (projected_obstruction.vertices.is_empty() || projected_obstruction.vertices.size() % 2 != 0) {
888+
continue;
889+
}
890+
891+
PathD clip_path;
892+
clip_path.reserve(projected_obstruction.vertices.size() / 2);
893+
for (int i = 0; i < projected_obstruction.vertices.size() / 2; i++) {
894+
clip_path.emplace_back(projected_obstruction.vertices[i * 2], projected_obstruction.vertices[i * 2 + 1]);
895+
}
896+
if (!IsPositive(clip_path)) {
897+
std::reverse(clip_path.begin(), clip_path.end());
898+
}
899+
obstruction_polygon_paths.push_back(std::move(clip_path));
910900
}
901+
}
911902

903+
obstruction_polygon_path_size = obstruction_polygon_paths.size();
904+
for (const Vector<Vector2> &obstruction_outline : obstruction_outlines) {
912905
PathD clip_path;
913-
clip_path.reserve(projected_obstruction.vertices.size() / 2);
914-
for (int i = 0; i < projected_obstruction.vertices.size() / 2; i++) {
915-
const PointD &point = PointD(projected_obstruction.vertices[i * 2], projected_obstruction.vertices[i * 2 + 1]);
916-
clip_path.push_back(point);
917-
}
918-
if (!IsPositive(clip_path)) {
919-
std::reverse(clip_path.begin(), clip_path.end());
906+
clip_path.reserve(obstruction_outline.size());
907+
for (const Vector2 &obstruction_point : obstruction_outline) {
908+
clip_path.emplace_back(obstruction_point.x, obstruction_point.y);
920909
}
921-
obstruction_polygon_paths.push_back(clip_path);
910+
obstruction_polygon_paths.push_back(std::move(clip_path));
922911
}
923912
}
924913

925914
Rect2 baking_rect = p_navigation_mesh->get_baking_rect();
915+
PathsD area_obstruction_polygon_paths;
926916
if (baking_rect.has_area()) {
927917
Vector2 baking_rect_offset = p_navigation_mesh->get_baking_rect_offset();
928918

@@ -934,48 +924,27 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
934924
RectD clipper_rect = RectD(rect_begin_x, rect_begin_y, rect_end_x, rect_end_y);
935925

936926
traversable_polygon_paths = RectClip(clipper_rect, traversable_polygon_paths);
937-
obstruction_polygon_paths = RectClip(clipper_rect, obstruction_polygon_paths);
927+
area_obstruction_polygon_paths = RectClip(clipper_rect, obstruction_polygon_paths);
928+
} else {
929+
area_obstruction_polygon_paths = obstruction_polygon_paths;
938930
}
939931

940-
PathsD path_solution;
941-
942932
// first merge all traversable polygons according to user specified fill rule
943933
PathsD dummy_clip_path;
944934
traversable_polygon_paths = Union(traversable_polygon_paths, dummy_clip_path, FillRule::NonZero);
945935
// merge all obstruction polygons, don't allow holes for what is considered "solid" 2D geometry
946-
obstruction_polygon_paths = Union(obstruction_polygon_paths, dummy_clip_path, FillRule::NonZero);
936+
area_obstruction_polygon_paths = Union(area_obstruction_polygon_paths, dummy_clip_path, FillRule::NonZero);
947937

948-
path_solution = Difference(traversable_polygon_paths, obstruction_polygon_paths, FillRule::NonZero);
938+
PathsD path_solution = Difference(traversable_polygon_paths, area_obstruction_polygon_paths, FillRule::NonZero);
949939

950940
real_t agent_radius_offset = p_navigation_mesh->get_agent_radius();
951941
if (agent_radius_offset > 0.0) {
952942
path_solution = InflatePaths(path_solution, -agent_radius_offset, JoinType::Miter, EndType::Polygon);
953943
}
954944

955-
if (!projected_obstructions.is_empty()) {
956-
obstruction_polygon_paths.resize(0);
957-
for (const NavigationMeshSourceGeometryData2D::ProjectedObstruction &projected_obstruction : projected_obstructions) {
958-
if (!projected_obstruction.carve) {
959-
continue;
960-
}
961-
if (projected_obstruction.vertices.is_empty() || projected_obstruction.vertices.size() % 2 != 0) {
962-
continue;
963-
}
964-
965-
PathD clip_path;
966-
clip_path.reserve(projected_obstruction.vertices.size() / 2);
967-
for (int i = 0; i < projected_obstruction.vertices.size() / 2; i++) {
968-
const PointD &point = PointD(projected_obstruction.vertices[i * 2], projected_obstruction.vertices[i * 2 + 1]);
969-
clip_path.push_back(point);
970-
}
971-
if (!IsPositive(clip_path)) {
972-
std::reverse(clip_path.begin(), clip_path.end());
973-
}
974-
obstruction_polygon_paths.push_back(clip_path);
975-
}
976-
if (obstruction_polygon_paths.size() > 0) {
977-
path_solution = Difference(path_solution, obstruction_polygon_paths, FillRule::NonZero);
978-
}
945+
if (obstruction_polygon_path_size > 0) {
946+
obstruction_polygon_paths.resize(obstruction_polygon_path_size);
947+
path_solution = Difference(path_solution, obstruction_polygon_paths, FillRule::NonZero);
979948
}
980949

981950
//path_solution = RamerDouglasPeucker(path_solution, 0.025); //
@@ -994,41 +963,19 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
994963
path_solution = RectClip(clipper_rect, path_solution);
995964
}
996965

997-
Vector<Vector<Vector2>> new_baked_outlines;
998-
999-
for (const PathD &scaled_path : path_solution) {
1000-
Vector<Vector2> polypath;
1001-
for (const PointD &scaled_point : scaled_path) {
1002-
polypath.push_back(Vector2(static_cast<real_t>(scaled_point.x), static_cast<real_t>(scaled_point.y)));
1003-
}
1004-
new_baked_outlines.push_back(polypath);
1005-
}
1006-
1007-
if (new_baked_outlines.size() == 0) {
966+
if (path_solution.size() == 0) {
1008967
p_navigation_mesh->clear();
1009968
return;
1010969
}
1011970

1012-
PathsD polygon_paths;
1013-
polygon_paths.reserve(new_baked_outlines.size());
1014-
1015-
for (const Vector<Vector2> &baked_outline : new_baked_outlines) {
1016-
PathD polygon_path;
1017-
for (const Vector2 &baked_outline_point : baked_outline) {
1018-
const PointD &point = PointD(baked_outline_point.x, baked_outline_point.y);
1019-
polygon_path.push_back(point);
1020-
}
1021-
polygon_paths.push_back(polygon_path);
1022-
}
1023-
1024971
ClipType clipper_cliptype = ClipType::Union;
1025972

1026973
List<TPPLPoly> tppl_in_polygon, tppl_out_polygon;
1027974

1028975
PolyTreeD polytree;
1029976
ClipperD clipper_D;
1030977

1031-
clipper_D.AddSubject(polygon_paths);
978+
clipper_D.AddSubject(path_solution);
1032979
clipper_D.Execute(clipper_cliptype, FillRule::NonZero, polytree);
1033980

1034981
for (size_t i = 0; i < polytree.Count(); i++) {

scene/resources/2d/navigation_mesh_source_geometry_data_2d.h

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
#include "scene/resources/2d/navigation_polygon.h"
3737

3838
class NavigationMeshSourceGeometryData2D : public Resource {
39+
friend class NavMeshGenerator2D;
40+
3941
GDCLASS(NavigationMeshSourceGeometryData2D, Resource);
4042
RWLock geometry_rwlock;
4143

0 commit comments

Comments
 (0)