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

New operator that generates navmesh for selected objects #194

Closed
wants to merge 5 commits into from

Conversation

theanine3D
Copy link
Contributor

This PR adds a new operator ("Generate Hubs Navigation Mesh") to the addon. The operator is accessible via the 3D viewport's "Object" menu while a mesh object is selected in object mode.

The operator is pretty straightforward - it makes a bmesh copy of the original object, checks the normals of all the faces, and then removes any that are too steep to walk on. Then it cleans up the result a bit (limited dissolve, triangulate, remove loose verts). The result is a lower-poly, more optimized mesh than the original model.

The operator is fast and creates an instant result to work with. In many cases the result needs only minimal editing afterward. The operator also adds the navmesh Hubs component to the newly generated object as well.

navmesh-gen-1

It currently has one limitation - it currently fails at generating connected staircase slopes, because the operator removes any steep faces, including the 90 degree vertical geometry in stairs. It will correctly grab the top (flat) face of each stair, but it won't connect them, so the user will still need to edit the navmesh afterward in edge cases like that. See GIF below. However, it only takes a few seconds of manual editing to turn these unconnected faces into a usable navmesh slope.

stair-example

At the moment, the operator also adds a new material to the resulting navmesh object (if the material doesn't already exist), with a bright neon pink color, to make it easy to distinguish the navmesh in the 3D viewport from the original object. I added this functionality because otherwise it's too easy to accidentally select the original object when you're trying to edit your navmesh afterward. I tried to pick a color that is less likely to already be present in most scenes. Because navmeshes aren't actually rendered once exported to Hubs, the navmesh material is just there to make editing in Blender easier, with hopefully no impact to performance.

Copy link
Contributor

@keianhzo keianhzo left a comment

Choose a reason for hiding this comment

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

This looks really good! Thanks for the contribution. I have left a couple of comments. We can keep the discussion open here to refine this.

Regarding the slope issue, I wonder if we could get around it playing with modifiers. Something like, apply a solidify modifier and then a remesh "voxel" modifier. If we combine that with removing faces that have an object in the +z direction of the face at a certain distance we could get something quite accurate.

In the future would be nice to have full navmesh support binding to a navmesh generation library like https://github.com/recastnavigation/recastnavigation

@@ -188,6 +188,7 @@ def object_menu_addition(self, context):
layout = self.layout
layout.separator()
op = layout.operator("wm.migrate_hubs_components")
op = layout.operator("object.generate_hubs_navmesh")
op.is_registration = False
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe this setting belongs to the previous operator.

return {'FINISHED'}

bm = bmesh.new()
bm.from_mesh(obj.data)
Copy link
Contributor

@keianhzo keianhzo Feb 24, 2023

Choose a reason for hiding this comment

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

You probably need to apply transforms here so the actual geometry is transformed. Something like this but on the mesh copy:

        bpy.ops.object.transform_apply(location=False, rotation=True, scale=True)

Copy link
Contributor

@keianhzo keianhzo Feb 24, 2023

Choose a reason for hiding this comment

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

It could be useful to convert a copy to the object to mesh and applying the modifiers. The user probably expects the nav-mesh generation to happen on the resulting mesh and this would also add supports for other convertible objects like surfaces, metaballs or anything generated with geometry nodes.

def execute(self, context):
import bmesh

obj = bpy.context.active_object
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be great if we can generate a nav mesh from multiple selected objects instead of only the active one

Fixed generate_hubs_navmesh operator menu lines.
Updated GenerateNavMesh operator to support generation from multiple selected objects, as well as support for multi-user objects.
@theanine3D theanine3D reopened this Mar 26, 2023
Removed unneeded lines for adding the nav object to a collection, which was causing an error in GenerateNavMesh operator.
Added preliminary code for solidify / remesh algorithm, but left it commented. If uncommented, the modifier combination produces an unsatisfactory result, with gaps in the resulting mesh. Code needs refining.
@theanine3D
Copy link
Contributor Author

theanine3D commented Mar 26, 2023

I've implemented all of the above requested changes/suggestions. (I also updated/synced the code with the latest Hubs addon release.) However, the solidify / remesh combination has issues.

I added code for it but my tests with the Remesh modifier did not produce satisfactory results. So I left that part of the code commented. You can uncomment lines 493-495, 499-502, and 506-512, if you'd like to play around with it and see if maybe you can get a better result. My tests kept resulting in missing faces, large gaps in the resulting model, large chunks of stairs still missing, etc. It also made the operator severely, drastically slower.

All the other code changes work fine though. The updated code now supports generating 1 navmesh from multiple selected objects. The transforms are applied beforehand as well, and if any objects are multi-user objects, they're forced to become single-user before transforms are applied.

I also added a remove doubles operation that now results in a navmesh with some parts of the stairs in the final result. There's still usually some missing pieces, but only a minimal amount of work is needed to manually connect the pieces together in Edit mode. See example below:

image

Because there are so many different types of scenes, it would be beneficial to have some sort of UI panel where users can tweak the settings used by the operator. Right now the remove doubles line in the operator will merge by a distance of 1.0 meter, but that might not work for all scenes. It just happened to be what worked on my test scene. But as of now, users have no way of changing that distance without changing the code itself (specifically, line 546 in operators.py)

@theanine3D theanine3D changed the title New operator that generates navmesh for active object New operator that generates navmesh for selected objects Mar 26, 2023
@netpro2k
Copy link
Contributor

In the future would be nice to have full navmesh support binding to a navmesh generation library like https://github.com/recastnavigation/recastnavigation

It used to be integrated into Blender pre 2.8 for blender game engine. This addon backports that integration: https://github.com/przemir/RecastBlenderAddon. Jim tried it out and had pretty good results.

It's slightly clunky to set up, and currently recast binaries are only provided for windows (I managed to compile them for my linux machine as well and it worked), but this seems like a really good path (no pun intended) to navmesh generation in Blender.

@keianhzo
Copy link
Contributor

Humm I didn't know that that addon already existed, I missed that in my search. but this works pretty good and it's not hard to set up. Might be good to give this a try to provide a fully functional solution.

@theanine3D theanine3D closed this Mar 28, 2023
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.

None yet

3 participants