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.
64 lines
2.2 KiB
64 lines
2.2 KiB
|
11 months ago
|
import numpy as np
|
||
|
|
|
||
|
|
def project_point(camera_position, look_at, point_3d):
|
||
|
|
"""
|
||
|
|
Project a 3D point into a normalized projection matrix.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
camera_position: The 3D position of the camera (x, y, z).
|
||
|
|
look_at: The 3D position the camera is looking at (x, y, z).
|
||
|
|
point_3d: The 3D point to project (x, y, z).
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
The 2D coordinates of the projected point in normalized space.
|
||
|
|
"""
|
||
|
|
# Step 1: Calculate the forward, right, and up vectors
|
||
|
|
def normalize(v):
|
||
|
|
return v / np.linalg.norm(v)
|
||
|
|
|
||
|
|
forward = normalize(np.array(look_at) - np.array(camera_position))
|
||
|
|
right = normalize(np.cross(forward, [0, 1, 0]))
|
||
|
|
up = np.cross(right, forward)
|
||
|
|
|
||
|
|
# Step 2: Create the view matrix
|
||
|
|
view_matrix = np.array([
|
||
|
|
[right[0], right[1], right[2], -np.dot(right, camera_position)],
|
||
|
|
[up[0], up[1], up[2], -np.dot(up, camera_position)],
|
||
|
|
[-forward[0], -forward[1], -forward[2], np.dot(forward, camera_position)],
|
||
|
|
[0, 0, 0, 1]
|
||
|
|
])
|
||
|
|
|
||
|
|
# Step 3: Create the projection matrix
|
||
|
|
near = 1.0 # Near plane normalized to 1
|
||
|
|
width = 1.0 # Width of the near plane
|
||
|
|
height = 1.0 # Height of the near plane
|
||
|
|
aspect_ratio = width / height
|
||
|
|
|
||
|
|
projection_matrix = np.array([
|
||
|
|
[1 / aspect_ratio, 0, 0, 0],
|
||
|
|
[0, 1, 0, 0],
|
||
|
|
[0, 0, -1, -2 * near],
|
||
|
|
[0, 0, -1, 0]
|
||
|
|
])
|
||
|
|
|
||
|
|
# Step 4: Transform the 3D point into clip space
|
||
|
|
point_3d_homogeneous = np.array([point_3d[0], point_3d[1], point_3d[2], 1])
|
||
|
|
view_space_point = view_matrix @ point_3d_homogeneous
|
||
|
|
clip_space_point = projection_matrix @ view_space_point
|
||
|
|
|
||
|
|
# Step 5: Perform perspective divide to get normalized device coordinates (NDC)
|
||
|
|
if clip_space_point[3] == 0:
|
||
|
|
raise ValueError("Invalid projection: w component is zero.")
|
||
|
|
ndc_x = clip_space_point[0] / clip_space_point[3]
|
||
|
|
ndc_y = clip_space_point[1] / clip_space_point[3]
|
||
|
|
|
||
|
|
return ndc_x, ndc_y
|
||
|
|
|
||
|
|
|
||
|
|
# Example usage
|
||
|
|
camera_position = (0, 0, 0) # Camera position
|
||
|
|
look_at = (0, 0, -1) # Camera is looking along the negative Z-axis
|
||
|
|
point_3d = (0.5, 0.5, -2) # A 3D point to project
|
||
|
|
|
||
|
|
projected_point = project_point(camera_position, look_at, point_3d)
|
||
|
|
print("Projected 2D Point in NDC:", projected_point)
|