Swift中如何获取ARSCNView内CGPoint对应的世界坐标
解决点击点转世界坐标的问题
嘿,我懂你现在的困境——已经把帧中心点转世界坐标的逻辑跑通了,但没法偏移到实际点击的屏幕位置,对吧?其实核心问题就是原函数里硬编码了屏幕中心的UV坐标,咱们只要把这部分改成动态传入的点击位置对应的UV就行,下面一步步来调整你的代码:
核心思路拆解
原函数之所以只能处理中心点,是因为它用了固定的(0.5, 0.5)作为屏幕UV(也就是屏幕中心的归一化坐标)。要支持任意点击点,咱们需要:
- 让函数接收具体的屏幕点击坐标(比如
screenX和screenY) - 将屏幕坐标转换成归一化UV坐标(范围0到1,再转成NDC空间的[-1,1])
- 把原函数里的中心UV替换成这个计算出来的点击UV
- 保留原有的视图/投影矩阵逆运算逻辑(这部分是从屏幕空间转世界空间的核心)
修改后的完整代码示例
假设你的原函数是基于3D引擎的通用逻辑,下面是调整后的getScreenCoordinates函数(保留了你原有的注释风格,只修改关键部分):
def getScreenCoordinates(screen_x, screen_y, screen_width, screen_height, view_matrix, projection_matrix): """ 将屏幕点击坐标转换为世界空间的方向向量和位置向量 参数: screen_x: 点击点的屏幕X坐标(比如鼠标X) screen_y: 点击点的屏幕Y坐标(比如鼠标Y) screen_width: 屏幕宽度 screen_height: 屏幕高度 view_matrix: 相机的视图矩阵 projection_matrix: 相机的投影矩阵 返回: tuple: (世界空间方向向量, 世界空间位置向量) """ # 步骤1:将屏幕坐标转换为NDC空间坐标(范围[-1,1]) # 注意:不同引擎屏幕原点位置不同!比如Unity是左下角(0,0),Unreal是左上角(0,0) # 如果是左上角原点,反转Y轴:ndc_y = 1.0 - (screen_y / screen_height) * 2.0 + 1.0?不对,正确公式是下面的注释版 ndc_x = (screen_x / screen_width) * 2.0 - 1.0 ndc_y = (screen_y / screen_height) * 2.0 - 1.0 # 左下角原点用这个 # ndc_y = (1.0 - (screen_y / screen_height)) * 2.0 - 1.0 # 左上角原点用这个 # 构建NDC空间的齐次点(z=-1对应近平面,保证是相机前方的点) ndc_point = (ndc_x, ndc_y, -1.0, 1.0) # 步骤2:计算视图投影矩阵的逆矩阵(原函数已有逻辑,直接复用) view_projection_matrix = multiply_matrices(projection_matrix, view_matrix) inv_view_projection_matrix = inverse_matrix(view_projection_matrix) # 步骤3:将NDC点转换为世界空间点 world_point = multiply_matrix_point(inv_view_projection_matrix, ndc_point) # 齐次坐标转笛卡尔坐标:必须除以w分量 world_point = (world_point[0]/world_point[3], world_point[1]/world_point[3], world_point[2]/world_point[3]) # 步骤4:计算世界空间方向向量(从相机位置指向世界点) camera_world_pos = get_camera_world_position(view_matrix) # 原函数已有获取相机位置的逻辑 world_direction = normalize_vector(( world_point[0]-camera_world_pos[0], world_point[1]-camera_world_pos[1], world_point[2]-camera_world_pos[2] )) # 返回方向向量和位置向量 return (world_direction, world_point)
关键注意点
- 屏幕坐标系差异:一定要根据你用的引擎调整Y轴计算!比如Unreal的屏幕原点在左上角,就必须用注释里的反转Y轴公式,否则转换出来的Y坐标会上下颠倒。
- 矩阵运算顺序:不同引擎的矩阵乘法顺序可能不同(比如是投影乘视图,还是视图乘投影),如果转换结果不对,先检查这里的顺序是否和原函数一致。
- 齐次除法:转换后的世界点必须除以w分量,否则坐标会出现缩放失真的问题,这是3D坐标转换的关键步骤。
调用示例
在点击事件里,你可以这样调用函数获取点击点的世界坐标:
# 获取鼠标点击的屏幕坐标 mouse_x, mouse_y = get_mouse_position() # 获取屏幕尺寸 screen_w, screen_h = get_screen_size() # 获取相机的视图和投影矩阵 camera_view = get_camera_view_matrix() camera_proj = get_camera_projection_matrix() # 转换为世界坐标 world_dir, world_pos = getScreenCoordinates(mouse_x, mouse_y, screen_w, screen_h, camera_view, camera_proj) # 现在world_pos就是点击点对应的世界空间位置啦!
这样修改后,你的函数就不再局限于帧中心点,而是可以处理任意屏幕点击位置的转换了。如果还有细节不对,比如矩阵运算的语法,你可以根据自己用的语言/引擎微调~
内容的提问来源于stack exchange,提问作者Anthony Krivonos
相关产品推荐
相关产品推荐

