update ModelRenderer

pull/35357/head
deanlee 3 months ago
parent f731b9cf75
commit 8e68e913e3
  1. 2
      system/ui/lib/shader_polygon.py
  2. 93
      system/ui/onroad/model_renderer.py

@ -221,7 +221,7 @@ class ShaderState:
self.initialized = False self.initialized = False
def draw_polygon(points: np.ndarray, color: rl.Color | None =None, gradient=None): def draw_polygon(points: np.ndarray, color=None, gradient=None):
""" """
Draw a complex polygon using shader-based even-odd fill rule Draw a complex polygon using shader-based even-odd fill rule

@ -4,6 +4,7 @@ import numpy as np
import pyray as rl import pyray as rl
from cereal import messaging, car from cereal import messaging, car
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.system.ui.lib.shader_polygon import draw_polygon
CLIP_MARGIN = 500 CLIP_MARGIN = 500
@ -145,29 +146,29 @@ class ModelRenderer:
def _draw_lane_lines(self): def _draw_lane_lines(self):
"""Draw lane lines and road edges""" """Draw lane lines and road edges"""
for i in range(4): for i, vertices in enumerate(self._lane_line_vertices):
# Skip if no vertices # Skip if no vertices
if not self._lane_line_vertices[i]: if vertices.size == 0:
continue continue
# Draw lane line # Draw lane line
alpha = np.clip(self._lane_line_probs[i], 0.0, 0.7) alpha = np.clip(self._lane_line_probs[i], 0.0, 0.7)
color = rl.Color(255, 255, 255, int(alpha * 255)) color = rl.Color(255, 255, 255, int(alpha * 255))
self._draw_polygon(self._lane_line_vertices[i], color) draw_polygon(vertices, color)
for i in range(2): for i, vertices in enumerate(self._road_edge_vertices):
# Skip if no vertices # Skip if no vertices
if not self._road_edge_vertices[i]: if vertices.size == 0:
continue continue
# Draw road edge # Draw road edge
alpha = np.clip(1.0 - self._road_edge_stds[i], 0.0, 1.0) alpha = np.clip(1.0 - self._road_edge_stds[i], 0.0, 1.0)
color = rl.Color(255, 0, 0, int(alpha * 255)) color = rl.Color(255, 0, 0, int(alpha * 255))
self._draw_polygon(self._road_edge_vertices[i], color) draw_polygon(vertices, color)
def _draw_path(self, sm, model, height): def _draw_path(self, sm, model, height):
"""Draw the path polygon with gradient based on acceleration""" """Draw the path polygon with gradient based on acceleration"""
if not self._track_vertices: if self._track_vertices.size == 0:
return return
if self._experimental_mode: if self._experimental_mode:
@ -175,16 +176,29 @@ class ModelRenderer:
acceleration = model.acceleration.x acceleration = model.acceleration.x
max_len = min(len(self._track_vertices) // 2, len(acceleration)) max_len = min(len(self._track_vertices) // 2, len(acceleration))
# Create gradient colors for path sections # Find midpoint index for polygon
for i in range(max_len): mid_point = len(self._track_vertices) // 2
# For acceleration-based coloring, process segments separately
left_side = self._track_vertices[:mid_point]
right_side = self._track_vertices[mid_point:][::-1] # Reverse for proper winding
# Create segments for gradient coloring
segment_colors = []
gradient_stops = []
for i in range(max_len - 1):
if i >= len(left_side) - 1 or i >= len(right_side) - 1:
break
track_idx = max_len - i - 1 # flip idx to start from bottom right track_idx = max_len - i - 1 # flip idx to start from bottom right
track_y = self._track_vertices[track_idx][1]
# Skip points out of frame # Skip points out of frame
if track_y < 0 or track_y > height: if left_side[track_idx][1] < 0 or left_side[track_idx][1] > height:
continue continue
# Calculate color based on acceleration # Calculate color based on acceleration
lin_grad_point = (height - track_y) / height lin_grad_point = (height - left_side[track_idx][1]) / height
# speed up: 120, slow down: 0 # speed up: 120, slow down: 0
path_hue = max(min(60 + acceleration[i] * 35, 120), 0) path_hue = max(min(60 + acceleration[i] * 35, 120), 0)
@ -197,12 +211,24 @@ class ModelRenderer:
# Use HSL to RGB conversion # Use HSL to RGB conversion
color = self._hsla_to_color(path_hue / 360.0, saturation, lightness, alpha) color = self._hsla_to_color(path_hue / 360.0, saturation, lightness, alpha)
# TODO: This is simplified - a full implementation would create a gradient fill # Create quad segment
segment = self._track_vertices[track_idx : track_idx + 2] + self._track_vertices[-track_idx - 2 : -track_idx] gradient_stops.append(lin_grad_point)
self._draw_polygon(segment, color) segment_colors.append(color)
# Skip a point, unless next is last if len(segment_colors) < 2:
i += 1 if i + 2 < max_len else 0 self.draw_complex_polygon(self._track_vertices, rl.Color(255, 255, 255, 30))
return
# Create gradient specification
gradient = {
'start': (0.0, 1.0), # Bottom of path
'end': (0.0, 0.0), # Top of path
'colors': segment_colors,
'stops': gradient_stops,
}
# Draw the entire path with a single gradient fill
draw_polygon(self._track_vertices, gradient=gradient)
else: else:
# Draw with throttle/no throttle gradient # Draw with throttle/no throttle gradient
allow_throttle = sm['longitudinalPlan'].allowThrottle or not self._longitudinal_control allow_throttle = sm['longitudinalPlan'].allowThrottle or not self._longitudinal_control
@ -226,7 +252,14 @@ class ModelRenderer:
self._blend_colors(begin_colors[2], end_colors[2], self._blend_factor), self._blend_colors(begin_colors[2], end_colors[2], self._blend_factor),
] ]
self._draw_polygon(self._track_vertices, colors[0]) gradient = {
'start': (0.0, 1.0), # Bottom of path
'end': (0.0, 0.0), # Top of path
'colors': colors,
'stops': [0.0, 1.0]
}
# Draw path with gradient
draw_polygon(self._track_vertices, gradient=gradient)
def _draw_lead(self, lead_data, vd, rect): def _draw_lead(self, lead_data, vd, rect):
"""Draw lead vehicle indicator""" """Draw lead vehicle indicator"""
@ -284,14 +317,14 @@ class ModelRenderer:
return (x, y) return (x, y)
def _map_line_to_polygon(self, line, y_off, z_off, max_idx, allow_invert=True): def _map_line_to_polygon(self, line, y_off, z_off, max_idx, allow_invert=True)-> np.ndarray:
"""Convert a 3D line to a 2D polygon for drawing""" """Convert a 3D line to a 2D polygon for drawing"""
line_x = line.x line_x = line.x
line_y = line.y line_y = line.y
line_z = line.z line_z = line.z
left_points = [] left_points: list[tuple[float, float]] = []
right_points = [] right_points: list[tuple[float, float]] = []
for i in range(max_idx + 1): for i in range(max_idx + 1):
# Skip points with negative x (behind camera) # Skip points with negative x (behind camera)
@ -309,23 +342,7 @@ class ModelRenderer:
left_points.append(left) left_points.append(left)
right_points.append(right) right_points.append(right)
if not left_points: return np.array(left_points + right_points[::-1], dtype=np.float32)
return []
return left_points + right_points[::-1]
def _draw_polygon(self, points, color):
# TODO: Enhance polygon drawing to support even-odd fill rule efficiently, as Raylib lacks native support.
# Use a faster triangulation algorithm (e.g., ear clipping) or GPU shader for
# efficient rendering of lane lines, road edges, and path polygons.
if len(points) <= 8:
rl.draw_triangle_fan(points, len(points), color)
else:
for i in range(1, len(points) - 1):
rl.draw_triangle(points[0], points[i], points[i + 1], color)
for i in range(len(points)):
rl.draw_line_ex(points[i], points[(i + 1) % len(points)], 1.5, color)
@staticmethod @staticmethod
def _map_val(x, x0, x1, y0, y1): def _map_val(x, x0, x1, y0, y1):

Loading…
Cancel
Save