import math import numpy as np,array def project_3d_to_2d(square_3d, observer, look_at, fov=90, aspect_ratio=1, near=0.1, far=1000): """ Project a 3D square onto a 2D plane. Args: square_3d: List of 4 points representing the square in 3D space [(x, y, z), ...]. observer: The observer's position in 3D space (x, y, z). look_at: The point the observer is looking at in 3D space (x, y, z). fov: Field of view in degrees. aspect_ratio: Aspect ratio of the 2D plane (width/height). near: Near clipping plane. far: Far clipping plane. Returns: List of 2D points [(x, y), ...]. """ # Step 1: Create the view matrix def normalize(v): return v / np.linalg.norm(v) forward = normalize(np.array(look_at) - np.array(observer)) right = normalize(np.cross(forward, [0, 1, 0])) up = np.cross(right, forward) view_matrix = np.array([ [right[0], right[1], right[2], -np.dot(right, observer)], [up[0], up[1], up[2], -np.dot(up, observer)], [-forward[0], -forward[1], -forward[2], np.dot(forward, observer)], [0, 0, 0, 1] ]) # Step 2: Create the projection matrix fov_rad = np.radians(fov) f = 1 / np.tan(fov_rad / 2) projection_matrix = np.array([ [f / aspect_ratio, 0, 0, 0], [0, f, 0, 0], [0, 0, (far + near) / (near - far), (2 * far * near) / (near - far)], [0, 0, -1, 0] ]) # Step 3: Transform the 3D points to 2D square_2d = [] for point in square_3d: # Convert to homogeneous coordinates point_3d = np.array([point[0], point[1], point[2], 1]) # Apply view and projection transformations transformed_point = projection_matrix @ view_matrix @ point_3d # Perform perspective divide x = transformed_point[0] / transformed_point[3] y = transformed_point[1] / transformed_point[3] square_2d.append((x, y)) return square_2d # Example usage square_3d = [ (1, 1, 5), # Top-right (-1, 1, 5), # Top-left (-1, -1, 5), # Bottom-left (1, -1, 5) # Bottom-right ] observer = (0, 0, 0) # Observer's position look_at = (0, 0, 1) # Observer is looking along the positive Z-axis square_2d = project_3d_to_2d(square_3d, observer, look_at) print("2D Coordinates of the square:", square_2d)