You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

70 lines
2.3 KiB

import numpy as np
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)