import pygame import sys import random # Initialize Pygame and set up the window pygame.init() screen = pygame.display.set_mode((800, 600)) pygame.display.set_caption("Simple 2D BVH Visualization") clock = pygame.time.Clock() font = pygame.font.Font(None, 24) # Utility functions to work with bounding boxes. # We represent a bbox as (min_x, min_y, max_x, max_y). def rect_to_bbox(rect): x, y, w, h = rect return (x, y, x + w, y + h) def union_bbox(bbox1, bbox2): x1 = min(bbox1[0], bbox2[0]) y1 = min(bbox1[1], bbox2[1]) x2 = max(bbox1[2], bbox2[2]) y2 = max(bbox1[3], bbox2[3]) return (x1, y1, x2, y2) # BVH Node class class BVHNode: def __init__(self, bbox, left=None, right=None, obj=None): self.bbox = bbox # Bounding box: (min_x, min_y, max_x, max_y) self.left = left # Left child (BVHNode or None) self.right = right # Right child (BVHNode or None) self.obj = obj # For leaf nodes, store the actual rectangle # Recursive BVH build function. # If there's one object, return a leaf node. # Otherwise, sort the objects by their center x-coordinate, split in half, # build left/right children, and compute the union of their bounding boxes. def build_bvh(objects): if not objects: return None if len(objects) == 1: return BVHNode(rect_to_bbox(objects[0]), obj=objects[0]) # Sort objects by center x-coordinate objects.sort(key=lambda rect: rect[0] + rect[2] / 2) mid = len(objects) // 2 left = build_bvh(objects[:mid]) right = build_bvh(objects[mid:]) node_bbox = union_bbox(left.bbox, right.bbox) return BVHNode(node_bbox, left, right) # Generate a list of random rectangles. def generate_rectangles(num_rects): rects = [] for _ in range(num_rects): x = random.randint(50, 750) y = random.randint(50, 550) w = random.randint(20, 100) h = random.randint(20, 100) rects.append((x, y, w, h)) return rects num_rects = 20 rectangles = generate_rectangles(num_rects) bvh_root = build_bvh(rectangles) # Toggle for showing the BVH overlay show_bvh = True # Recursively draw BVH nodes. def draw_bvh(node, surface): if node is None: return # Convert bbox from (min_x, min_y, max_x, max_y) to pygame.Rect x, y, x2, y2 = node.bbox rect = pygame.Rect(x, y, x2 - x, y2 - y) # Use green for leaf nodes and red for internal nodes. color = (0, 255, 0) if node.obj is not None else (255, 0, 0) pygame.draw.rect(surface, color, rect, 1) draw_bvh(node.left, surface) draw_bvh(node.right, surface) # Main loop. running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN: # Toggle BVH display with D if event.key == pygame.K_d: show_bvh = not show_bvh # Regenerate rectangles and rebuild BVH with R elif event.key == pygame.K_r: rectangles = generate_rectangles(num_rects) bvh_root = build_bvh(rectangles) screen.fill((30, 30, 30)) # Draw each rectangle (the "objects") in white. for rect in rectangles: pygame.draw.rect(screen, (255, 255, 255), rect, 2) # Optionally draw the BVH overlay. if show_bvh and bvh_root: draw_bvh(bvh_root, screen) # Debug text instructions. debug_text = font.render("Press D to toggle BVH overlay, R to regenerate rectangles", True, (255, 255, 255)) screen.blit(debug_text, (10, 10)) pygame.display.flip() clock.tick(60) pygame.quit() sys.exit()