simvx.core.navigation3d¶
3D navigation mesh system — navmesh generation, A* pathfinding, agents, obstacles.
Provides NavigationMesh3D for defining walkable surfaces, NavigationServer3D as a singleton coordinator, NavigationAgent3D for autonomous path-following, and NavigationObstacle3D for dynamic obstacle avoidance.
Module Contents¶
Classes¶
3D navigation mesh with triangle-based A* pathfinding. |
|
Global navigation server that manages all registered navigation regions. |
|
Node that holds a NavigationMesh3D and registers it with the server. |
|
3D pathfinding agent that follows paths on the navigation mesh. |
|
Dynamic obstacle that affects navigation agent avoidance. |
Data¶
API¶
- simvx.core.navigation3d.__all__¶
[‘NavigationMesh3D’, ‘NavigationRegion3D’, ‘NavigationAgent3D’, ‘NavigationServer3D’, ‘NavigationObs…
- class simvx.core.navigation3d.NavigationMesh3D[source]¶
3D navigation mesh with triangle-based A* pathfinding.
Stores walkable geometry as triangles and builds an adjacency graph for pathfinding. Supports manual polygon insertion and automated bake from level geometry.
Initialization
- property vertices: numpy.ndarray¶
(N, 3) float32 array of mesh vertices.
- property triangles: numpy.ndarray¶
(M, 3) int32 array of triangle vertex indices.
- property triangle_count: int¶
- add_polygon(vertices: list[simvx.core.math.types.Vec3], cell_size: float = 0.0) → None[source]¶
Add a walkable polygon.
Without
cell_sizethe polygon is fan-triangulated from the first vertex (fast, 2 triangles for a quad). Whencell_sizeis positive the polygon’s axis-aligned bounding box is subdivided into a regular grid of right-triangles, keeping only cells whose centres fall inside the polygon. The finer mesh is required for obstacle carving to work at useful resolution.Args: vertices: 3+ coplanar points defining the polygon boundary. cell_size: When > 0, grid cell size for subdivision. Typical values: 0.5 – 2.0 depending on obstacle density.
- add_triangle(v0: simvx.core.math.types.Vec3, v1: simvx.core.math.types.Vec3, v2: simvx.core.math.types.Vec3) → None[source]¶
Add a single walkable triangle.
- add_obstacle(vertices: list[simvx.core.math.types.Vec3]) → None[source]¶
Subtract an obstacle region from the walkable area.
The polygon is projected onto the XZ plane. Any navmesh triangle whose centroid falls inside the obstacle polygon (or whose area overlaps it significantly) is marked as blocked and excluded from pathfinding.
Args: vertices: 3+ points defining the obstacle boundary (Y is ignored).
- bake_from_geometry(mesh_vertices: numpy.ndarray, mesh_indices: numpy.ndarray, agent_radius: float = 0.5, agent_height: float = 2.0, max_slope: float = 45.0, cell_size: float = 0.3, cell_height: float = 0.2) → None[source]¶
Generate navmesh from level geometry using simplified Recast-style algorithm.
Steps: 1. Voxelize geometry into a height field 2. Mark walkable voxels (slope < max_slope, clearance > agent_height) 3. Build regions from connected walkable areas 4. Extract contours and triangulate
Args: mesh_vertices: (N, 3) float32 array of source mesh vertices. mesh_indices: (M, 3) int32 array of triangle indices. agent_radius: Agent capsule radius for erosion. agent_height: Minimum clearance height. max_slope: Maximum walkable slope in degrees. cell_size: Horizontal voxel size. cell_height: Vertical voxel size.
- find_path(start: simvx.core.math.types.Vec3, end: simvx.core.math.types.Vec3) → list[simvx.core.math.types.Vec3][source]¶
A* pathfinding on the navmesh triangle graph.
Finds the shortest path from start to end by searching through connected triangles. Returns a list of waypoints (triangle centroids + start/end) forming the path, or an empty list if no path exists.
Args: start: Start position in world space. end: End position in world space.
Returns: List of Vec3 waypoints, or empty list if unreachable.
- get_closest_point(point: simvx.core.math.types.Vec3) → simvx.core.math.types.Vec3[source]¶
Snap a point to the nearest navmesh surface.
Args: point: Query point in world space.
Returns: Closest point on the navmesh surface.
- is_point_on_mesh(point: simvx.core.math.types.Vec3, tolerance: float = 0.5) → bool[source]¶
Test if a point is on the walkable area.
Args: point: Query point in world space. tolerance: Maximum distance from navmesh surface to still count.
Returns: True if point is within tolerance of the navmesh.
- sample_position(center: simvx.core.math.types.Vec3, radius: float, max_attempts: int = 30) → simvx.core.math.types.Vec3 | None[source]¶
Sample a random point near center that lies on the navmesh.
Args: center: Center of the sampling sphere. radius: Maximum distance from center. max_attempts: Number of random samples to try.
Returns: A random point on the navmesh within radius, or None if not found.
- class simvx.core.navigation3d.NavigationServer3D[source]¶
Global navigation server that manages all registered navigation regions.
Provides unified pathfinding and spatial queries across all active regions.
Initialization
- classmethod get_singleton() → simvx.core.navigation3d.NavigationServer3D[source]¶
Return the global NavigationServer3D instance (created on first access).
- register_region(region: simvx.core.navigation3d.NavigationRegion3D) → None[source]¶
Register a navigation region.
- unregister_region(region: simvx.core.navigation3d.NavigationRegion3D) → None[source]¶
Unregister a navigation region.
- register_obstacle(obstacle: simvx.core.navigation3d.NavigationObstacle3D) → None[source]¶
Register a dynamic obstacle.
- unregister_obstacle(obstacle: simvx.core.navigation3d.NavigationObstacle3D) → None[source]¶
Unregister a dynamic obstacle.
- find_path(start: simvx.core.math.types.Vec3, end: simvx.core.math.types.Vec3) → list[simvx.core.math.types.Vec3][source]¶
Find a path from start to end across all active navigation regions.
Queries each enabled region and returns the shortest valid path found.
Args: start: Start position in world space. end: End position in world space.
Returns: List of Vec3 waypoints, or empty list if unreachable.
- get_closest_point(point: simvx.core.math.types.Vec3) → simvx.core.math.types.Vec3[source]¶
Find the closest point on any active navmesh surface.
Args: point: Query point in world space.
Returns: Closest point on any navmesh, or the input point if no regions exist.
- property obstacles: list[simvx.core.navigation3d.NavigationObstacle3D]¶
All registered dynamic obstacles.
- class simvx.core.navigation3d.NavigationRegion3D(navigation_mesh: simvx.core.navigation3d.NavigationMesh3D | None = None, **kwargs)[source]¶
Bases:
simvx.core.nodes_3d.node3d.Node3DNode that holds a NavigationMesh3D and registers it with the server.
Attach a NavigationMesh3D to this node and add it to the scene tree to make its walkable surface available for pathfinding.
Initialization
- enabled¶
‘Property(…)’
- render_layer¶
‘Property(…)’
- property position¶
- property rotation: simvx.core.math.types.Quat¶
- property scale¶
- property rotation_degrees: simvx.core.math.types.Vec3¶
- property world_position: simvx.core.math.types.Vec3¶
- property world_rotation: simvx.core.math.types.Quat¶
- property world_scale: simvx.core.math.types.Vec3¶
- property forward: simvx.core.math.types.Vec3¶
- property right: simvx.core.math.types.Vec3¶
- property up: simvx.core.math.types.Vec3¶
- translate(offset: tuple[float, float, float] | numpy.ndarray)¶
- translate_global(offset: tuple[float, float, float] | numpy.ndarray)¶
- rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)¶
- rotate_x(angle: float)¶
- rotate_y(angle: float)¶
- rotate_z(angle: float)¶
- look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)¶
- set_render_layer(index: int, enabled: bool = True) → None¶
- is_on_render_layer(index: int) → bool¶
- wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)¶
- strict_errors: ClassVar[bool]¶
True
- script_error_raised¶
‘Signal(…)’
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property process_mode: simvx.core.descriptors.ProcessMode¶
- reset_error() → None¶
- add_child(node: simvx.core.node.Node) → simvx.core.node.Node¶
- remove_child(node: simvx.core.node.Node)¶
- reparent(new_parent: simvx.core.node.Node)¶
- get_node(path: str) → simvx.core.node.Node¶
- find_child(name: str, recursive: bool = False) → simvx.core.node.Node | None¶
- find(node_type: type, recursive: bool = True) → simvx.core.node.Node | None¶
- property path: str¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) → bool¶
- ready() → None¶
- process(dt: float) → None¶
- physics_process(dt: float) → None¶
- draw(renderer) → None¶
- input_event(event: simvx.core.events.InputEvent) → None¶
- input(event: simvx.core.events.TreeInputEvent) → None¶
- unhandled_input(event: simvx.core.events.TreeInputEvent) → None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) → simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- clear_children()¶
- destroy()¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- get_tree() → simvx.core.scene_tree.SceneTree¶
- __getitem__(key: str)¶
- classmethod get_properties() → dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶
- class simvx.core.navigation3d.NavigationAgent3D(**kwargs)[source]¶
Bases:
simvx.core.nodes_3d.node3d.Node3D3D pathfinding agent that follows paths on the navigation mesh.
Computes a path to target_position and advances along it each physics frame. Emits navigation_finished when the target is reached.
Attach as a child of a Node3D whose position you want to steer.
Initialization
- target_desired_distance¶
‘Property(…)’
- path_desired_distance¶
‘Property(…)’
- max_speed¶
‘Property(…)’
- avoidance_radius¶
‘Property(…)’
- property target_position: simvx.core.math.types.Vec3¶
- get_next_path_position() → simvx.core.math.types.Vec3[source]¶
Get the next waypoint position the agent is heading toward.
Returns: Next waypoint, or current position if path is empty.
- render_layer¶
‘Property(…)’
- property position¶
- property rotation: simvx.core.math.types.Quat¶
- property scale¶
- property rotation_degrees: simvx.core.math.types.Vec3¶
- property world_position: simvx.core.math.types.Vec3¶
- property world_rotation: simvx.core.math.types.Quat¶
- property world_scale: simvx.core.math.types.Vec3¶
- property forward: simvx.core.math.types.Vec3¶
- property right: simvx.core.math.types.Vec3¶
- property up: simvx.core.math.types.Vec3¶
- translate(offset: tuple[float, float, float] | numpy.ndarray)¶
- translate_global(offset: tuple[float, float, float] | numpy.ndarray)¶
- rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)¶
- rotate_x(angle: float)¶
- rotate_y(angle: float)¶
- rotate_z(angle: float)¶
- look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)¶
- set_render_layer(index: int, enabled: bool = True) → None¶
- is_on_render_layer(index: int) → bool¶
- wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)¶
- strict_errors: ClassVar[bool]¶
True
- script_error_raised¶
‘Signal(…)’
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property process_mode: simvx.core.descriptors.ProcessMode¶
- reset_error() → None¶
- add_child(node: simvx.core.node.Node) → simvx.core.node.Node¶
- remove_child(node: simvx.core.node.Node)¶
- reparent(new_parent: simvx.core.node.Node)¶
- get_node(path: str) → simvx.core.node.Node¶
- find_child(name: str, recursive: bool = False) → simvx.core.node.Node | None¶
- find(node_type: type, recursive: bool = True) → simvx.core.node.Node | None¶
- property path: str¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) → bool¶
- ready() → None¶
- enter_tree() → None¶
- exit_tree() → None¶
- process(dt: float) → None¶
- draw(renderer) → None¶
- input_event(event: simvx.core.events.InputEvent) → None¶
- input(event: simvx.core.events.TreeInputEvent) → None¶
- unhandled_input(event: simvx.core.events.TreeInputEvent) → None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) → simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- clear_children()¶
- destroy()¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- get_tree() → simvx.core.scene_tree.SceneTree¶
- __getitem__(key: str)¶
- classmethod get_properties() → dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶
- class simvx.core.navigation3d.NavigationObstacle3D(position=None, rotation=None, scale=None, **kwargs)[source]¶
Bases:
simvx.core.nodes_3d.node3d.Node3DDynamic obstacle that affects navigation agent avoidance.
Place in the scene tree to create areas that agents will steer around. Does not carve the navmesh — instead, agents detect obstacles at runtime and adjust their velocity to avoid collisions.
Initialization
- radius¶
‘Property(…)’
- height¶
‘Property(…)’
- render_layer¶
‘Property(…)’
- property position¶
- property rotation: simvx.core.math.types.Quat¶
- property scale¶
- property rotation_degrees: simvx.core.math.types.Vec3¶
- property world_position: simvx.core.math.types.Vec3¶
- property world_rotation: simvx.core.math.types.Quat¶
- property world_scale: simvx.core.math.types.Vec3¶
- property forward: simvx.core.math.types.Vec3¶
- property right: simvx.core.math.types.Vec3¶
- property up: simvx.core.math.types.Vec3¶
- translate(offset: tuple[float, float, float] | numpy.ndarray)¶
- translate_global(offset: tuple[float, float, float] | numpy.ndarray)¶
- rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)¶
- rotate_x(angle: float)¶
- rotate_y(angle: float)¶
- rotate_z(angle: float)¶
- look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)¶
- set_render_layer(index: int, enabled: bool = True) → None¶
- is_on_render_layer(index: int) → bool¶
- wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)¶
- strict_errors: ClassVar[bool]¶
True
- script_error_raised¶
‘Signal(…)’
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property process_mode: simvx.core.descriptors.ProcessMode¶
- reset_error() → None¶
- add_child(node: simvx.core.node.Node) → simvx.core.node.Node¶
- remove_child(node: simvx.core.node.Node)¶
- reparent(new_parent: simvx.core.node.Node)¶
- get_node(path: str) → simvx.core.node.Node¶
- find_child(name: str, recursive: bool = False) → simvx.core.node.Node | None¶
- find(node_type: type, recursive: bool = True) → simvx.core.node.Node | None¶
- property path: str¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) → bool¶
- ready() → None¶
- process(dt: float) → None¶
- physics_process(dt: float) → None¶
- draw(renderer) → None¶
- input_event(event: simvx.core.events.InputEvent) → None¶
- input(event: simvx.core.events.TreeInputEvent) → None¶
- unhandled_input(event: simvx.core.events.TreeInputEvent) → None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) → simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- clear_children()¶
- destroy()¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- get_tree() → simvx.core.scene_tree.SceneTree¶
- __getitem__(key: str)¶
- classmethod get_properties() → dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶