Overview
Procedural motion generation involves two main components:- Path Planning (A):* Constructs a navigation graph from terrain and finds optimal paths between start/goal positions
- Motion Synthesis (MDM Path): Generates character motion that follows the planned path using a motion diffusion model
A* Path Planning
The A* module (astar.py) provides terrain-aware pathfinding with support for jumping, climbing, and navigating complex heightfields.
AStarSettings
Configuration class for A* pathfinding parameters.Navigation Graph Construction
construct_navigation_graph
Builds a directed graph from heightfield terrain where nodes are grid cells and edges represent traversable connections.- Node Creation: Each heightfield cell becomes a TerrainNode
- Adjacent Edges: Connect 8-neighbor cells if height difference ≤
max_z_diff - Cliff Detection: Identify cliff nodes (elevated above neighbors)
- Jump Edges: Connect cliff nodes within
max_jump_xy_distif vertical gap is within jump range - Obstacle Checking: Remove jump edges blocked by intermediate walls
terrain(SubTerrain): Heightfield terrain representationmax_z_diff(float): Maximum height difference for adjacent connectionsmax_jump_xy_dist(float): Maximum horizontal distance for jump connectionsmax_jump_z_diff(float): Maximum upward jump heightmin_jump_z_diff(float): Maximum downward jump height (negative value)
nodes(list): 2D list of TerrainNode objects indexed by [x][y]
TerrainNode
Represents a navigable location in the terrain graph.Path Search
a_star_search
Finds the optimal path between start and goal nodes using A* algorithm with terrain-aware cost functions.xy_dist²: Squared horizontal distance (favors shorter paths)z_diff²: Squared vertical distance (favors flat paths)roughness: Mean absolute difference of 3x3 height patch (penalizes bumpy terrain)random_cost: Optional stochastic term for path diversity
terrain(SubTerrain): Heightfield terrainstart(ndarray): Start grid index [x, y]goal(ndarray): Goal grid index [x, y]max_z_diff,max_jump_xy_dist,max_jump_z_diff,min_jump_z_diff: Graph construction parameters (ignored ifnav_graphprovided)w_z(float): Vertical movement cost weightw_xy(float): Horizontal movement cost weightw_bumpy(float): Terrain roughness penalty weightmax_bumpy(float): Maximum roughness threshold (clamped)stochastic_step_cost_fn(callable): Optional function returning random cost per stepnav_graph(list): Pre-computed navigation graph (if None, constructs new graph)max_compute_time(float): Maximum search time in secondsverbose(bool): Print timing information
path(list): List of grid indices representing the path, or None if no path foundcost(float): Total path cost, or None if no path found
run_a_star_on_start_end_nodes
Wrapper function that runs A* with AStarSettings and returns 3D world-space path points.- Converts grid indices to 3D world positions
- Subdivides long jumps into intermediate points
- Returns False if path not found or cost exceeds
settings.max_cost
path_nodes_3dpos(Tensor): [num_points, 3] tensor of world positions, or False if failed
Path Sampling
pick_random_start_end_nodes
Randomly samples valid start and goal nodes with minimum separation.pick_random_start_end_nodes_on_edges
Samples start/goal near terrain borders (useful for traversal tasks).Alternative Path Generators
catmull_rom_path
Generates smooth curved path using Catmull-Rom spline interpolation.control_points(list): List of [x, y] control points (if None, generates 6 random points)num_samples(int): Initial sampling rate (auto-adjusted based on path length)
path_points(Tensor): [num_points, 3] path positions with heights from terrain
straight_line
Generates direct linear path between two points.path_points_xyz(Tensor): [num_points, 3] linearly interpolated path with terrain heights
MDM Path Generation
The MDM path module (mdm_path.py) generates realistic character motion along planned paths using Motion Diffusion Models.
MDMPathSettings
Configuration for MDM-based path following.Motion Generation
generate_frames_until_end_of_path
Main function for generating motion that follows a path from start to end.- Initialization: Generate motion at path start with appropriate heading
- Autoregressive Loop:
- Extract previous frames (with overlap)
- Find closest path node to current position
- Look ahead
next_node_lookaheadnodes for target - Generate motion segment toward target using MDM
- Check if character reached end of path
- Repeat until done or time limit
- Batch Evaluation: Compute losses for all generated motions
- Selection: Sort by loss and return top-k motions
path_nodes(Tensor): [num_nodes, 3] path positions in world spaceterrain(SubTerrain): Heightfield terrainchar_model(KinCharModel): Character kinematic modelmdm_model(MDM): Trained motion diffusion modelprev_frames(MotionFrames): Optional previous motion for continuationmdm_path_settings(MDMPathSettings): Path following configurationmdm_gen_settings(MDMGenSettings): MDM generation settingsadd_noise_to_loss(bool): Add noise to loss for diversity in selectionverbose(bool): Print progress messagesslice_terrain(bool): Extract local terrain patches per motionfirst_heading_mode(str): “auto” (toward next node) or “random”
sorted_motion_frames(list): List of MotionFrames sorted by loss (best first)sorted_motion_terrains(list): Corresponding terrain patchesinfo(dict): Dictionary with keys:"losses": Sorted total losses"contact_losses": Contact loss terms"pen_losses": Penetration loss terms
generate_frames_along_path
Generates a single motion segment toward the next path node.gen_motion_frames(MotionFrames): Generated motion segmentdone(Tensor): Boolean tensor indicating which motions reached the end
gen_mdm_motion_at_path_start
Initializes motion at the first path node."auto": Face toward second path node"random": Random heading in [0, 2π]
Motion Loss Computation
compute_motion_loss
Evaluates how well motion follows the path and respects terrain constraints.- Penetration Loss:
sum(clamp(-sdf, max=0)) * w_pen - Contact Loss:
sum(sdf * contacts) * w_contact - Path Following Loss: (Currently unused, reserved for future trajectory tracking)
motion_frames(MotionFrames): Generated motion with batch dimensionpath_nodes(Tensor): Path node positionsterrain(SubTerrain): Terrain for SDF querieschar_model(KinCharModel): Character modelbody_points(list): Per-body sampled points for collisionw_contact,w_pen,w_path: Loss weights
- Dictionary with keys:
"total_loss","contact_loss","pen_loss"
Utility Functions
get_closest_path_node_idx
Finds the nearest path node to character position.root_pos(Tensor): [batch_size, 3] character root positionspath_nodes_xyz(Tensor): [num_nodes, 3] path positions
closest_node_idx(Tensor): [batch_size] indices of closest nodes
gen_mdm_motion_at_xy
Generates motion starting at arbitrary XY positions with random targets.Complete Workflow Example
Performance Tips
- Reuse Navigation Graph: Pre-compute the nav graph once and pass to multiple
a_star_searchcalls - Batch Size Tuning: Larger
mdm_batch_sizeincreases diversity but uses more memory - Path Simplification: For long paths, consider downsampling nodes to reduce computation
- Terrain Slicing: Enable
slice_terrain=Trueto reduce memory for large heightfields - Early Stopping: Reduce
max_motion_lengthif paths are shorter than expected
Related Modules
- Motion Optimization - Refine generated motion
- Motion Diffusion Model - Core MDM implementation
- Terrain Utilities - Heightfield operations and SDF computation