refactor: 拆分updateGizmoDrag并同步任务文档
This commit is contained in:
parent
280d6f8b2a
commit
2c9f512996
@ -53,7 +53,10 @@
|
|||||||
- 本轮新增深入分析结论(非 VR):
|
- 本轮新增深入分析结论(非 VR):
|
||||||
- `ui/panels/animation_tools.py::_getActor` 第一轮拆分已完成
|
- `ui/panels/animation_tools.py::_getActor` 第一轮拆分已完成
|
||||||
- 实测指标:`510 -> 39` 行,近似圈复杂度 `191 -> 15`,内嵌局部函数 `9 -> 0`
|
- 实测指标:`510 -> 39` 行,近似圈复杂度 `191 -> 15`,内嵌局部函数 `9 -> 0`
|
||||||
- 下一轮建议转向 `core/selection.py::updateGizmoDrag`,暂不触碰 VR 模块
|
- `core/selection.py::updateGizmoDrag` 第一轮拆分已完成:
|
||||||
|
- 实测指标:`278 -> 32` 行,近似圈复杂度 `65 -> 10`
|
||||||
|
- 缩放/旋转/平移逻辑已拆到独立 helper
|
||||||
|
- 下一轮建议转向 `ui/panels/editor_panels_left.py::_draw_resource_manager`
|
||||||
|
|
||||||
## 1. 总体画像
|
## 1. 总体画像
|
||||||
|
|
||||||
@ -91,11 +94,11 @@
|
|||||||
1. `ui/LUI/lui_function_properties.py::_draw_component_properties` (`1441` 行)
|
1. `ui/LUI/lui_function_properties.py::_draw_component_properties` (`1441` 行)
|
||||||
2. `ui/LUI/lui_manager_interaction.py::_update_drag` (`348` 行)
|
2. `ui/LUI/lui_manager_interaction.py::_update_drag` (`348` 行)
|
||||||
3. `ui/panels/editor_panels_left.py::_draw_resource_manager` (`310` 行)
|
3. `ui/panels/editor_panels_left.py::_draw_resource_manager` (`310` 行)
|
||||||
4. `core/selection.py::updateGizmoDrag` (`278` 行)
|
4. `ui/LUI/lui_manager_interaction.py::_handle_resize_drag` (`257` 行)
|
||||||
5. `ui/LUI/lui_manager_interaction.py::_handle_resize_drag` (`257` 行)
|
5. `ui/LUI/lui_manager_editor.py::_set_parent_child_relationship` (`234` 行)
|
||||||
6. `ui/LUI/lui_manager_editor.py::_set_parent_child_relationship` (`234` 行)
|
6. `ui/panels/editor_panels_top.py::draw_menu_bar` (`227` 行)
|
||||||
7. `ui/panels/editor_panels_top.py::draw_menu_bar` (`227` 行)
|
7. `scene/scene_manager_io_mixin.py::saveScene` (`222` 行)
|
||||||
8. `scene/scene_manager_io_mixin.py::saveScene` (`222` 行)
|
8. `TransformGizmo/move_gizmo.py::_on_mouse_down` (`222` 行)
|
||||||
|
|
||||||
### 2.3 异常处理密度高(可观测性风险)
|
### 2.3 异常处理密度高(可观测性风险)
|
||||||
|
|
||||||
@ -154,10 +157,10 @@
|
|||||||
|
|
||||||
建议拆分顺序(非 VR 当前阶段):
|
建议拆分顺序(非 VR 当前阶段):
|
||||||
|
|
||||||
1. `core/selection.py::updateGizmoDrag`
|
1. `ui/panels/editor_panels_left.py::_draw_resource_manager`
|
||||||
2. `ui/panels/editor_panels_left.py::_draw_resource_manager`
|
2. `ui/LUI/lui_manager_interaction.py::_update_drag`
|
||||||
3. `ui/LUI/lui_manager_interaction.py::_update_drag`
|
3. `ui/LUI/lui_function_properties.py::_draw_component_properties`(可按“变换/布局/视觉/交互/脚本”分区)
|
||||||
4. `ui/LUI/lui_function_properties.py::_draw_component_properties`(可按“变换/布局/视觉/交互/脚本”分区)
|
4. `ui/LUI/lui_manager_interaction.py::_handle_resize_drag`
|
||||||
|
|
||||||
预期收益:
|
预期收益:
|
||||||
|
|
||||||
@ -218,17 +221,31 @@
|
|||||||
- 保持“文件路径优先,内存 autoBind 兜底”语义一致
|
- 保持“文件路径优先,内存 autoBind 兜底”语义一致
|
||||||
- 不改 VR 逻辑
|
- 不改 VR 逻辑
|
||||||
|
|
||||||
### Task E(并行候选,1 天)
|
### Task E(已完成,第一轮)
|
||||||
|
|
||||||
- 拆分 `core/selection.py::updateGizmoDrag`:
|
- 拆分 `core/selection.py::updateGizmoDrag`:
|
||||||
- `_apply_scale_drag`
|
- `_apply_scale_drag`
|
||||||
- `_apply_rotation_drag`
|
- `_apply_rotation_drag`
|
||||||
- `_compute_axis_projected_distance`
|
- `_compute_axis_movement_distance`
|
||||||
- `_apply_translation_drag`
|
- `_apply_translation_drag`
|
||||||
- 验收:
|
- 验收:
|
||||||
- 主函数长度降到 `<= 120` 行
|
- 主函数长度降到 `<= 120` 行(实际 `32` 行)
|
||||||
- 保持当前 gizmo 拖拽行为一致
|
- 保持当前 gizmo 拖拽行为一致
|
||||||
|
|
||||||
|
### Task F(推荐下一步,1 天)
|
||||||
|
|
||||||
|
- 拆分 `ui/panels/editor_panels_left.py::_draw_resource_manager`
|
||||||
|
- 验收:
|
||||||
|
- 主函数长度降到 `<= 160` 行
|
||||||
|
- 文件/目录项渲染逻辑去重
|
||||||
|
|
||||||
|
### Task G(并行候选,1-2 天)
|
||||||
|
|
||||||
|
- 拆分 `ui/LUI/lui_manager_interaction.py::_update_drag`
|
||||||
|
- 验收:
|
||||||
|
- 主函数长度降到 `<= 140` 行
|
||||||
|
- 拖拽与缩放交互行为保持一致
|
||||||
|
|
||||||
## 4.1 本轮深入分析(非 VR,P1 准备)
|
## 4.1 本轮深入分析(非 VR,P1 准备)
|
||||||
|
|
||||||
### A) `scene/scene_manager_io_mixin.py::loadScene`(核心优先,已完成)
|
### A) `scene/scene_manager_io_mixin.py::loadScene`(核心优先,已完成)
|
||||||
@ -254,7 +271,7 @@
|
|||||||
- 失败重试逻辑保持语义一致。
|
- 失败重试逻辑保持语义一致。
|
||||||
- 当前状态(2026-02-28):
|
- 当前状态(2026-02-28):
|
||||||
- 第二轮已完成(`loadScene` 已达验收目标:`74` 行)。
|
- 第二轮已完成(`loadScene` 已达验收目标:`74` 行)。
|
||||||
- 后续建议转入回归观察,优先推进 `core/selection.py::updateGizmoDrag`。
|
- 后续建议转入回归观察,优先推进 `ui/panels/editor_panels_left.py::_draw_resource_manager`。
|
||||||
|
|
||||||
### B) `main.py::__init__`(第二优先,已完成第一轮)
|
### B) `main.py::__init__`(第二优先,已完成第一轮)
|
||||||
|
|
||||||
@ -280,19 +297,19 @@
|
|||||||
- 入口函数已收敛为流程编排。
|
- 入口函数已收敛为流程编排。
|
||||||
- 已通过 `python -m compileall ui/panels/animation_tools.py`。
|
- 已通过 `python -m compileall ui/panels/animation_tools.py`。
|
||||||
|
|
||||||
### D) `core/selection.py::updateGizmoDrag`(第四优先)
|
### D) `core/selection.py::updateGizmoDrag`(已完成第一轮)
|
||||||
|
|
||||||
- 函数规模: `278` 行
|
- 函数规模: `32` 行(重构前 `278` 行)
|
||||||
- 近似圈复杂度: `65`
|
- 近似圈复杂度: `10`(重构前 `65`)
|
||||||
- 关键问题:
|
- 已落地 helper:
|
||||||
- 缩放/旋转/平移三套逻辑混在同一函数,分支切换成本高。
|
- `_validate_gizmo_drag_state`
|
||||||
- 投影计算、坐标变换、UI 刷新混杂,异常边界不清晰。
|
- `_apply_scale_drag`
|
||||||
- 建议拆分:
|
- `_apply_rotate_drag`
|
||||||
- `_validate_gizmo_drag_state()`
|
- `_compute_axis_movement_distance`
|
||||||
- `_drag_scale(mouseDeltaX, mouseDeltaY)`
|
- `_apply_translate_drag`
|
||||||
- `_drag_rotate(mouseDeltaX, mouseDeltaY)`
|
- 状态:
|
||||||
- `_project_mouse_to_axis_distance(mouseX, mouseY)`
|
- 主流程已收敛为编排入口。
|
||||||
- `_drag_translate(projected_distance)`
|
- 已通过 `python -m compileall core/selection.py`。
|
||||||
|
|
||||||
### E) `ui/panels/editor_panels_left.py::_draw_resource_manager`(第五优先)
|
### E) `ui/panels/editor_panels_left.py::_draw_resource_manager`(第五优先)
|
||||||
|
|
||||||
@ -312,9 +329,9 @@
|
|||||||
|
|
||||||
1. `loadScene` 已完成两轮拆分(当前建议冻结并转入回归观察)。
|
1. `loadScene` 已完成两轮拆分(当前建议冻结并转入回归观察)。
|
||||||
2. `main.__init__` 已完成第一轮拆分(建议转入回归观察)。
|
2. `main.__init__` 已完成第一轮拆分(建议转入回归观察)。
|
||||||
3. 下一步处理 `updateGizmoDrag`(输入与变换逻辑解耦)。
|
3. 下一步处理 `_draw_resource_manager`(提炼重复 UI 渲染分支)。
|
||||||
4. 然后处理 `_draw_resource_manager`(提炼重复 UI 渲染分支)。
|
4. 然后处理 `_update_drag`(LUI 交互链路收敛)。
|
||||||
5. 最后处理 `_update_drag`(LUI 交互链路收敛)。
|
5. 最后处理 `_draw_component_properties`(属性面板分区拆分)。
|
||||||
|
|
||||||
## 5. 与现有文档关系
|
## 5. 与现有文档关系
|
||||||
|
|
||||||
@ -324,4 +341,4 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
如果按此路线继续,建议下一轮直接从 **Task E** 开始,我可以先落地 `updateGizmoDrag` 的第一轮拆分并保持行为不变。
|
如果按此路线继续,建议下一轮直接从 **Task F** 开始,我可以先落地 `_draw_resource_manager` 的第一轮拆分并保持行为不变。
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# 项目任务清单(Project Task Checklist)
|
# 项目任务清单(Project Task Checklist)
|
||||||
|
|
||||||
更新时间:2026-02-28
|
更新时间:2026-03-01
|
||||||
适用范围:`d:\IMGUI\EG` 本地工作区(不含远程仓库内容)
|
适用范围:`d:\IMGUI\EG` 本地工作区(不含远程仓库内容)
|
||||||
|
|
||||||
## 目标
|
## 目标
|
||||||
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
- Qt 运行依赖主路径已清理完成(排除 `RenderPipelineFile`)。
|
- Qt 运行依赖主路径已清理完成(排除 `RenderPipelineFile`)。
|
||||||
- 项目已进入“非 VR 结构优化阶段”。
|
- 项目已进入“非 VR 结构优化阶段”。
|
||||||
- `_getActor` 第一轮拆分已完成,当前最高优先任务转为 `updateGizmoDrag` 拆分。
|
- `_getActor` 与 `updateGizmoDrag` 第一轮拆分已完成,当前最高优先任务转为资源管理器面板拆分。
|
||||||
|
|
||||||
## 已完成(Done)
|
## 已完成(Done)
|
||||||
|
|
||||||
@ -61,17 +61,17 @@
|
|||||||
- 新增 helper:`_sync_owner_model_path_tags`、`_get_valid_cached_actor`、`_try_memory_fallback_actor`、`_collect_actor_candidate_paths`、`_try_actor_from_path` 等
|
- 新增 helper:`_sync_owner_model_path_tags`、`_get_valid_cached_actor`、`_try_memory_fallback_actor`、`_collect_actor_candidate_paths`、`_try_actor_from_path` 等
|
||||||
- 保持策略:文件路径优先,失败后内存/autoBind 兜底
|
- 保持策略:文件路径优先,失败后内存/autoBind 兜底
|
||||||
|
|
||||||
|
### E. Gizmo 拖拽拆分完成(第一轮)
|
||||||
|
|
||||||
|
- [x] `core/selection.py::updateGizmoDrag` 第一轮拆分完成:
|
||||||
|
- 行数:`278 -> 32`
|
||||||
|
- 近似圈复杂度:`65 -> 10`
|
||||||
|
- 新增 helper:`_validate_gizmo_drag_state`、`_apply_scale_drag`、`_apply_rotate_drag`、`_compute_axis_movement_distance`、`_apply_translate_drag`
|
||||||
|
- 保持目标:gizmo 缩放/旋转/平移行为不变
|
||||||
|
|
||||||
## 下一步(Next)
|
## 下一步(Next)
|
||||||
|
|
||||||
### N1 `updateGizmoDrag` 拆分(最高优先级,非 VR)
|
### N1 `资源管理器面板` 拆分(最高优先级,非 VR)
|
||||||
|
|
||||||
- 目标文件:`core/selection.py`
|
|
||||||
- 当前规模:`278` 行
|
|
||||||
- 验收目标:
|
|
||||||
- 主函数压缩到 `<= 120` 行
|
|
||||||
- 保持 gizmo 拖拽行为一致
|
|
||||||
|
|
||||||
### N2 `资源管理器面板` 拆分(高优先级,非 VR)
|
|
||||||
|
|
||||||
- 目标文件:`ui/panels/editor_panels_left.py::_draw_resource_manager`
|
- 目标文件:`ui/panels/editor_panels_left.py::_draw_resource_manager`
|
||||||
- 当前规模:`310` 行
|
- 当前规模:`310` 行
|
||||||
@ -79,6 +79,14 @@
|
|||||||
- 提取目录/文件项渲染与右键菜单复用逻辑
|
- 提取目录/文件项渲染与右键菜单复用逻辑
|
||||||
- 交互行为保持一致
|
- 交互行为保持一致
|
||||||
|
|
||||||
|
### N2 `LUI 交互拖拽链路` 拆分(高优先级,非 VR)
|
||||||
|
|
||||||
|
- 目标文件:`ui/LUI/lui_manager_interaction.py::_update_drag`
|
||||||
|
- 当前规模:`348` 行
|
||||||
|
- 验收目标:
|
||||||
|
- 入口流程收敛到 `<= 140` 行
|
||||||
|
- 保持拖拽/缩放/吸附交互一致
|
||||||
|
|
||||||
## 验收标准(阶段)
|
## 验收标准(阶段)
|
||||||
|
|
||||||
- 不安装 PyQt/PySide 时,`python main.py` 可进入编辑器主界面。
|
- 不安装 PyQt/PySide 时,`python main.py` 可进入编辑器主界面。
|
||||||
|
|||||||
@ -1639,42 +1639,31 @@ class SelectionSystem:
|
|||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
def updateGizmoDrag(self, mouseX, mouseY):
|
def _validate_gizmo_drag_state(self):
|
||||||
"""更新坐标轴拖拽 - 使用正确的坐标系变换,支持旋转后的子节点拖拽"""
|
|
||||||
try:
|
|
||||||
# 添加详细的状态检查和调试信息
|
|
||||||
if not self.isDraggingGizmo:
|
if not self.isDraggingGizmo:
|
||||||
print("拖拽更新失败: 不在拖拽状态")
|
print("拖拽更新失败: 不在拖拽状态")
|
||||||
return
|
return False
|
||||||
if not self.gizmoTarget:
|
if not self.gizmoTarget:
|
||||||
print("拖拽更新失败: 没有拖拽目标")
|
print("拖拽更新失败: 没有拖拽目标")
|
||||||
return
|
return False
|
||||||
if not hasattr(self, 'dragStartMousePos') or not self.dragStartMousePos:
|
if not hasattr(self, 'dragStartMousePos') or not self.dragStartMousePos:
|
||||||
print("拖拽更新失败: 没有拖拽起始位置")
|
print("拖拽更新失败: 没有拖拽起始位置")
|
||||||
return
|
return False
|
||||||
if not hasattr(self, 'gizmoTargetStartPos') or not self.gizmoTargetStartPos:
|
if not hasattr(self, 'gizmoTargetStartPos') or not self.gizmoTargetStartPos:
|
||||||
print("拖拽更新失败: 没有目标起始位置")
|
print("拖拽更新失败: 没有目标起始位置")
|
||||||
return
|
return False
|
||||||
if not hasattr(self, 'gizmoStartPos') or not self.gizmoStartPos:
|
if not hasattr(self, 'gizmoStartPos') or not self.gizmoStartPos:
|
||||||
print("拖拽更新失败: 没有坐标轴起始位置")
|
print("拖拽更新失败: 没有坐标轴起始位置")
|
||||||
return
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
is_scale_tool = self.world.tool_manager.isScaleTool() if self.world.tool_manager else False
|
def _refresh_gizmo_target_panel(self):
|
||||||
is_rotate_tool = self.world.tool_manager.isRotateTool() if self.world.tool_manager else False
|
if hasattr(self.world, 'property_panel') and self.world.property_panel:
|
||||||
|
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
||||||
is_gui_element = (hasattr(self.gizmoTarget,'getTag') and
|
|
||||||
self.gizmoTarget.getTag("is_gui_element") == "1")
|
|
||||||
|
|
||||||
|
|
||||||
# 计算鼠标移动距离(屏幕像素)
|
|
||||||
mouseDeltaX = mouseX - self.dragStartMousePos[0]
|
|
||||||
mouseDeltaY = mouseY - self.dragStartMousePos[1]
|
|
||||||
|
|
||||||
if is_scale_tool:
|
|
||||||
scale_factor = 1.0 + (mouseDeltaX + mouseDeltaY) * 0.01
|
|
||||||
|
|
||||||
|
def _apply_scale_drag(self, mouse_delta_x, mouse_delta_y, is_gui_element):
|
||||||
|
scale_factor = 1.0 + (mouse_delta_x + mouse_delta_y) * 0.01
|
||||||
scale_factor = max(0.001, scale_factor)
|
scale_factor = max(0.001, scale_factor)
|
||||||
|
|
||||||
start_scale = getattr(self, 'gizmoTargetStartScale', Vec3(1, 1, 1))
|
start_scale = getattr(self, 'gizmoTargetStartScale', Vec3(1, 1, 1))
|
||||||
|
|
||||||
if is_gui_element:
|
if is_gui_element:
|
||||||
@ -1685,37 +1674,37 @@ class SelectionSystem:
|
|||||||
elif self.dragGizmoAxis == "z":
|
elif self.dragGizmoAxis == "z":
|
||||||
new_scale = Vec3(start_scale.x, start_scale.y, start_scale.z * scale_factor)
|
new_scale = Vec3(start_scale.x, start_scale.y, start_scale.z * scale_factor)
|
||||||
else:
|
else:
|
||||||
new_scale = Vec3(start_scale.x * scale_factor,
|
new_scale = Vec3(
|
||||||
|
start_scale.x * scale_factor,
|
||||||
start_scale.y * scale_factor,
|
start_scale.y * scale_factor,
|
||||||
start_scale.z * scale_factor)
|
start_scale.z * scale_factor,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# 普通3D模型的缩放处理
|
|
||||||
if self.dragGizmoAxis == "x":
|
if self.dragGizmoAxis == "x":
|
||||||
new_scale = Vec3(start_scale.x * scale_factor, start_scale.y, start_scale.z)
|
new_scale = Vec3(start_scale.x * scale_factor, start_scale.y, start_scale.z)
|
||||||
elif self.dragGizmoAxis == "y":
|
elif self.dragGizmoAxis == "y":
|
||||||
new_scale = Vec3(start_scale.x, start_scale.y * scale_factor, start_scale.z)
|
new_scale = Vec3(start_scale.x, start_scale.y * scale_factor, start_scale.z)
|
||||||
elif self.dragGizmoAxis == "z":
|
elif self.dragGizmoAxis == "z":
|
||||||
z_scale_factor = 1.0 - (mouseDeltaX + mouseDeltaY) * 0.01
|
z_scale_factor = 1.0 - (mouse_delta_x + mouse_delta_y) * 0.01
|
||||||
new_scale = Vec3(start_scale.x, start_scale.y, start_scale.z * z_scale_factor)
|
new_scale = Vec3(start_scale.x, start_scale.y, start_scale.z * z_scale_factor)
|
||||||
else:
|
else:
|
||||||
new_scale = Vec3(start_scale.x * scale_factor,
|
new_scale = Vec3(
|
||||||
|
start_scale.x * scale_factor,
|
||||||
start_scale.y * scale_factor,
|
start_scale.y * scale_factor,
|
||||||
start_scale.z * scale_factor)
|
start_scale.z * scale_factor,
|
||||||
|
)
|
||||||
|
|
||||||
new_scale = Vec3(
|
new_scale = Vec3(
|
||||||
max(0.001, new_scale.x),
|
max(0.001, new_scale.x),
|
||||||
max(0.001, new_scale.y),
|
max(0.001, new_scale.y),
|
||||||
max(0.001,new_scale.z)
|
max(0.001, new_scale.z),
|
||||||
)
|
)
|
||||||
|
|
||||||
# 应用新缩放值
|
|
||||||
self.gizmoTarget.setScale(new_scale)
|
self.gizmoTarget.setScale(new_scale)
|
||||||
if hasattr(self.world, 'property_panel') and self.world.property_panel:
|
self._refresh_gizmo_target_panel()
|
||||||
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
|
||||||
return
|
def _apply_rotate_drag(self, mouse_delta_x, mouse_delta_y):
|
||||||
elif is_rotate_tool:
|
|
||||||
rotation_speed = 0.5
|
rotation_speed = 0.5
|
||||||
rotation_amount = (mouseDeltaX + mouseDeltaY) * rotation_speed
|
rotation_amount = (mouse_delta_x + mouse_delta_y) * rotation_speed
|
||||||
start_hpr = getattr(self, 'gizmoTargetStartHpr', self.gizmoTarget.getHpr())
|
start_hpr = getattr(self, 'gizmoTargetStartHpr', self.gizmoTarget.getHpr())
|
||||||
|
|
||||||
if self.dragGizmoAxis == "x":
|
if self.dragGizmoAxis == "x":
|
||||||
@ -1725,41 +1714,31 @@ class SelectionSystem:
|
|||||||
elif self.dragGizmoAxis == "z":
|
elif self.dragGizmoAxis == "z":
|
||||||
new_hpr = Vec3(start_hpr.x, start_hpr.y, start_hpr.z + rotation_amount)
|
new_hpr = Vec3(start_hpr.x, start_hpr.y, start_hpr.z + rotation_amount)
|
||||||
else:
|
else:
|
||||||
# 默认绕所有轴旋转
|
new_hpr = Vec3(
|
||||||
new_hpr = Vec3(start_hpr.x + rotation_amount,
|
start_hpr.x + rotation_amount,
|
||||||
start_hpr.y + rotation_amount,
|
start_hpr.y + rotation_amount,
|
||||||
start_hpr.z + rotation_amount)
|
start_hpr.z + rotation_amount,
|
||||||
|
)
|
||||||
|
|
||||||
self.gizmoTarget.setHpr(new_hpr)
|
self.gizmoTarget.setHpr(new_hpr)
|
||||||
if hasattr(self.world, 'property_panel') and self.world.property_panel:
|
self._refresh_gizmo_target_panel()
|
||||||
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
|
||||||
return
|
|
||||||
|
|
||||||
# 使用坐标轴的实际位置而不是目标节点位置来计算屏幕投影
|
def _get_local_axis_vector(self):
|
||||||
gizmo_world_pos = self.gizmoStartPos
|
|
||||||
|
|
||||||
# 【关键修复】:获取正确的轴向量,考虑父节点的旋转
|
|
||||||
# 检查目标节点是否有父节点
|
|
||||||
parent_node = self.gizmoTarget.getParent()
|
|
||||||
|
|
||||||
# 计算轴向量在正确坐标系中的方向
|
|
||||||
if self.dragGizmoAxis == "x":
|
if self.dragGizmoAxis == "x":
|
||||||
# 在局部坐标系中的X轴方向
|
return Vec3(1, 0, 0)
|
||||||
local_axis_vector = Vec3(1, 0, 0)
|
if self.dragGizmoAxis == "y":
|
||||||
elif self.dragGizmoAxis == "y":
|
return Vec3(0, 1, 0)
|
||||||
# 在局部坐标系中的Y轴方向
|
if self.dragGizmoAxis == "z":
|
||||||
local_axis_vector = Vec3(0, 1, 0)
|
return Vec3(0, 0, 1)
|
||||||
elif self.dragGizmoAxis == "z":
|
|
||||||
# 在局部坐标系中的Z轴方向
|
|
||||||
local_axis_vector = Vec3(0, 0, 1)
|
|
||||||
else:
|
|
||||||
print(f"拖拽更新失败: 未知轴类型 {self.dragGizmoAxis}")
|
print(f"拖拽更新失败: 未知轴类型 {self.dragGizmoAxis}")
|
||||||
return
|
return None
|
||||||
|
|
||||||
|
def _compute_world_axis_vector(self, local_axis_vector):
|
||||||
world_axis_vector = local_axis_vector
|
world_axis_vector = local_axis_vector
|
||||||
|
parent_node = self.gizmoTarget.getParent()
|
||||||
|
|
||||||
if parent_node and parent_node != self.world.render:
|
if parent_node and parent_node != self.world.render:
|
||||||
try:
|
try:
|
||||||
#获取变换矩阵
|
|
||||||
transfrom_mat = parent_node.getMat(self.world.render)
|
transfrom_mat = parent_node.getMat(self.world.render)
|
||||||
if transfrom_mat.is_identity() or self._isMatrixValid(transfrom_mat):
|
if transfrom_mat.is_identity() or self._isMatrixValid(transfrom_mat):
|
||||||
world_axis_vector = transfrom_mat.xformVec(local_axis_vector)
|
world_axis_vector = transfrom_mat.xformVec(local_axis_vector)
|
||||||
@ -1767,77 +1746,27 @@ class SelectionSystem:
|
|||||||
print("警告: 检测到无效变换矩阵,使用默认轴向量")
|
print("警告: 检测到无效变换矩阵,使用默认轴向量")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"变换计算出错: {e},使用默认轴向量")
|
print(f"变换计算出错: {e},使用默认轴向量")
|
||||||
else:
|
|
||||||
world_axis_vector = local_axis_vector
|
|
||||||
|
|
||||||
# 确定轴向量的变换上下文
|
return world_axis_vector
|
||||||
# if parent_node and parent_node != self.world.render:
|
|
||||||
# transform_mat = parent_node.getMat(self.world.render)
|
|
||||||
# world_axis_vector = transform_mat.xformVec(local_axis_vector)
|
|
||||||
# else:
|
|
||||||
# world_axis_vector = local_axis_vector
|
|
||||||
|
|
||||||
#axis_end = gizmo_world_pos + world_axis_vector
|
def _world_to_screen(self, world_pos):
|
||||||
|
|
||||||
# 投影到屏幕空间
|
|
||||||
def worldToScreen(worldPos):
|
|
||||||
try:
|
try:
|
||||||
camPos = self.world.cam.getRelativePoint(self.world.render, worldPos)
|
cam_pos = self.world.cam.getRelativePoint(self.world.render, world_pos)
|
||||||
if camPos.getY() <= 0:
|
if cam_pos.getY() <= 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
screenPos = Point2()
|
screen_pos = Point2()
|
||||||
if self.world.cam.node().getLens().project(camPos, screenPos):
|
if self.world.cam.node().getLens().project(cam_pos, screen_pos):
|
||||||
winWidth, winHeight = self.world.getWindowSize()
|
win_width, win_height = self.world.getWindowSize()
|
||||||
winX = (screenPos.x + 1) * 0.5 * winWidth
|
win_x = (screen_pos.x + 1) * 0.5 * win_width
|
||||||
winY = (1 - screenPos.y) * 0.5 * winHeight
|
win_y = (1 - screen_pos.y) * 0.5 * win_height
|
||||||
return (winX, winY)
|
return win_x, win_y
|
||||||
return None
|
return None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"世界坐标转屏幕坐标失败: {e}")
|
print(f"世界坐标转屏幕坐标失败: {e}")
|
||||||
return None
|
return None
|
||||||
axis_start_screen = worldToScreen(gizmo_world_pos)
|
|
||||||
axis_end_world = gizmo_world_pos + world_axis_vector
|
|
||||||
axis_end_screen = worldToScreen(axis_end_world)
|
|
||||||
|
|
||||||
if not axis_start_screen or not axis_end_screen:
|
|
||||||
print("拖拽更新失败: 无法获取轴线屏幕坐标")
|
|
||||||
return
|
|
||||||
|
|
||||||
screen_axis_dir = (
|
|
||||||
axis_end_screen[0] - axis_start_screen[0],
|
|
||||||
axis_end_screen[1] - axis_start_screen[1]
|
|
||||||
)
|
|
||||||
|
|
||||||
# 归一化屏幕轴方向
|
|
||||||
import math
|
|
||||||
length = math.sqrt(screen_axis_dir[0]**2 + screen_axis_dir[1]**2)
|
|
||||||
if length > 0:
|
|
||||||
#screen_axis_dir = (screen_axis_dir[0] / length, screen_axis_dir[1] / length)
|
|
||||||
screen_axis_dir = (
|
|
||||||
screen_axis_dir[0] / length,
|
|
||||||
screen_axis_dir[1] / length
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
print("拖拽更新失败: 屏幕轴方向长度为0")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 将鼠标移动投影到轴方向上
|
|
||||||
projected_distance = (mouseDeltaX * screen_axis_dir[0] +
|
|
||||||
mouseDeltaY * screen_axis_dir[1])
|
|
||||||
|
|
||||||
cam_pos = self.world.cam.getPos(self.world.render)
|
|
||||||
distance_to_object = (cam_pos - gizmo_world_pos).length()
|
|
||||||
|
|
||||||
lens = self.world.cam.node().getLens()
|
|
||||||
fov = lens.getFov()[0]
|
|
||||||
winWidth,winHeight = self.world.getWindowSize()
|
|
||||||
|
|
||||||
pixels_to_world_units = (2*distance_to_object*math.tan(math.radians(fov/2)))/winWidth
|
|
||||||
|
|
||||||
movement_distance = projected_distance * pixels_to_world_units
|
|
||||||
|
|
||||||
|
def _compute_parent_scale_factor(self):
|
||||||
total_scale_factor = 1.0
|
total_scale_factor = 1.0
|
||||||
current_node = self.gizmoTarget.getParent()
|
current_node = self.gizmoTarget.getParent()
|
||||||
|
|
||||||
@ -1848,71 +1777,133 @@ class SelectionSystem:
|
|||||||
if node_scale.x > 0 and node_scale.y > 0 and node_scale.z > 0:
|
if node_scale.x > 0 and node_scale.y > 0 and node_scale.z > 0:
|
||||||
avg_scale = (node_scale.x + node_scale.y + node_scale.z) / 3.0
|
avg_scale = (node_scale.x + node_scale.y + node_scale.z) / 3.0
|
||||||
total_scale_factor *= avg_scale
|
total_scale_factor *= avg_scale
|
||||||
#avg_scale = (node_scale.x+node_scale.y + node_scale.z) / 3.0
|
|
||||||
#total_scale_factor *= avg_scale
|
|
||||||
current_node = current_node.getParent()
|
current_node = current_node.getParent()
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
except:
|
except Exception:
|
||||||
break
|
break
|
||||||
|
return total_scale_factor
|
||||||
|
|
||||||
|
def _compute_axis_movement_distance(self, mouse_delta_x, mouse_delta_y):
|
||||||
|
gizmo_world_pos = self.gizmoStartPos
|
||||||
|
local_axis_vector = self._get_local_axis_vector()
|
||||||
|
if local_axis_vector is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
world_axis_vector = self._compute_world_axis_vector(local_axis_vector)
|
||||||
|
axis_start_screen = self._world_to_screen(gizmo_world_pos)
|
||||||
|
axis_end_world = gizmo_world_pos + world_axis_vector
|
||||||
|
axis_end_screen = self._world_to_screen(axis_end_world)
|
||||||
|
|
||||||
|
if not axis_start_screen or not axis_end_screen:
|
||||||
|
print("拖拽更新失败: 无法获取轴线屏幕坐标")
|
||||||
|
return None
|
||||||
|
|
||||||
|
screen_axis_dir = (
|
||||||
|
axis_end_screen[0] - axis_start_screen[0],
|
||||||
|
axis_end_screen[1] - axis_start_screen[1],
|
||||||
|
)
|
||||||
|
length = math.sqrt(screen_axis_dir[0] ** 2 + screen_axis_dir[1] ** 2)
|
||||||
|
if length <= 0:
|
||||||
|
print("拖拽更新失败: 屏幕轴方向长度为0")
|
||||||
|
return None
|
||||||
|
|
||||||
|
screen_axis_dir = (
|
||||||
|
screen_axis_dir[0] / length,
|
||||||
|
screen_axis_dir[1] / length,
|
||||||
|
)
|
||||||
|
projected_distance = (
|
||||||
|
mouse_delta_x * screen_axis_dir[0] +
|
||||||
|
mouse_delta_y * screen_axis_dir[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
cam_pos = self.world.cam.getPos(self.world.render)
|
||||||
|
distance_to_object = (cam_pos - gizmo_world_pos).length()
|
||||||
|
lens = self.world.cam.node().getLens()
|
||||||
|
fov = lens.getFov()[0]
|
||||||
|
win_width, _ = self.world.getWindowSize()
|
||||||
|
|
||||||
|
pixels_to_world_units = (2 * distance_to_object * math.tan(math.radians(fov / 2))) / win_width
|
||||||
|
movement_distance = projected_distance * pixels_to_world_units
|
||||||
|
|
||||||
|
total_scale_factor = self._compute_parent_scale_factor()
|
||||||
if total_scale_factor > 0:
|
if total_scale_factor > 0:
|
||||||
movement_distance = movement_distance / total_scale_factor
|
movement_distance = movement_distance / total_scale_factor
|
||||||
|
|
||||||
currentPos = self.gizmoTargetStartPos
|
return movement_distance
|
||||||
|
|
||||||
|
def _apply_translate_drag(self, movement_distance):
|
||||||
|
current_pos = self.gizmoTargetStartPos
|
||||||
|
|
||||||
# 根据拖拽的轴,只修改对应的坐标分量
|
|
||||||
if self.dragGizmoAxis == "x":
|
if self.dragGizmoAxis == "x":
|
||||||
newPos = Vec3(currentPos.x + movement_distance, currentPos.y, currentPos.z)
|
new_pos = Vec3(current_pos.x + movement_distance, current_pos.y, current_pos.z)
|
||||||
#print(f"X轴移动:{currentPos.x} -> {newPos.x}")
|
|
||||||
elif self.dragGizmoAxis == "y":
|
elif self.dragGizmoAxis == "y":
|
||||||
newPos = Vec3(currentPos.x, currentPos.y + movement_distance, currentPos.z)
|
new_pos = Vec3(current_pos.x, current_pos.y + movement_distance, current_pos.z)
|
||||||
#print(f"Y轴移动:{currentPos.y} -> {newPos.y}")
|
|
||||||
elif self.dragGizmoAxis == "z":
|
elif self.dragGizmoAxis == "z":
|
||||||
newPos = Vec3(currentPos.x, currentPos.y, currentPos.z + movement_distance)
|
new_pos = Vec3(current_pos.x, current_pos.y, current_pos.z + movement_distance)
|
||||||
#print(f"Z轴移动:{currentPos.z} -> {newPos.z}")
|
|
||||||
else:
|
else:
|
||||||
print(f"未知轴: {self.dragGizmoAxis}")
|
print(f"未知轴: {self.dragGizmoAxis}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# 应用新位置到目标节点
|
|
||||||
light_object = self.gizmoTarget.getPythonTag("rp_light_object")
|
light_object = self.gizmoTarget.getPythonTag("rp_light_object")
|
||||||
if light_object:
|
if light_object:
|
||||||
self.gizmoTarget.setPos(newPos)
|
self.gizmoTarget.setPos(new_pos)
|
||||||
self._sync_rp_light_position(self.gizmoTarget, light_object)
|
self._sync_rp_light_position(self.gizmoTarget, light_object)
|
||||||
print(f"🔄 光源拖拽移动: {currentPos} -> {newPos}")
|
print(f"🔄 光源拖拽移动: {current_pos} -> {new_pos}")
|
||||||
else:
|
else:
|
||||||
self.gizmoTarget.setPos(newPos)
|
self.gizmoTarget.setPos(new_pos)
|
||||||
print(f"🔄 节点拖拽移动: {currentPos} -> {newPos} (轴: {self.dragGizmoAxis}, 距离: {movement_distance:.3f})")
|
print(f"🔄 节点拖拽移动: {current_pos} -> {new_pos} (轴: {self.dragGizmoAxis}, 距离: {movement_distance:.3f})")
|
||||||
|
|
||||||
# 更新属性面板
|
self._refresh_gizmo_target_panel()
|
||||||
if hasattr(self.world, 'property_panel') and self.world.property_panel:
|
|
||||||
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
|
||||||
|
|
||||||
# 更新坐标轴位置 - 计算新的中心位置
|
min_point = Point3()
|
||||||
minPoint = Point3()
|
max_point = Point3()
|
||||||
maxPoint = Point3()
|
if self.gizmoTarget.calcTightBounds(min_point, max_point, self.world.render):
|
||||||
if self.gizmoTarget.calcTightBounds(minPoint, maxPoint, self.world.render):
|
center = Point3(
|
||||||
center = Point3((minPoint.x + maxPoint.x) * 0.5,
|
(min_point.x + max_point.x) * 0.5,
|
||||||
(minPoint.y + maxPoint.y) * 0.5,
|
(min_point.y + max_point.y) * 0.5,
|
||||||
(minPoint.z + maxPoint.z) * 0.5)
|
(min_point.z + max_point.z) * 0.5,
|
||||||
|
)
|
||||||
self.gizmo.setPos(center)
|
self.gizmo.setPos(center)
|
||||||
|
|
||||||
# 实时更新属性面板
|
self._refresh_gizmo_target_panel()
|
||||||
if hasattr(self.world, 'property_panel') and self.world.property_panel:
|
|
||||||
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
|
||||||
|
|
||||||
# 每次拖拽都输出调试信息(但限制频率)
|
|
||||||
if not hasattr(self, '_last_drag_debug_time'):
|
if not hasattr(self, '_last_drag_debug_time'):
|
||||||
self._last_drag_debug_time = 0
|
self._last_drag_debug_time = 0
|
||||||
|
|
||||||
import time
|
import time
|
||||||
current_time = time.time()
|
current_time = time.time()
|
||||||
if current_time - self._last_drag_debug_time > 0.1: # 每0.1秒最多输出一次
|
if current_time - self._last_drag_debug_time > 0.1:
|
||||||
#print(f"拖拽更新成功 - 轴:{self.dragGizmoAxis}, 比例:{scale_factor:.6f}, 投影:{projected_distance:.2f}")
|
|
||||||
self._last_drag_debug_time = current_time
|
self._last_drag_debug_time = current_time
|
||||||
|
|
||||||
|
def updateGizmoDrag(self, mouseX, mouseY):
|
||||||
|
"""更新坐标轴拖拽 - 使用正确的坐标系变换,支持旋转后的子节点拖拽"""
|
||||||
|
try:
|
||||||
|
if not self._validate_gizmo_drag_state():
|
||||||
|
return
|
||||||
|
|
||||||
|
is_scale_tool = self.world.tool_manager.isScaleTool() if self.world.tool_manager else False
|
||||||
|
is_rotate_tool = self.world.tool_manager.isRotateTool() if self.world.tool_manager else False
|
||||||
|
is_gui_element = (
|
||||||
|
hasattr(self.gizmoTarget, 'getTag') and
|
||||||
|
self.gizmoTarget.getTag("is_gui_element") == "1"
|
||||||
|
)
|
||||||
|
|
||||||
|
mouse_delta_x = mouseX - self.dragStartMousePos[0]
|
||||||
|
mouse_delta_y = mouseY - self.dragStartMousePos[1]
|
||||||
|
|
||||||
|
if is_scale_tool:
|
||||||
|
self._apply_scale_drag(mouse_delta_x, mouse_delta_y, is_gui_element)
|
||||||
|
return
|
||||||
|
if is_rotate_tool:
|
||||||
|
self._apply_rotate_drag(mouse_delta_x, mouse_delta_y)
|
||||||
|
return
|
||||||
|
|
||||||
|
movement_distance = self._compute_axis_movement_distance(mouse_delta_x, mouse_delta_y)
|
||||||
|
if movement_distance is None:
|
||||||
|
return
|
||||||
|
self._apply_translate_drag(movement_distance)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"更新坐标轴拖拽失败: {str(e)}")
|
print(f"更新坐标轴拖拽失败: {str(e)}")
|
||||||
import traceback
|
import traceback
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user