修复世界位置更新,节点拖动逻辑改进,所有节点不受父级缩放影响

This commit is contained in:
Hector 2025-08-18 11:49:39 +08:00
parent 0cce93b05a
commit ad59e573be
3 changed files with 94 additions and 47 deletions

File diff suppressed because one or more lines are too long

View File

@ -1282,33 +1282,23 @@ class SelectionSystem:
# 确定轴向量的变换上下文
if parent_node and parent_node != self.world.render:
# 子节点:使用父节点的局部坐标系
# print(f"子节点拖拽 - 父节点: {parent_node.getName()}, 父节点旋转: {parent_node.getHpr()}")
# transform_context = parent_node
transform_mat = parent_node.getMat(self.world.render)
world_axis_vector = transform_mat.xformVec(local_axis_vector)
else:
world_axis_vector = local_axis_vector
# 顶级模型:使用世界坐标系
# print(f"顶级模型拖拽 - 使用世界坐标系")
# transform_context = self.world.render
axis_end = gizmo_world_pos + world_axis_vector
#axis_end = gizmo_world_pos + world_axis_vector
# 投影到屏幕空间
def worldToScreen(worldPos):
try:
# 先转换为相机坐标系
camPos = self.world.cam.getRelativePoint(self.world.render, worldPos)
# 检查是否在相机前方
if camPos.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)
@ -1316,28 +1306,45 @@ class SelectionSystem:
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)
#gizmo_screen = worldToScreen(gizmo_world_pos)
#axis_screen = worldToScreen(axis_end)
gizmo_screen = worldToScreen(gizmo_world_pos)
axis_screen = worldToScreen(axis_end)
# if not gizmo_screen:
# print("拖拽更新失败: 坐标轴中心不在屏幕内")
# return
# if not axis_screen:
# print("拖拽更新失败: 坐标轴端点不在屏幕内")
# return
#
# # 计算轴在屏幕空间的方向向量
# screen_axis_dir = (
# axis_screen[0] - gizmo_screen[0],
# axis_screen[1] - gizmo_screen[1]
# )
if not gizmo_screen:
print("拖拽更新失败: 坐标轴中心不在屏幕内")
return
if not axis_screen:
print("拖拽更新失败: 坐标轴端点不在屏幕内")
if not axis_start_screen or not axis_end_screen:
print("拖拽更新失败: 无法获取轴线屏幕坐标")
return
# 计算轴在屏幕空间的方向向量
screen_axis_dir = (
axis_screen[0] - gizmo_screen[0],
axis_screen[1] - gizmo_screen[1]
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)
screen_axis_dir = (
screen_axis_dir[0] / length,
screen_axis_dir[1] / length
)
else:
print("拖拽更新失败: 屏幕轴方向长度为0")
return
@ -1346,29 +1353,54 @@ class SelectionSystem:
projected_distance = (mouseDeltaX * screen_axis_dir[0] +
mouseDeltaY * screen_axis_dir[1])
scale_adjustment = 1.0
if parent_node and parent_node!= self.world.render:
current_node = parent_node
total_scale = 1.0
while current_node and current_node != self.world.render:
node_scale = current_node.getScale()
avg_scale = (node_scale.x+node_scale.y + node_scale.z)/3.0
total_scale *= avg_scale
current_node = current_node.getParent()
if total_scale>0:
scale_adjustment = 1.0 / total_scale
# parent_scale = parent_node.getScale()
# avg_scale = (parent_scale.x+parent_scale.y+parent_scale.z)/3.0
# if avg_scale>0:
# scale_adjustment = 1.0 / avg_scale
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()
fixed_pixel_to_world_ratio = 0.01 # 1像素 = 0.01世界单位
scale_factor = fixed_pixel_to_world_ratio * scale_adjustment
pixels_to_world_units = (2*distance_to_object*math.tan(math.radians(fov/2)))/winWidth
movement_distance = projected_distance * pixels_to_world_units
total_scale_factor = 1.0
current_node = self.gizmoTarget.getParent()
while current_node and current_node != self.world.render:
node_scale = current_node.getScale()
avg_scale = (node_scale.x+node_scale.y + node_scale.z) / 3.0
total_scale_factor *= avg_scale
current_node = current_node.getParent()
if total_scale_factor > 0:
movement_distance = movement_distance / total_scale_factor
movement_distance = projected_distance * scale_factor
# 获取当前位置并只修改选中轴的坐标
currentPos = self.gizmoTargetStartPos
# scale_adjustment = 1.0
# if parent_node and parent_node!= self.world.render:
# current_node = parent_node
# total_scale = 1.0
# while current_node and current_node != self.world.render:
# node_scale = current_node.getScale()
# avg_scale = (node_scale.x+node_scale.y + node_scale.z)/3.0
# total_scale *= avg_scale
# current_node = current_node.getParent()
# if total_scale>0:
# scale_adjustment = 1.0 / total_scale
# # parent_scale = parent_node.getScale()
# # avg_scale = (parent_scale.x+parent_scale.y+parent_scale.z)/3.0
# # if avg_scale>0:
# # scale_adjustment = 1.0 / avg_scale
#
#
# fixed_pixel_to_world_ratio = 0.01 # 1像素 = 0.01世界单位
# scale_factor = fixed_pixel_to_world_ratio * scale_adjustment
#
# movement_distance = projected_distance * scale_factor
# # 获取当前位置并只修改选中轴的坐标
# currentPos = self.gizmoTargetStartPos
# 根据拖拽的轴,只修改对应的坐标分量
if self.dragGizmoAxis == "x":
@ -1411,7 +1443,7 @@ class SelectionSystem:
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}")
#print(f"拖拽更新成功 - 轴:{self.dragGizmoAxis}, 比例:{scale_factor:.6f}, 投影:{projected_distance:.2f}")
self._last_drag_debug_time = current_time
except Exception as e:

View File

@ -192,9 +192,24 @@ class PropertyPanelManager:
self.pos_z.setValue(relativePos.getZ())
# 连接位置变化事件
self.pos_x.valueChanged.connect(lambda v: model.setX(parent, v) if parent else model.setX(v))
self.pos_y.valueChanged.connect(lambda v: model.setY(parent, v) if parent else model.setY(v))
self.pos_z.valueChanged.connect(lambda v: model.setZ(parent, v) if parent else model.setZ(v))
# self.pos_x.valueChanged.connect(lambda v: model.setX(parent, v) if parent else model.setX(v))
# self.pos_y.valueChanged.connect(lambda v: model.setY(parent, v) if parent else model.setY(v))
# self.pos_z.valueChanged.connect(lambda v: model.setZ(parent, v) if parent else model.setZ(v))
def updateXPosition(value):
model.setX(value)
self.refreshModelValues(model)
self.pos_x.valueChanged.connect(updateXPosition)
def updateYPosition(value):
model.setY(value)
self.refreshModelValues(model)
self.pos_y.valueChanged.connect(updateYPosition)
def updateZPosition(value):
model.setZ(value)
self.refreshModelValues(model)
self.pos_z.valueChanged.connect(updateZPosition)
# 创建并设置 X, Y, Z 标签居中
x_label1 = QLabel("X")