Browse Source

Add ability to `bake_navigation_mesh` off thread.

This feature makes it possible to workaround problems such as:
 - long baking time due to heavy synchronization when parsing geometry
   from mesh instances
 - crash when freeing `NavigationMeshInstance` while baking
 - errors when actively baking node tree is being detached from the
   scene tree
Pawel Lampe 3 years ago
parent
commit
88d3f14697

+ 2 - 1
doc/classes/NavigationRegion3D.xml

@@ -12,8 +12,9 @@
 	<methods>
 		<method name="bake_navigation_mesh">
 			<return type="void" />
+			<argument index="0" name="on_thread" type="bool" default="true" />
 			<description>
-				Bakes the [NavigationMesh]. The baking is done in a separate thread because navigation baking is not a cheap operation. This can be done at runtime. When it is completed, it automatically sets the new [NavigationMesh].
+				Bakes the [NavigationMesh]. If [code]on_thread[/code] is set to [code]true[/code] (default), the baking is done on a separate thread. Baking on separate thread is useful because navigation baking is not a cheap operation. When it is completed, it automatically sets the new [NavigationMesh]. Please note that baking on separate thread may be very slow if geometry is parsed from meshes as async access to each mesh involves heavy synchronization.
 			</description>
 		</method>
 		<method name="get_region_rid" qualifiers="const">

+ 7 - 3
scene/3d/navigation_region_3d.cpp

@@ -165,13 +165,17 @@ void _bake_navigation_mesh(void *p_user_data) {
 	}
 }
 
-void NavigationRegion3D::bake_navigation_mesh() {
+void NavigationRegion3D::bake_navigation_mesh(bool p_on_thread) {
 	ERR_FAIL_COND_MSG(bake_thread.is_started(), "Unable to start another bake request. The navigation mesh bake thread is already baking a navigation mesh.");
 
 	BakeThreadsArgs *args = memnew(BakeThreadsArgs);
 	args->nav_region = this;
 
-	bake_thread.start(_bake_navigation_mesh, args);
+	if (p_on_thread) {
+		bake_thread.start(_bake_navigation_mesh, args);
+	} else {
+		_bake_navigation_mesh(args);
+	}
 }
 
 void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
@@ -204,7 +208,7 @@ void NavigationRegion3D::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion3D::get_region_rid);
 
-	ClassDB::bind_method(D_METHOD("bake_navigation_mesh"), &NavigationRegion3D::bake_navigation_mesh);
+	ClassDB::bind_method(D_METHOD("bake_navigation_mesh", "on_thread"), &NavigationRegion3D::bake_navigation_mesh, DEFVAL(true));
 	ClassDB::bind_method(D_METHOD("_bake_finished", "nav_mesh"), &NavigationRegion3D::_bake_finished);
 
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh");

+ 2 - 2
scene/3d/navigation_region_3d.h

@@ -62,9 +62,9 @@ public:
 	void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh);
 	Ref<NavigationMesh> get_navigation_mesh() const;
 
-	/// Bakes the navigation mesh in a dedicated thread; once done, automatically
+	/// Bakes the navigation mesh; once done, automatically
 	/// sets the new navigation mesh and emits a signal
-	void bake_navigation_mesh();
+	void bake_navigation_mesh(bool p_on_thread);
 	void _bake_finished(Ref<NavigationMesh> p_nav_mesh);
 
 	TypedArray<String> get_configuration_warnings() const override;