# 3D Navigation SimVX provides 3D navigation mesh pathfinding through `NavigationMesh3D`, a server/agent architecture, and dynamic obstacle avoidance. ## NavigationMesh3D Defines walkable geometry as triangles and performs A* pathfinding over the triangle adjacency graph. ### Manual Construction ```python from simvx.core import NavigationMesh3D, Vec3 navmesh = NavigationMesh3D() # Add walkable triangles navmesh.add_triangle(Vec3(0, 0, 0), Vec3(10, 0, 0), Vec3(10, 0, 10)) navmesh.add_triangle(Vec3(0, 0, 0), Vec3(10, 0, 10), Vec3(0, 0, 10)) # Or add polygons (auto-triangulated via fan) navmesh.add_polygon([Vec3(20, 0, 0), Vec3(30, 0, 0), Vec3(30, 0, 10), Vec3(20, 0, 10)]) path = navmesh.find_path(Vec3(1, 0, 1), Vec3(25, 0, 5)) # Returns list of Vec3 waypoints, or [] if unreachable ``` ### Baking from Level Geometry Generate a navmesh automatically from mesh data using a Recast-style voxelization pipeline: ```python import numpy as np vertices = np.array([...], dtype=np.float32) # (N, 3) mesh vertices indices = np.array([...], dtype=np.int32) # (M, 3) triangle indices navmesh.bake_from_geometry( vertices, indices, agent_radius=0.5, # capsule radius for erosion agent_height=2.0, # minimum clearance max_slope=45.0, # walkable slope limit (degrees) cell_size=0.3, # horizontal voxel size cell_height=0.2, # vertical voxel size ) ``` ### Spatial Queries ```python # Snap a point to the nearest navmesh surface closest = navmesh.get_closest_point(Vec3(5, 10, 5)) # Test if a point is on the walkable area on_mesh = navmesh.is_point_on_mesh(Vec3(5, 0, 5), tolerance=0.5) # Sample a random walkable point near a position pos = navmesh.sample_position(Vec3(5, 0, 5), radius=10.0) ``` ## NavigationServer3D Singleton that manages all navigation regions and provides unified pathfinding across them. ```python from simvx.core import NavigationServer3D server = NavigationServer3D.get_singleton() # Find path across all active regions path = server.find_path(Vec3(0, 0, 0), Vec3(50, 0, 50)) # Snap to closest point on any navmesh closest = server.get_closest_point(Vec3(25, 5, 25)) ``` ## NavigationRegion3D A scene node that holds a `NavigationMesh3D` and auto-registers it with the server when added to the tree. ```python from simvx.core import NavigationRegion3D, NavigationMesh3D navmesh = NavigationMesh3D() # ... populate navmesh ... region = NavigationRegion3D(navigation_mesh=navmesh) scene.add_child(region) # Auto-registers with NavigationServer3D region.enabled = False # Temporarily exclude from pathfinding ``` ## NavigationAgent3D Pathfinding agent that follows paths on the navigation mesh with automatic steering and obstacle avoidance. Attach as a child of the node you want to move. ```python from simvx.core import NavigationAgent3D, Node3D, Vec3 class Enemy(Node3D): def ready(self): self.agent = NavigationAgent3D() self.agent.max_speed = 8.0 self.agent.avoidance_radius = 0.6 self.agent.navigation_finished.connect(self._on_arrived) self.add_child(self.agent) self.agent.target_position = Vec3(50, 0, 50) def physics_process(self, dt): if not self.agent.is_navigation_finished(): self.position += self.agent.velocity * dt def _on_arrived(self): print("Reached destination!") ``` ### Settings | Setting | Default | Description | |---------|---------|-------------| | `max_speed` | `10.0` | Maximum movement speed | | `path_desired_distance` | `1.0` | Distance to waypoint before advancing | | `target_desired_distance` | `1.0` | Distance to target to consider reached | | `avoidance_radius` | `0.5` | Radius for obstacle avoidance | ### Signals - **`navigation_finished`** -- Emitted when the agent reaches its target. ## NavigationObstacle3D Dynamic obstacle that agents steer around at runtime. Does not carve the navmesh -- agents detect obstacles and adjust their velocity. ```python from simvx.core import NavigationObstacle3D obstacle = NavigationObstacle3D() obstacle.radius = 2.0 obstacle.height = 3.0 scene.add_child(obstacle) # Auto-registers with server ``` ## API Reference See {py:mod}`simvx.core.navigation3d` for the complete 3D navigation API.