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¶
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:
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¶
# 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.
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.
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.
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 |
|---|---|---|
|
|
Maximum movement speed |
|
|
Distance to waypoint before advancing |
|
|
Distance to target to consider reached |
|
|
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.
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 simvx.core.navigation3d for the complete 3D navigation API.