Python标准库开发3D引擎:3D点转2D屏幕坐标实现咨询
3D空间点转2D屏幕坐标实现(Python标准库适配Tkinter)
核心实现思路
- 坐标平移:将世界坐标系下的3D点转换为相机坐标系下的相对坐标,消除相机位置偏移影响
- 旋转变换:通过旋转矩阵抵消相机X、Y轴旋转带来的视角偏移,得到相机视角下的真实相对位置
- 透视投影:利用小孔成像原理,将3D相对坐标投影为归一化的2D平面坐标
- 屏幕坐标适配:将归一化坐标转换为Tkinter画布的实际像素坐标,适配Tkinter左上角为原点、Y轴向下的坐标系规则
完整实现代码
import math # 可根据自身场景调整的全局参数 FOV = math.pi / 3 # 视场角,默认60度 SCREEN_WIDTH = 800 # Tkinter画布宽度 SCREEN_HEIGHT = 600 # Tkinter画布高度 SCREEN_CENTER_X = SCREEN_WIDTH // 2 SCREEN_CENTER_Y = SCREEN_HEIGHT // 2 # 焦距计算,固定值无需修改 FOCAL_LENGTH = SCREEN_WIDTH / (2 * math.tan(FOV / 2)) def point_3d_to_2d(cam_x: float, cam_y: float, cam_z: float, cam_rot_x: float, cam_rot_y: float, point_x: float, point_y: float, point_z: float) -> tuple[float, float] | None: """ 3D世界坐标点转Tkinter 2D屏幕坐标 角度单位:角度(°) 返回值:点在相机后方时返回None,否则返回(x, y)像素坐标 """ # 1. 坐标平移,计算点相对于相机的原始坐标 rel_x = point_x - cam_x rel_y = point_y - cam_y rel_z = point_z - cam_z # 2. 角度转弧度 rot_x_rad = math.radians(cam_rot_x) rot_y_rad = math.radians(cam_rot_y) # 3. Y轴旋转(偏航角)变换 y_rot_x = rel_x * math.cos(rot_y_rad) + rel_z * math.sin(rot_y_rad) y_rot_z = -rel_x * math.sin(rot_y_rad) + rel_z * math.cos(rot_y_rad) y_rot_y = rel_y # 4. X轴旋转(俯仰角)变换 x_rot_y = y_rot_y * math.cos(rot_x_rad) - y_rot_z * math.sin(rot_x_rad) x_rot_z = y_rot_y * math.sin(rot_x_rad) + y_rot_z * math.cos(rot_x_rad) x_rot_x = y_rot_x # 5. 点在相机后方/重合,跳过渲染 if x_rot_z <= 0: return None # 6. 透视投影计算归一化2D坐标 proj_x = (FOCAL_LENGTH * x_rot_x) / x_rot_z proj_y = (FOCAL_LENGTH * x_rot_y) / x_rot_z # 7. 转换为Tkinter画布坐标(Y轴翻转,偏移到画布中心) screen_x = SCREEN_CENTER_X + proj_x screen_y = SCREEN_CENTER_Y - proj_y return (screen_x, screen_y)
使用说明
- 代码中
SCREEN_WIDTH、SCREEN_HEIGHT需替换为你实际使用的Tkinter画布宽高 - 视场角
FOV可根据想要的视角效果调整,值越大广角效果越强 - 传入的相机旋转角单位为角度,如果你自己存储的是弧度可删除代码中的角度转弧度逻辑
- 如果返回None说明点在相机视野后方,不需要绘制对应的点和连线
内容的提问来源于stack exchange,提问作者Decode0007
相关产品推荐
相关产品推荐

