4.3 KiB
4.3 KiB
坐标轴系统修复说明
问题描述
用户报告主程序中的坐标轴系统无响应:
- 鼠标悬停在坐标轴上无高亮效果
- 点击坐标轴无法开始拖拽
- 独立的demo程序(
standalone_gizmo_test.py)工作正常
根本原因
经过分析发现,问题出在Qt集成环境下的窗口尺寸获取不准确:
- 独立demo:直接继承自
ShowBase,使用self.win.getXSize()和self.win.getYSize()获取窗口尺寸是准确的 - 主程序:使用Qt集成的
Panda3DWorld基类,self.win.getXSize()返回的尺寸与实际Qt渲染区域尺寸不匹配 - 坐标轴点击检测:依赖屏幕空间投影计算,窗口尺寸错误导致投影坐标计算错误
修复方案
1. 添加Qt部件引用机制
在MyWorld类中添加:
# Qt部件引用(用于获取准确的渲染区域尺寸)
self.qtWidget = None
def setQtWidget(self, widget):
"""设置Qt部件引用"""
self.qtWidget = widget
def getWindowSize(self):
"""获取准确的窗口尺寸"""
if self.qtWidget:
# 优先使用Qt部件的实际尺寸
width, height = self.qtWidget.getActualSize()
if width > 0 and height > 0:
return width, height
# 备用方案:使用Panda3D窗口尺寸
if hasattr(self, 'win') and self.win:
width = self.win.getXSize()
height = self.win.getYSize()
return width, height
# 最后的默认值
return 800, 600
2. 修改CustomPanda3DWidget
添加方法以获取Qt部件实际尺寸:
def getActualSize(self):
"""获取Qt部件的实际渲染尺寸"""
return (self.width(), self.height())
在构造函数中建立引用:
# 让world引用这个widget,以便获取准确的尺寸
if hasattr(world, 'setQtWidget'):
world.setQtWidget(self)
3. 修改所有屏幕坐标计算
将所有使用self.win.getXSize()和self.win.getYSize()的地方改为使用新的getWindowSize()方法:
修改前:
win_x = (screen_pos.getX() + 1.0) * 0.5 * self.win.getXSize()
win_y = (1.0 - screen_pos.getY()) * 0.5 * self.win.getYSize()
修改后:
# 获取准确的窗口尺寸
win_width, win_height = self.getWindowSize()
win_x = (screen_pos.getX() + 1.0) * 0.5 * win_width
win_y = (1.0 - screen_pos.getY()) * 0.5 * win_height
4. 修改的关键方法
checkGizmoClick()- 坐标轴点击检测的主方法updateGizmoHighlight()- 坐标轴悬停高亮updateGizmoDrag()- 坐标轴拖拽更新mousePressEventLeft()- 鼠标点击事件处理mouseMoveEvent()- 鼠标移动事件处理checkGizmoClickFallback()- 备用点击检测方法
技术原理
屏幕空间投影算法
坐标轴点击检测使用以下步骤:
-
世界坐标 → 相机坐标:
cam_space_pos = self.cam.getRelativePoint(self.render, world_pos) -
相机坐标 → 标准化屏幕坐标:
screen_pos = Point2() self.cam.node().getLens().project(cam_space_pos, screen_pos) -
标准化坐标 → 像素坐标:
win_x = (screen_pos.getX() + 1.0) * 0.5 * win_width win_y = (1.0 - screen_pos.getY()) * 0.5 * win_height -
点到线段距离计算:
distance = self.distanceToLine((mouse_x, mouse_y), center_screen, axis_screen)
窗口尺寸差异的影响
如果窗口尺寸不准确:
- 步骤3中的像素坐标计算错误
- 坐标轴在屏幕上的投影位置计算错误
- 鼠标点击位置与计算出的轴位置不匹配
- 导致点击检测失败
测试验证
创建了测试脚本demo/test_size_fix.py来验证修复效果:
- 对比Qt部件尺寸和Panda3D窗口尺寸
- 实时监控尺寸变化
- 验证
getWindowSize()方法的正确性
预期效果
修复后的坐标轴系统应该:
- ✅ 鼠标悬停时正确高亮对应的轴(红色X轴、绿色Y轴、蓝色Z轴变为黄色)
- ✅ 点击坐标轴能够正确开始拖拽
- ✅ 拖拽时只沿选定轴方向移动物体
- ✅ 松开鼠标时正确结束拖拽
兼容性
修复方案完全向后兼容:
- 如果没有Qt环境,自动回退到使用Panda3D窗口尺寸
- 如果Qt部件引用未设置,使用备用方案
- 不影响独立的ShowBase应用程序