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 makeshift baker #176

Closed
wants to merge 3 commits into from

Conversation

SlashScreen
Copy link
Contributor

No description provided.

@TokisanGames
Copy link
Owner

Can you post instructions for use here so I can set it up in the wiki?
Thanks.

@SlashScreen
Copy link
Contributor Author

SlashScreen commented Aug 6, 2023

Here are the instructions:
Terrain3D does not yet have a proper implementation for navmeshing and colliders. However, there is a workaround solution- a multithreaded navigation baker that will bake the entire terrain at once. Here's how to use it:

  1. Create a ChunkBaker node, and place all of the geometry you want to be included in the bake as children underneath it, like you would a regular NavigationRegion3D. This includes the terrain you wish to bake.
  2. Provide a template navmesh resource. Set it up as you would any conventional bake, apart from a few settings:
  • In Geometry > Parsed Geometry Type, select Static Colliders or Both.
  • In Filters > Baking AABB, change the w, h, and d values to select the size of the chunks that will be baked. Only the w and d values matter, but the h value should be tall enough to encompass the entire height of your terrain. The larger the chunk size, the more time it will take for each chunk to bake, but longer each chunk will take. A good starting point is (128, 512, 128).
  1. Provide the rest of the settings.
  • Bake Path: This is the folder where it will dump the baked navmesh once complete.
  • Terrain: This a reference to the terrain node you want to bake.
  • Bake Region: This is the region (Large square you can add in the terrain menu) you want to bake, referred to by index. -1 will bake all regions. Index 0 is the center.
  • Pretty Print: Bake progress will be printed in a fancy way into the output as the bake progresses. Godot will rarely be running smooth enough to watch this go by in-editor, however, so if you want to save the processing time required to print, you can safely turn it off.
  1. After making sure the debug collidion on your Terrain3D is turned on, hit the "Bake terrain navigation" button at the top. Godot will freeze for a bit as the scene geometry is parsed on the main thread. Then, your computer will become barely usable for a few minutes, as all cores will be maxed to get the bake done as soon as possible. On an 8 core Ryzen 7 5800X, one region of high complexity took 10-30. Each region is done sequentially, so bake time scales linearly with regions. Godot will become unstable during the bake.
  2. Once the bake is finished, It has created a resource file in your bake path. This is a large bundle of the navmeshes your chunks have created. There is no need to include this in an exported game.
  3. Create a NavmeshBundleUnpacker node in your scene, It requires one resource: the bundle you just created. Assign it to the node, and hit "Unpack". After some time, you will find it has created a small army of NavigationRegion3Ds, each corresponding to a baked chunk. Your terrain navmesh is now in the scene. You bundle is no longer necessary to keep, if you don't want to.

The baking process is now complete. Congrats!

@aclave1
Copy link

aclave1 commented Sep 6, 2023

I used this PR in my project to bake terrain and it works great!

For future devs: I am making an RTS and needed to rebake certain chunks whenever I place down a building. Here's the script that I used when the building is placed:

edit: new faster solution. the previous solution would consider the whole terrain mesh, this rebakes one chunk.
This parses the navmesh once and stores it as a hidden meshinstance node for future rebakes. This prevents multiple rebakes continuously shrinking the navmesh. If there's a better runtime rebake strategy please let me know but this one is working okay for me.

func _add_node_to_terrain_nav(node:Node3D, pos):
	var navmesh_bundle_unpacker = get_tree().get_nodes_in_group("navmesh_bundle_unpacker")[0]
#	var chunk_baker = get_tree().get_nodes_in_group("chunk_baker")[0]
	pos.y = max(pos.y, 0) # bake aabb starts at y=0
	# find nav region where node should live
	for r in navmesh_bundle_unpacker.get_children():
		var region = r as NavigationRegion3D
		var nm:NavigationMesh = region.navigation_mesh.duplicate()
		var aabb = AABB(nm.filter_baking_aabb_offset, nm.filter_baking_aabb.size)
		if aabb.has_point(pos):
			var navmesh_geometry:MeshInstance3D = r.get_node("navmesh_geometry")
			if navmesh_geometry == null:
				var arr_mesh = ArrayMesh.new()
				var arrays = []
				arrays.resize(Mesh.ARRAY_MAX)
				arrays[Mesh.ARRAY_VERTEX] = nm.get_vertices()
				var indices = PackedInt32Array()
				for pid in nm.get_polygon_count():
					var poly = nm.get_polygon(pid)
					for p in poly:
						indices.append(p)
				arrays[Mesh.ARRAY_INDEX] = indices
				# Create the Mesh.
				arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
				navmesh_geometry = MeshInstance3D.new()
				navmesh_geometry.mesh = arr_mesh
				navmesh_geometry.global_position = navmesh_geometry.global_position + Vector3(0,-0.5,0) # offset it down to make it intersect
				navmesh_geometry.name = "navmesh_geometry"
				navmesh_geometry.visible = false
				region.add_child(navmesh_geometry)
			region.add_child(node)
			region.bake_navigation_mesh()

Old slow solution

for region in navmesh_bundle_unpacker.get_children():
	var r = region as NavigationRegion3D
	var nm = r.navigation_mesh.duplicate()
	var aabb = AABB(nm.filter_baking_aabb_offset, nm.filter_baking_aabb.size)
        # find the chunk corresponding to the building location
	if aabb.has_point(transform.origin):
		chunk_baker.add_child(building)
		var parsed_geometry = NavigationMeshSourceGeometryData3D.new()
		NavigationMeshGenerator.parse_source_geometry_data(nm, parsed_geometry, chunk_baker, func(): 
			NavigationMeshGenerator.bake_from_source_geometry_data(nm, parsed_geometry, func():
				r.navigation_mesh = nm
			)
		)

@TokisanGames
Copy link
Owner

Superseded by #253 which has been merged. Thanks for the initial work. I'll credit you both in the release notes.

@SlashScreen
Copy link
Contributor Author

Good, nobody has to use it anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants