refactor: 拆分updateGizmoDrag并同步任务文档

This commit is contained in:
ayuan9957 2026-03-01 12:16:08 +08:00
parent d32a604c2f
commit 4f70cc113b

View File

@ -1639,42 +1639,31 @@ class SelectionSystem:
import traceback
traceback.print_exc()
def updateGizmoDrag(self, mouseX, mouseY):
"""更新坐标轴拖拽 - 使用正确的坐标系变换,支持旋转后的子节点拖拽"""
try:
# 添加详细的状态检查和调试信息
def _validate_gizmo_drag_state(self):
if not self.isDraggingGizmo:
print("拖拽更新失败: 不在拖拽状态")
return
return False
if not self.gizmoTarget:
print("拖拽更新失败: 没有拖拽目标")
return
return False
if not hasattr(self, 'dragStartMousePos') or not self.dragStartMousePos:
print("拖拽更新失败: 没有拖拽起始位置")
return
return False
if not hasattr(self, 'gizmoTargetStartPos') or not self.gizmoTargetStartPos:
print("拖拽更新失败: 没有目标起始位置")
return
return False
if not hasattr(self, 'gizmoStartPos') or not self.gizmoStartPos:
print("拖拽更新失败: 没有坐标轴起始位置")
return
return False
return True
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")
# 计算鼠标移动距离(屏幕像素)
mouseDeltaX = mouseX - self.dragStartMousePos[0]
mouseDeltaY = mouseY - self.dragStartMousePos[1]
if is_scale_tool:
scale_factor = 1.0 + (mouseDeltaX + mouseDeltaY) * 0.01
def _refresh_gizmo_target_panel(self):
if hasattr(self.world, 'property_panel') and self.world.property_panel:
self.world.property_panel.refreshModelValues(self.gizmoTarget)
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)
start_scale = getattr(self, 'gizmoTargetStartScale', Vec3(1, 1, 1))
if is_gui_element:
@ -1685,37 +1674,37 @@ class SelectionSystem:
elif self.dragGizmoAxis == "z":
new_scale = Vec3(start_scale.x, start_scale.y, start_scale.z * scale_factor)
else:
new_scale = Vec3(start_scale.x * scale_factor,
new_scale = Vec3(
start_scale.x * scale_factor,
start_scale.y * scale_factor,
start_scale.z * scale_factor)
start_scale.z * scale_factor,
)
else:
# 普通3D模型的缩放处理
if self.dragGizmoAxis == "x":
new_scale = Vec3(start_scale.x * scale_factor, start_scale.y, start_scale.z)
elif self.dragGizmoAxis == "y":
new_scale = Vec3(start_scale.x, start_scale.y * scale_factor, start_scale.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)
else:
new_scale = Vec3(start_scale.x * scale_factor,
new_scale = Vec3(
start_scale.x * scale_factor,
start_scale.y * scale_factor,
start_scale.z * scale_factor)
start_scale.z * scale_factor,
)
new_scale = Vec3(
max(0.001, new_scale.x),
max(0.001, new_scale.y),
max(0.001,new_scale.z)
max(0.001, new_scale.z),
)
# 应用新缩放值
self.gizmoTarget.setScale(new_scale)
if hasattr(self.world, 'property_panel') and self.world.property_panel:
self.world.property_panel.refreshModelValues(self.gizmoTarget)
return
elif is_rotate_tool:
self._refresh_gizmo_target_panel()
def _apply_rotate_drag(self, mouse_delta_x, mouse_delta_y):
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())
if self.dragGizmoAxis == "x":
@ -1725,41 +1714,31 @@ class SelectionSystem:
elif self.dragGizmoAxis == "z":
new_hpr = Vec3(start_hpr.x, start_hpr.y, start_hpr.z + rotation_amount)
else:
# 默认绕所有轴旋转
new_hpr = Vec3(start_hpr.x + rotation_amount,
new_hpr = Vec3(
start_hpr.x + rotation_amount,
start_hpr.y + rotation_amount,
start_hpr.z + rotation_amount)
start_hpr.z + rotation_amount,
)
self.gizmoTarget.setHpr(new_hpr)
if hasattr(self.world, 'property_panel') and self.world.property_panel:
self.world.property_panel.refreshModelValues(self.gizmoTarget)
return
self._refresh_gizmo_target_panel()
# 使用坐标轴的实际位置而不是目标节点位置来计算屏幕投影
gizmo_world_pos = self.gizmoStartPos
# 【关键修复】:获取正确的轴向量,考虑父节点的旋转
# 检查目标节点是否有父节点
parent_node = self.gizmoTarget.getParent()
# 计算轴向量在正确坐标系中的方向
def _get_local_axis_vector(self):
if self.dragGizmoAxis == "x":
# 在局部坐标系中的X轴方向
local_axis_vector = Vec3(1, 0, 0)
elif self.dragGizmoAxis == "y":
# 在局部坐标系中的Y轴方向
local_axis_vector = Vec3(0, 1, 0)
elif self.dragGizmoAxis == "z":
# 在局部坐标系中的Z轴方向
local_axis_vector = Vec3(0, 0, 1)
else:
return Vec3(1, 0, 0)
if self.dragGizmoAxis == "y":
return Vec3(0, 1, 0)
if self.dragGizmoAxis == "z":
return Vec3(0, 0, 1)
print(f"拖拽更新失败: 未知轴类型 {self.dragGizmoAxis}")
return
return None
def _compute_world_axis_vector(self, local_axis_vector):
world_axis_vector = local_axis_vector
parent_node = self.gizmoTarget.getParent()
if parent_node and parent_node != self.world.render:
try:
#获取变换矩阵
transfrom_mat = parent_node.getMat(self.world.render)
if transfrom_mat.is_identity() or self._isMatrixValid(transfrom_mat):
world_axis_vector = transfrom_mat.xformVec(local_axis_vector)
@ -1767,77 +1746,27 @@ class SelectionSystem:
print("警告: 检测到无效变换矩阵,使用默认轴向量")
except Exception as e:
print(f"变换计算出错: {e},使用默认轴向量")
else:
world_axis_vector = local_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
return world_axis_vector
#axis_end = gizmo_world_pos + world_axis_vector
# 投影到屏幕空间
def worldToScreen(worldPos):
def _world_to_screen(self, world_pos):
try:
camPos = self.world.cam.getRelativePoint(self.world.render, worldPos)
if camPos.getY() <= 0:
cam_pos = self.world.cam.getRelativePoint(self.world.render, world_pos)
if cam_pos.getY() <= 0:
return None
screenPos = Point2()
if self.world.cam.node().getLens().project(camPos, screenPos):
winWidth, winHeight = self.world.getWindowSize()
winX = (screenPos.x + 1) * 0.5 * winWidth
winY = (1 - screenPos.y) * 0.5 * winHeight
return (winX, winY)
screen_pos = Point2()
if self.world.cam.node().getLens().project(cam_pos, screen_pos):
win_width, win_height = self.world.getWindowSize()
win_x = (screen_pos.x + 1) * 0.5 * win_width
win_y = (1 - screen_pos.y) * 0.5 * win_height
return win_x, win_y
return None
except Exception as e:
print(f"世界坐标转屏幕坐标失败: {e}")
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
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:
avg_scale = (node_scale.x + node_scale.y + node_scale.z) / 3.0
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()
else:
break
except:
except Exception:
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:
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":
newPos = Vec3(currentPos.x + movement_distance, currentPos.y, currentPos.z)
#print(f"X轴移动{currentPos.x} -> {newPos.x}")
new_pos = Vec3(current_pos.x + movement_distance, current_pos.y, current_pos.z)
elif self.dragGizmoAxis == "y":
newPos = Vec3(currentPos.x, currentPos.y + movement_distance, currentPos.z)
#print(f"Y轴移动{currentPos.y} -> {newPos.y}")
new_pos = Vec3(current_pos.x, current_pos.y + movement_distance, current_pos.z)
elif self.dragGizmoAxis == "z":
newPos = Vec3(currentPos.x, currentPos.y, currentPos.z + movement_distance)
#print(f"Z轴移动{currentPos.z} -> {newPos.z}")
new_pos = Vec3(current_pos.x, current_pos.y, current_pos.z + movement_distance)
else:
print(f"未知轴: {self.dragGizmoAxis}")
return
# 应用新位置到目标节点
light_object = self.gizmoTarget.getPythonTag("rp_light_object")
if light_object:
self.gizmoTarget.setPos(newPos)
self.gizmoTarget.setPos(new_pos)
self._sync_rp_light_position(self.gizmoTarget, light_object)
print(f"🔄 光源拖拽移动: {currentPos} -> {newPos}")
print(f"🔄 光源拖拽移动: {current_pos} -> {new_pos}")
else:
self.gizmoTarget.setPos(newPos)
print(f"🔄 节点拖拽移动: {currentPos} -> {newPos} (轴: {self.dragGizmoAxis}, 距离: {movement_distance:.3f})")
self.gizmoTarget.setPos(new_pos)
print(f"🔄 节点拖拽移动: {current_pos} -> {new_pos} (轴: {self.dragGizmoAxis}, 距离: {movement_distance:.3f})")
# 更新属性面板
if hasattr(self.world, 'property_panel') and self.world.property_panel:
self.world.property_panel.refreshModelValues(self.gizmoTarget)
self._refresh_gizmo_target_panel()
# 更新坐标轴位置 - 计算新的中心位置
minPoint = Point3()
maxPoint = Point3()
if self.gizmoTarget.calcTightBounds(minPoint, maxPoint, self.world.render):
center = Point3((minPoint.x + maxPoint.x) * 0.5,
(minPoint.y + maxPoint.y) * 0.5,
(minPoint.z + maxPoint.z) * 0.5)
min_point = Point3()
max_point = Point3()
if self.gizmoTarget.calcTightBounds(min_point, max_point, self.world.render):
center = Point3(
(min_point.x + max_point.x) * 0.5,
(min_point.y + max_point.y) * 0.5,
(min_point.z + max_point.z) * 0.5,
)
self.gizmo.setPos(center)
# 实时更新属性面板
if hasattr(self.world, 'property_panel') and self.world.property_panel:
self.world.property_panel.refreshModelValues(self.gizmoTarget)
self._refresh_gizmo_target_panel()
# 每次拖拽都输出调试信息(但限制频率)
if not hasattr(self, '_last_drag_debug_time'):
self._last_drag_debug_time = 0
import time
current_time = time.time()
if current_time - self._last_drag_debug_time > 0.1: # 每0.1秒最多输出一次
#print(f"拖拽更新成功 - 轴:{self.dragGizmoAxis}, 比例:{scale_factor:.6f}, 投影:{projected_distance:.2f}")
if current_time - self._last_drag_debug_time > 0.1:
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:
print(f"更新坐标轴拖拽失败: {str(e)}")
import traceback