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

Navmesh baking optimization #451

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Dekker3D
Copy link
Contributor

This PR should cut down navigation mesh baking time by about half. Terrain3D::_generate_triangle_pair uses fewer control map lookups (-6 when p_require_nav is false, -2 if true), and Terrain3DStorage::get_pixel uses a modified private version of get_map_region that returns an Image* and skips converting it to a godot::Ref, reducing the time spent on get_pixel by about 1/3rd. This is based on the assumption that nobody will put anything other than godot::Image in the height/control/color map arrays, which should be true because they're TypedArrays and they're not directly accessible from outside the extension.

The modified version of get_map_region introduces some code duplication, and it might be good to use this modified version in other places where a Ref really isn't needed, so this PR isn't as clean as it perhaps could've been. I'm personally unlikely to even use it in my project, as it should be much faster to just directly sample the physics shapes I'm making, which can also be generated in a thread, unlike Terrain3D.

… though it doesn't make a big difference here), avoid 6 control map lookups when generating triangles if p_require_nav is false, and 2 lookups if true.
…d casting them to Image*, instead of wrapping in a godot::Ref.
return nullptr;
}
}

Ref<Image> Terrain3DStorage::get_map_region(const MapType p_map_type, const int p_region_index) const {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not remove the code redundancy by having this function call the other?
This builds, but I didn't test it. And it could be done inline.

Image *Terrain3DStorage::_get_map_region_ptr(const MapType p_map_type, const int p_region_index) const {
	return (Image *)&(_height_maps[p_region_index]);
}

Ref<Image> Terrain3DStorage::get_map_region(const MapType p_map_type, const int p_region_index) const {
	return _get_map_region_ptr(p_map_type, p_region_index);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly because I am not entirely sure yet what my version does. Having one function call the other might mean having a redundant cast (not that big a deal, since it should really only be for calls from outside the extension), or messing up the reference counting somehow (pretty big deal, seems kinda unlikely, not 100% sure).

@TokisanGames
Copy link
Owner

get_map_region has been dropped. You can see here in set/get_pixel how the general API focus is changing towards selecting regions by location (fixed) rather than ids (mutable) and working with Regions. So the ptr function probably needs to be moved to Terrain3DRegion.

6d77480#diff-f5a6479fa5fc2f89383edd16b70ed900e9b288af17f42366f3ac1bdb5a19306a

Although we are keeping the typedarrays referenced by ID, which are updated by update_maps, and then sent to the shader. So if more optimal we could undo these changes to set/get_pixel and reference the maps directly bypassing regions and refs.

Read the comments here

/////////
// Terrain3DRegions house the maps, instances, and other data for each region.
// Regions are dual indexed:
// 1) By `region_location:Vector2i` as the primary key. This is the only stable index
// so should be the main index for users.
// 2) By `region_id:int`. This index changes on every add/remove, depends on load order,
// and is not stable. It should not be relied on by users and is primarily for internal use.
// `_regions` stores all loaded Terrain3DRegions, indexed by region_location.
// Inactive regions are those marked for deletion.
Dictionary _regions; // Dict[region_location:Vector2i] -> Terrain3DRegion
// All _active_ region maps are maintained in secondary indices. These arrays provide
// direct access to maps in the regions, indexed by region_id. These arrays are converted
// to TextureArrays for the shader.
TypedArray<Vector2i> _region_locations;
TypedArray<Image> _height_maps;
TypedArray<Image> _control_maps;
TypedArray<Image> _color_maps;
// Editing occurs on the Image arrays above, which are converted to Texture arrays
// below for the shader.
// 16x16 grid with region_id:int at its location, no region = 0, region_ids >= 1
PackedInt32Array _region_map;
bool _region_map_dirty = true;
// These contain the TextureArray RIDs from the RenderingServer
GeneratedTexture _generated_height_maps;
GeneratedTexture _generated_control_maps;
GeneratedTexture _generated_color_maps;

I'd recommend just waiting until I finish my PR before spending any more time on it, but wanted to share the information to get you thinking about it.

@TokisanGames
Copy link
Owner

Now that my PRs are merged in, let's revisit this and look at optimizing set_pixel, get_pixel and refs.

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.

2 participants