You need to enable JavaScript to run this app. Kivy3点击3D对象触发函数实现:正俯视相机下的坐标转换问题
优惠活动
大模型
产品
解决方案
定价
更多

Kivy3点击3D对象触发函数实现:正俯视相机下的坐标转换问题

问题核心偏差定位

你之前手写坐标转换逻辑存在三个关键偏差,导致投影位置和实际渲染位置无法对齐:

  • 轴映射错位:当前为正俯视相机,视轴沿世界Y轴方向,此时屏幕水平方向对应世界X轴、屏幕垂直方向对应世界Z轴,之前代码中用世界Y轴差值做三角函数分母的计算逻辑,混淆了相机视轴的参考方向
  • 缩放系数不匹配:手写的fov换算逻辑没有对齐Kivy3透视投影的实际视锥范围,导致线性偏移存在固定比例误差
  • 边界计算粗糙:手动给对象坐标加10偏移来模拟边界的方式,没有对齐对象实际的包围盒尺寸,无法准确匹配投影范围
正俯视场景下的实时坐标转换实现

因为当前相机为完全正俯视视角(无倾斜、无旋转),坐标映射为严格的线性关系,不需要复杂的矩阵连乘即可实现精准转换:

基准参数对齐

先明确固定俯视的相机坐标系约定:

  • 相机沿世界Y轴正方向放置,视线朝向世界Y轴负方向,完全垂直向下
  • 相机视锥中心线上的空间点,投影后固定落在控件的几何中心位置((width/2, height/2))
  • 视场角fov参数和Kivy3 Renderer初始化时传入的参数完全一致

投影计算逻辑

按照透视投影的基本原理推导映射关系:

  1. 计算对象到相机的垂直深度(正俯视下深度值恒为Y轴方向的差值):
    depth = camera.pos.y - obj.pos.y
  2. 将fov值转换为弧度单位,计算对应深度处的可视范围:
    • 垂直可视总高度:visible_height = 2 * depth * tan(fov/2 * π/180)
    • 水平可视总宽度:visible_height * (控件宽度 / 控件高度)(匹配透视投影的宽高比)
  3. 计算对象的屏幕投影坐标:
    # 导入需要的数学计算模块
    import math
    cam_pos = self.camera.pos
    obj_pos = obj.pos
    # 深度计算
    depth = cam_pos.y - obj_pos.y
    fov_rad = math.radians(self.camera.fov)
    # 对应深度下的可视范围
    visible_height = 2 * depth * math.tan(fov_rad / 2)
    visible_width = visible_height * (self.width / self.height)
    # 转换为屏幕坐标
    screen_x = self.width / 2 + ( (obj_pos.x - cam_pos.x) / visible_width ) * self.width
    screen_y = self.height / 2 - ( (obj_pos.z - cam_pos.z) / visible_height ) * self.height
    

注意:Kivy坐标系的Y轴原点在控件左下角,向上为正;如果你的世界Z轴正方向是指向屏幕上方的,需要对计算值做符号对齐,否则投影位置会上下颠倒

点击检测适配

你所有对象为固定10×10×10的立方体,正俯视下的屏幕投影为正方形,可直接通过像素距离做判定:

  • 计算对象投影对应的屏幕半尺寸像素值:obj_half_size_pix = (5 / visible_height) * self.height(对象半长为5单位,换算为深度下的像素占比)
  • 当点击坐标与对象投影中心的差值同时满足以下两个条件时,判定为点击命中:
    • abs(touch_x - screen_x) <= obj_half_size_pix
    • abs(touch_y - screen_y) <= obj_half_size_pix
  • 命中后直接触发绑定的对应函数即可
通用适配方案(不局限正俯视场景)

如果后续需要调整相机角度、不再保持纯正俯视,可直接复用Kivy3 Renderer内部缓存的视图、投影矩阵完成转换,避免自行推导公式带来的偏差:

  1. 取每帧渲染时生成的视图矩阵V、投影矩阵P,相乘得到VP矩阵
  2. 将3D对象的齐次坐标[x, y, z, 1]左乘VP矩阵,得到裁剪空间坐标
  3. 对裁剪空间坐标做透视除法,将x、y、z分量除以w分量,得到范围在[-1, 1]的标准化设备坐标(NDC)
  4. 将NDC坐标线性映射为Kivy屏幕坐标:
    screen_x = (ndc_x + 1) / 2 * self.width
    screen_y = (ndc_y + 1) / 2 * self.height
    

这种计算逻辑和Kivy3实际渲染的坐标管线完全对齐,无论相机位置、角度如何调整,都能输出精准的投影坐标。

内容的提问来源于stack exchange,提问作者GreenJon902

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.22 15:45:11