forked from Rowland/EG
修复缩放影响子节点移动
This commit is contained in:
parent
602f172e32
commit
ef2c8b777c
2
.idea/AugmentWebviewStateStore.xml
generated
2
.idea/AugmentWebviewStateStore.xml
generated
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1187,44 +1187,32 @@ class SelectionSystem:
|
||||
# 检查目标节点是否有父节点
|
||||
parent_node = self.gizmoTarget.getParent()
|
||||
|
||||
# 确定轴向量的变换上下文
|
||||
if parent_node and parent_node != self.world.render:
|
||||
# 子节点:使用父节点的局部坐标系
|
||||
print(f"子节点拖拽 - 父节点: {parent_node.getName()}, 父节点旋转: {parent_node.getHpr()}")
|
||||
transform_context = parent_node
|
||||
else:
|
||||
# 顶级模型:使用世界坐标系
|
||||
print(f"顶级模型拖拽 - 使用世界坐标系")
|
||||
transform_context = self.world.render
|
||||
|
||||
# 计算轴向量在正确坐标系中的方向
|
||||
if self.dragGizmoAxis == "x":
|
||||
# 在变换上下文中的X轴方向
|
||||
# 在局部坐标系中的X轴方向
|
||||
local_axis_vector = Vec3(1, 0, 0)
|
||||
elif self.dragGizmoAxis == "y":
|
||||
# 在变换上下文中的Y轴方向
|
||||
# 在局部坐标系中的Y轴方向
|
||||
local_axis_vector = Vec3(0, 1, 0)
|
||||
elif self.dragGizmoAxis == "z":
|
||||
# 在变换上下文中的Z轴方向
|
||||
# 在局部坐标系中的Z轴方向
|
||||
local_axis_vector = Vec3(0, 0, 1)
|
||||
else:
|
||||
print(f"拖拽更新失败: 未知轴类型 {self.dragGizmoAxis}")
|
||||
return
|
||||
|
||||
# 将局部轴向量转换到世界坐标系(用于屏幕投影)
|
||||
if transform_context != self.world.render:
|
||||
# 获取变换矩阵并应用到轴向量上
|
||||
transform_mat = transform_context.getMat(self.world.render)
|
||||
# 只旋转向量,不平移
|
||||
# 确定轴向量的变换上下文
|
||||
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)
|
||||
world_axis_vector.normalize() # 归一化
|
||||
print(f"转换后的轴向量: {local_axis_vector} -> {world_axis_vector}")
|
||||
else:
|
||||
# 顶级节点,直接使用世界轴向量
|
||||
world_axis_vector = local_axis_vector
|
||||
print(f"世界轴向量: {world_axis_vector}")
|
||||
|
||||
# 计算轴的端点位置(用于屏幕投影)
|
||||
# 顶级模型:使用世界坐标系
|
||||
# print(f"顶级模型拖拽 - 使用世界坐标系")
|
||||
# transform_context = self.world.render
|
||||
axis_end = gizmo_world_pos + world_axis_vector
|
||||
|
||||
# 投影到屏幕空间
|
||||
@ -1279,83 +1267,62 @@ class SelectionSystem:
|
||||
projected_distance = (mouseDeltaX * screen_axis_dir[0] +
|
||||
mouseDeltaY * screen_axis_dir[1])
|
||||
|
||||
# 计算动态比例因子,基于相机距离和视野角度
|
||||
cam_pos = self.world.cam.getPos()
|
||||
distance_to_object = (cam_pos - gizmo_world_pos).length()
|
||||
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
|
||||
|
||||
# 获取相机的视野角度
|
||||
fov = self.world.cam.node().getLens().getFov()[0] # 水平视野角度
|
||||
fov_radians = math.radians(fov)
|
||||
|
||||
# 获取窗口尺寸
|
||||
winWidth, winHeight = self.world.getWindowSize()
|
||||
fixed_pixel_to_world_ratio = 0.01 # 1像素 = 0.01世界单位
|
||||
scale_factor = fixed_pixel_to_world_ratio * scale_adjustment
|
||||
|
||||
# 计算一个像素在世界坐标系中的大小(在目标物体的距离处)
|
||||
# 使用透视投影公式:world_size = screen_size * distance * tan(fov/2) / (screen_width/2)
|
||||
pixel_to_world_ratio = distance_to_object * math.tan(fov_radians / 2) / (winWidth / 2)
|
||||
|
||||
# 【改进修复】:智能缩放补偿,区分继承缩放和本体缩放
|
||||
# 计算父节点链的累积缩放(不包括目标节点本身)
|
||||
parent_cumulative_scale = 1.0
|
||||
current_node = self.gizmoTarget.getParent()
|
||||
while current_node and current_node != self.world.render:
|
||||
node_scale = current_node.getScale()
|
||||
# 使用缩放的几何平均值作为累积因子
|
||||
scale_magnitude = (abs(node_scale.x) * abs(node_scale.y) * abs(node_scale.z)) ** (1.0/3.0)
|
||||
parent_cumulative_scale *= scale_magnitude
|
||||
current_node = current_node.getParent()
|
||||
|
||||
# 获取目标节点自身的缩放
|
||||
target_scale = self.gizmoTarget.getScale()
|
||||
target_scale_magnitude = (abs(target_scale.x) * abs(target_scale.y) * abs(target_scale.z)) ** (1.0/3.0)
|
||||
|
||||
# 智能补偿策略:
|
||||
# 1. 只对父节点链的小缩放进行完全补偿(这通常是单位转换导致的)
|
||||
# 2. 对目标节点自身的缩放进行部分补偿(避免大模型缩小后移动过快)
|
||||
parent_compensation = 1.0 / parent_cumulative_scale if parent_cumulative_scale > 0 else 1.0
|
||||
|
||||
# 对目标节点自身的缩放使用平方根补偿,减少过度补偿
|
||||
target_compensation = 1.0 / math.sqrt(target_scale_magnitude) if target_scale_magnitude > 0 else 1.0
|
||||
|
||||
# 限制目标补偿的最大值,避免移动过快
|
||||
target_compensation = min(target_compensation, 10.0) # 最大10倍补偿
|
||||
|
||||
# 综合补偿因子
|
||||
total_compensation = parent_compensation * target_compensation
|
||||
scale_factor = pixel_to_world_ratio * 0.5*total_compensation
|
||||
|
||||
# 【关键修复】:在正确的坐标系中计算移动向量
|
||||
# 计算移动距离(标量)
|
||||
movement_distance = projected_distance * scale_factor
|
||||
|
||||
# 在正确的坐标系中计算移动向量
|
||||
if transform_context != self.world.render:
|
||||
# 子节点:在父节点的局部坐标系中移动
|
||||
if self.dragGizmoAxis == "x":
|
||||
movement_local = Vec3(movement_distance, 0, 0)
|
||||
elif self.dragGizmoAxis == "y":
|
||||
movement_local = Vec3(0, movement_distance, 0)
|
||||
elif self.dragGizmoAxis == "z":
|
||||
movement_local = Vec3(0, 0, movement_distance)
|
||||
|
||||
# 将局部移动向量转换到父节点的坐标系中
|
||||
# 由于我们要应用到目标节点上,而目标节点相对于父节点,我们直接使用局部移动
|
||||
movement = movement_local
|
||||
print(f"子节点移动向量(局部): {movement}")
|
||||
# 获取当前位置并只修改选中轴的坐标
|
||||
currentPos = self.gizmoTargetStartPos
|
||||
|
||||
# 根据拖拽的轴,只修改对应的坐标分量
|
||||
if self.dragGizmoAxis == "x":
|
||||
newPos = Vec3(currentPos.x + movement_distance, currentPos.y, currentPos.z)
|
||||
print(f"X轴移动:{currentPos.x} -> {newPos.x}")
|
||||
elif self.dragGizmoAxis == "y":
|
||||
newPos = Vec3(currentPos.x, currentPos.y + movement_distance, currentPos.z)
|
||||
print(f"Y轴移动:{currentPos.y} -> {newPos.y}")
|
||||
elif self.dragGizmoAxis == "z":
|
||||
newPos = Vec3(currentPos.x, currentPos.y, currentPos.z + movement_distance)
|
||||
print(f"Z轴移动:{currentPos.z} -> {newPos.z}")
|
||||
else:
|
||||
# 顶级模型:在世界坐标系中移动
|
||||
if self.dragGizmoAxis == "x":
|
||||
movement = Vec3(movement_distance, 0, 0)
|
||||
elif self.dragGizmoAxis == "y":
|
||||
movement = Vec3(0, movement_distance, 0)
|
||||
elif self.dragGizmoAxis == "z":
|
||||
movement = Vec3(0, 0, movement_distance)
|
||||
print(f"顶级模型移动向量(世界): {movement}")
|
||||
|
||||
# 应用移动到目标节点
|
||||
newPos = self.gizmoTargetStartPos + movement
|
||||
self.gizmoTarget.setPos(newPos)
|
||||
print(f"未知轴: {self.dragGizmoAxis}")
|
||||
return
|
||||
|
||||
# 应用新位置到目标节点
|
||||
light_object = self.gizmoTarget.getPythonTag("rp_light_object")
|
||||
if light_object:
|
||||
light_object.pos = newPos
|
||||
self.gizmoTarget.setPos(newPos)
|
||||
else:
|
||||
self.gizmoTarget.setPos(newPos)
|
||||
|
||||
# 更新坐标轴位置 - 计算新的中心位置
|
||||
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)
|
||||
self.gizmo.setPos(center)
|
||||
|
||||
# 实时更新属性面板
|
||||
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
||||
|
||||
# 每次拖拽都输出调试信息(但限制频率)
|
||||
@ -1365,18 +1332,9 @@ class SelectionSystem:
|
||||
import time
|
||||
current_time = time.time()
|
||||
if current_time - self._last_drag_debug_time > 0.1: # 每0.1秒最多输出一次
|
||||
print(f"拖拽更新成功 - 轴:{self.dragGizmoAxis}, 距离:{distance_to_object:.2f}, 比例:{scale_factor:.6f}, 投影:{projected_distance:.2f}")
|
||||
print(f"拖拽更新成功 - 轴:{self.dragGizmoAxis}, 比例:{scale_factor:.6f}, 投影:{projected_distance:.2f}")
|
||||
self._last_drag_debug_time = current_time
|
||||
|
||||
newPos = self.gizmoTargetStartPos + movement
|
||||
light_object = self.gizmoTarget.getPythonTag("rp_light_object")
|
||||
if light_object:
|
||||
light_object.pos = newPos
|
||||
self.gizmoTarget.setPos(newPos)
|
||||
else:
|
||||
self.gizmoTarget.setPos(newPos)
|
||||
self.gizmo.setPos(newPos)
|
||||
|
||||
except Exception as e:
|
||||
print(f"更新坐标轴拖拽失败: {str(e)}")
|
||||
import traceback
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -391,7 +391,8 @@ class MainWindow(QMainWindow):
|
||||
self.createPointLight.clicked.connect(lambda :self.world.createPointLight())
|
||||
|
||||
# 连接树节点点击信号
|
||||
self.treeWidget.itemClicked.connect(self.world.onTreeItemClicked)
|
||||
# self.treeWidget.itemClicked.connect(self.world.onTreeItemClicked)
|
||||
self.treeWidget.itemSelectionChanged.connect(lambda :self.world.onTreeItemClicked(self.treeWidget.currentItem(), 0))
|
||||
print("已连接点击信号")
|
||||
|
||||
# 连接工具切换信号
|
||||
|
||||
Loading…
Reference in New Issue
Block a user