坐标轴控制旋转,缩放
This commit is contained in:
parent
48c90034df
commit
8e8564048e
File diff suppressed because one or more lines are too long
BIN
core/RotationHandleFull.fbx
Executable file
BIN
core/RotationHandleFull.fbx
Executable file
Binary file not shown.
BIN
core/RotationHandleQuarter.fbx
Executable file
BIN
core/RotationHandleQuarter.fbx
Executable file
Binary file not shown.
BIN
core/UniformScaleHandle.fbx
Executable file
BIN
core/UniformScaleHandle.fbx
Executable file
Binary file not shown.
@ -11,7 +11,7 @@ from PIL.ImageChops import lighter
|
|||||||
from panda3d.core import (Vec3, Point3, Point2, LineSegs, ColorAttrib, RenderState,
|
from panda3d.core import (Vec3, Point3, Point2, LineSegs, ColorAttrib, RenderState,
|
||||||
DepthTestAttrib, CollisionTraverser, CollisionHandlerQueue,
|
DepthTestAttrib, CollisionTraverser, CollisionHandlerQueue,
|
||||||
CollisionNode, CollisionRay, GeomNode, BitMask32, Material, LColor, DepthWriteAttrib,
|
CollisionNode, CollisionRay, GeomNode, BitMask32, Material, LColor, DepthWriteAttrib,
|
||||||
TransparencyAttrib, Vec4)
|
TransparencyAttrib, Vec4, CollisionCapsule)
|
||||||
from direct.task.TaskManagerGlobal import taskMgr
|
from direct.task.TaskManagerGlobal import taskMgr
|
||||||
import math
|
import math
|
||||||
|
|
||||||
@ -38,6 +38,9 @@ class SelectionSystem:
|
|||||||
self.gizmoXAxis = None # X轴
|
self.gizmoXAxis = None # X轴
|
||||||
self.gizmoYAxis = None # Y轴
|
self.gizmoYAxis = None # Y轴
|
||||||
self.gizmoZAxis = None # Z轴
|
self.gizmoZAxis = None # Z轴
|
||||||
|
self.gizmoRotXAxis = None
|
||||||
|
self.gizmoRotYAxis = None
|
||||||
|
self.gizmoRotZAxis = None
|
||||||
self.axis_length = 5.0 # 坐标轴长度(增加到5.0)
|
self.axis_length = 5.0 # 坐标轴长度(增加到5.0)
|
||||||
|
|
||||||
# 拖拽相关状态
|
# 拖拽相关状态
|
||||||
@ -312,6 +315,8 @@ class SelectionSystem:
|
|||||||
|
|
||||||
self._setupGizmoRendering()
|
self._setupGizmoRendering()
|
||||||
|
|
||||||
|
self.setupGizmoCollision()
|
||||||
|
|
||||||
# 现在才显示坐标轴
|
# 现在才显示坐标轴
|
||||||
self.gizmo.show()
|
self.gizmo.show()
|
||||||
|
|
||||||
@ -329,41 +334,120 @@ class SelectionSystem:
|
|||||||
if not self.gizmo:
|
if not self.gizmo:
|
||||||
return
|
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
|
||||||
|
|
||||||
|
if is_scale_tool:
|
||||||
|
model_paths = [
|
||||||
|
"core/UniformScaleHandle.fbx",
|
||||||
|
]
|
||||||
|
elif is_rotate_tool:
|
||||||
|
model_paths = [
|
||||||
|
"core/RotationHandleQuarter.fbx",
|
||||||
|
]
|
||||||
|
else:
|
||||||
model_paths = [
|
model_paths = [
|
||||||
"core/TranslateArrowHandle.fbx",
|
"core/TranslateArrowHandle.fbx",
|
||||||
"EG/core/TranslateArrowHandle.fbx",
|
|
||||||
]
|
]
|
||||||
arrow_model = None
|
|
||||||
|
# model_paths = [
|
||||||
|
# "core/TranslateArrowHandle.fbx",
|
||||||
|
# "EG/core/TranslateArrowHandle.fbx",
|
||||||
|
# ]
|
||||||
|
gizmo_model = None
|
||||||
|
gizmoRot_model = None
|
||||||
for path in model_paths:
|
for path in model_paths:
|
||||||
try:
|
try:
|
||||||
arrow_model = self.world.loader.loadModel(path)
|
if is_rotate_tool:
|
||||||
if arrow_model:
|
gizmo_model = self.world.loader.loadModel("core/TranslateArrowHandle.fbx")
|
||||||
|
gizmoRot_model = self.world.loader.loadModel(path)
|
||||||
|
else:
|
||||||
|
gizmo_model = self.world.loader.loadModel(path)
|
||||||
|
if gizmo_model:
|
||||||
print(f"成功加载模型: {path}")
|
print(f"成功加载模型: {path}")
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
x_rHandle = None
|
||||||
|
y_rHandle = None
|
||||||
|
z_rHandle = None
|
||||||
|
|
||||||
|
if is_rotate_tool:
|
||||||
|
self.gizmoRotXAxis = self.gizmo.attachNewNode("gizmo_rot_x_axis")
|
||||||
|
x_rHandle = gizmoRot_model.copyTo(self.gizmoRotXAxis)
|
||||||
|
x_rHandle.setName("x_handle")
|
||||||
|
self.gizmoRotYAxis = self.gizmo.attachNewNode("gizmo_rot_y_axis")
|
||||||
|
y_rHandle = gizmoRot_model.copyTo(self.gizmoRotYAxis)
|
||||||
|
y_rHandle.setName("y_handle")
|
||||||
|
self.gizmoRotZAxis = self.gizmo.attachNewNode("gizmo_rot_z_axis")
|
||||||
|
z_rHandle = gizmoRot_model.copyTo(self.gizmoRotZAxis)
|
||||||
|
z_rHandle.setName("z_handle")
|
||||||
|
|
||||||
self.gizmoXAxis = self.gizmo.attachNewNode("gizmo_x_axis")
|
self.gizmoXAxis = self.gizmo.attachNewNode("gizmo_x_axis")
|
||||||
x_arrow = arrow_model.copyTo(self.gizmoXAxis)
|
x_handle = gizmo_model.copyTo(self.gizmoXAxis)
|
||||||
x_arrow.setName("x_arrow")
|
x_handle.setName("x_handle")
|
||||||
x_arrow.setHpr(0,-90,0)
|
|
||||||
x_arrow.setScale(0.1,0.05,0.05)
|
|
||||||
x_arrow.setPos(0,0,0)
|
|
||||||
|
|
||||||
self.gizmoYAxis = self.gizmo.attachNewNode("gizmo_y_axis")
|
self.gizmoYAxis = self.gizmo.attachNewNode("gizmo_y_axis")
|
||||||
y_arrow = arrow_model.copyTo(self.gizmoYAxis)
|
y_handle = gizmo_model.copyTo(self.gizmoYAxis)
|
||||||
y_arrow.setName("y_arrow")
|
y_handle.setName("y_handle")
|
||||||
y_arrow.setHpr(90,0,0)
|
|
||||||
y_arrow.setScale(0.1,0.05,0.05)
|
|
||||||
y_arrow.setPos(0,0,0)
|
|
||||||
|
|
||||||
# 创建Z轴(蓝色)
|
|
||||||
self.gizmoZAxis = self.gizmo.attachNewNode("gizmo_z_axis")
|
self.gizmoZAxis = self.gizmo.attachNewNode("gizmo_z_axis")
|
||||||
z_arrow = arrow_model.copyTo(self.gizmoZAxis)
|
z_handle = gizmo_model.copyTo(self.gizmoZAxis)
|
||||||
z_arrow.setName("z_arrow")
|
z_handle.setName("z_handle")
|
||||||
# 旋转箭头使其指向Z轴正方向
|
|
||||||
z_arrow.setHpr(0, 0, -90) # 根据需要调整旋转
|
if is_scale_tool:
|
||||||
z_arrow.setScale(0.1,0.05,0.05)
|
x_handle.setHpr(0,-90,0)
|
||||||
z_arrow.setPos(0, 0, 0)
|
x_handle.setScale(0.6,0.03,0.03)
|
||||||
|
x_handle.setPos(2.2,0,0)
|
||||||
|
|
||||||
|
y_handle.setHpr(90,0,0)
|
||||||
|
y_handle.setScale(0.6,0.03,0.03)
|
||||||
|
y_handle.setPos(0,2.2,0)
|
||||||
|
|
||||||
|
z_handle.setHpr(0,0,-90)
|
||||||
|
z_handle.setScale(0.6,0.03,0.03)
|
||||||
|
z_handle.setPos(0,0,2.2)
|
||||||
|
elif is_rotate_tool:
|
||||||
|
x_rHandle.setHpr(0,0,90)
|
||||||
|
x_rHandle.setScale(0.025,0.0125,0.0125)
|
||||||
|
x_rHandle.setPos(0,0,0)
|
||||||
|
|
||||||
|
y_rHandle.setHpr(0,0,0)
|
||||||
|
y_rHandle.setScale(0.025,0.0125,0.0125)
|
||||||
|
y_rHandle.setPos(0,0,0)
|
||||||
|
|
||||||
|
z_rHandle.setHpr(-90,0,0)
|
||||||
|
z_rHandle.setScale(0.025,0.0125,0.0125)
|
||||||
|
z_rHandle.setPos(0,0,0)
|
||||||
|
|
||||||
|
x_handle.setHpr(0, -90, 0)
|
||||||
|
x_handle.setScale(0.1, 0.05, 0.05)
|
||||||
|
x_handle.setPos(0, 0, 0)
|
||||||
|
|
||||||
|
y_handle.setHpr(90, 0, 0)
|
||||||
|
y_handle.setScale(0.1, 0.05, 0.05)
|
||||||
|
y_handle.setPos(0, 0, 0)
|
||||||
|
|
||||||
|
z_handle.setHpr(0, 0, -90)
|
||||||
|
z_handle.setScale(0.1, 0.05, 0.05)
|
||||||
|
z_handle.setPos(0, 0, 0)
|
||||||
|
|
||||||
|
self.setGizmoRotAxisColor("x", self.gizmo_colors["x"])
|
||||||
|
self.setGizmoRotAxisColor("y", self.gizmo_colors["y"])
|
||||||
|
self.setGizmoRotAxisColor("z", self.gizmo_colors["z"])
|
||||||
|
else:
|
||||||
|
x_handle.setHpr(0,-90,0)
|
||||||
|
x_handle.setScale(0.1,0.05,0.05)
|
||||||
|
x_handle.setPos(0,0,0)
|
||||||
|
|
||||||
|
y_handle.setHpr(90,0,0)
|
||||||
|
y_handle.setScale(0.1,0.05,0.05)
|
||||||
|
y_handle.setPos(0,0,0)
|
||||||
|
|
||||||
|
z_handle.setHpr(0,0,-90)
|
||||||
|
z_handle.setScale(0.1,0.05,0.05)
|
||||||
|
z_handle.setPos(0,0,0)
|
||||||
|
|
||||||
# 设置初始颜色
|
# 设置初始颜色
|
||||||
self.setGizmoAxisColor("x", self.gizmo_colors["x"])
|
self.setGizmoAxisColor("x", self.gizmo_colors["x"])
|
||||||
@ -379,6 +463,7 @@ class SelectionSystem:
|
|||||||
def _setupGizmoRendering(self):
|
def _setupGizmoRendering(self):
|
||||||
try:
|
try:
|
||||||
axis_nodes = [self.gizmoXAxis,self.gizmoYAxis,self.gizmoZAxis]
|
axis_nodes = [self.gizmoXAxis,self.gizmoYAxis,self.gizmoZAxis]
|
||||||
|
axis_Rotnodes = [self.gizmoRotXAxis, self.gizmoRotYAxis, self.gizmoRotZAxis]
|
||||||
|
|
||||||
for axis_node in axis_nodes:
|
for axis_node in axis_nodes:
|
||||||
if axis_node:
|
if axis_node:
|
||||||
@ -388,21 +473,45 @@ class SelectionSystem:
|
|||||||
axis_node.setFogOff()
|
axis_node.setFogOff()
|
||||||
#设置渲染层级,确保大多数对象之前渲染
|
#设置渲染层级,确保大多数对象之前渲染
|
||||||
axis_node.setBin("fixed",30)
|
axis_node.setBin("fixed",30)
|
||||||
axis_node.setDepthWrite(False)
|
#axis_node.setDepthWrite(False)
|
||||||
axis_node.setDepthTest(False)
|
#axis_node.setDepthTest(True)
|
||||||
|
|
||||||
|
for axis_rotnode in axis_Rotnodes:
|
||||||
|
if axis_rotnode:
|
||||||
|
axis_rotnode.setLightOff()
|
||||||
|
axis_rotnode.setShaderOff()
|
||||||
|
axis_rotnode.setFogOff()
|
||||||
|
axis_rotnode.setBin("fixed",30)
|
||||||
|
#axis_rotnode.setDepthWrite(False)
|
||||||
|
#axis_rotnode.setDepthTest(True)
|
||||||
|
|
||||||
arrow_nodes = []
|
arrow_nodes = []
|
||||||
if self.gizmoXAxis:
|
if self.gizmoXAxis:
|
||||||
x_arrow = self.gizmoXAxis.find("x_arrow")
|
x_handle = self.gizmoXAxis.find("x_handle")
|
||||||
if x_arrow:
|
if x_handle:
|
||||||
arrow_nodes.append(x_arrow)
|
arrow_nodes.append(x_handle)
|
||||||
if self.gizmoYAxis:
|
if self.gizmoYAxis:
|
||||||
y_arrow = self.gizmoYAxis.find("y_arrow")
|
y_handle = self.gizmoYAxis.find("y_handle")
|
||||||
if y_arrow:
|
if y_handle:
|
||||||
arrow_nodes.append(y_arrow)
|
arrow_nodes.append(y_handle)
|
||||||
if self.gizmoZAxis:
|
if self.gizmoZAxis:
|
||||||
z_arrow = self.gizmoZAxis.find("z_arrow")
|
z_handle = self.gizmoZAxis.find("z_handle")
|
||||||
if z_arrow:
|
if z_handle:
|
||||||
arrow_nodes.append(z_arrow)
|
arrow_nodes.append(z_handle)
|
||||||
|
|
||||||
|
rot_nodes = []
|
||||||
|
if self.gizmoRotXAxis:
|
||||||
|
x_rHandle = self.gizmoRotXAxis.find("x_handle")
|
||||||
|
if x_rHandle:
|
||||||
|
rot_nodes.append(x_rHandle)
|
||||||
|
if self.gizmoRotYAxis:
|
||||||
|
y_rHandle = self.gizmoRotYAxis.find("y_handle")
|
||||||
|
if y_rHandle:
|
||||||
|
rot_nodes.append(y_rHandle)
|
||||||
|
if self.gizmoRotZAxis:
|
||||||
|
z_rHandle = self.gizmoRotZAxis.find("z_handle")
|
||||||
|
if z_rHandle:
|
||||||
|
rot_nodes.append(z_rHandle)
|
||||||
|
|
||||||
for arrow_node in arrow_nodes:
|
for arrow_node in arrow_nodes:
|
||||||
if arrow_node:
|
if arrow_node:
|
||||||
@ -410,17 +519,30 @@ class SelectionSystem:
|
|||||||
arrow_node.setShaderOff()
|
arrow_node.setShaderOff()
|
||||||
arrow_node.setFogOff()
|
arrow_node.setFogOff()
|
||||||
arrow_node.setBin("fixed",31)
|
arrow_node.setBin("fixed",31)
|
||||||
arrow_node.setDepthWrite(False)
|
#arrow_node.setDepthWrite(False)
|
||||||
arrow_node.setDepthTest(False)
|
#arrow_node.setDepthTest(False)
|
||||||
#启用透明度S
|
#启用透明度S
|
||||||
arrow_node.setTransparency(TransparencyAttrib.MAlpha)
|
arrow_node.setTransparency(TransparencyAttrib.MAlpha)
|
||||||
|
|
||||||
|
for rot_node in rot_nodes:
|
||||||
|
if rot_node:
|
||||||
|
rot_node.setLightOff()
|
||||||
|
rot_node.setShaderOff()
|
||||||
|
rot_node.setFogOff()
|
||||||
|
rot_node.setBin("fixed",31)
|
||||||
|
#rot_node.setDepthWrite(False)
|
||||||
|
#rot_node.setDepthTest(False)
|
||||||
|
#启用透明度S
|
||||||
|
rot_node.setTransparency(TransparencyAttrib.MAlpha)
|
||||||
|
|
||||||
if self.gizmo:
|
if self.gizmo:
|
||||||
self.gizmo.setLightOff()
|
self.gizmo.setLightOff()
|
||||||
self.gizmo.setShaderOff()
|
self.gizmo.setShaderOff()
|
||||||
self.gizmo.setFogOff()
|
self.gizmo.setFogOff()
|
||||||
self.gizmo.setBin("fixed",29)
|
self.gizmo.setBin("fixed",29)
|
||||||
self.gizmo.setDepthWrite(False)
|
# self.gizmo.setDepthWrite(False)
|
||||||
self.gizmo.setDepthTest(False)
|
#self.gizmo.setDepthTest(False)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"设置坐标轴渲染属性失败: {str(e)}")
|
print(f"设置坐标轴渲染属性失败: {str(e)}")
|
||||||
|
|
||||||
@ -448,12 +570,49 @@ class SelectionSystem:
|
|||||||
self.clearGizmo()
|
self.clearGizmo()
|
||||||
return task.done
|
return task.done
|
||||||
|
|
||||||
|
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
|
||||||
|
was_scale_tool = getattr(self,'_last_tool_scale_state',False)
|
||||||
|
was_rotate_tool =getattr(self,'_last_tool_rotate_state',False)
|
||||||
|
|
||||||
|
tool_changed = (is_scale_tool!=was_scale_tool) or (is_rotate_tool != was_rotate_tool)
|
||||||
|
|
||||||
|
if tool_changed:
|
||||||
|
self._last_tool_scale_state = is_scale_tool
|
||||||
|
self._last_tool_rotate_state = is_rotate_tool
|
||||||
|
|
||||||
|
if self.gizmoXAxis:
|
||||||
|
self.gizmoXAxis.removeNode()
|
||||||
|
self.gizmoXAxis = None
|
||||||
|
if self.gizmoYAxis:
|
||||||
|
self.gizmoYAxis.removeNode()
|
||||||
|
self.gizmoYAxis = None
|
||||||
|
if self.gizmoZAxis:
|
||||||
|
self.gizmoZAxis.removeNode()
|
||||||
|
self.gizmoZAxis = None
|
||||||
|
if self.gizmoRotXAxis:
|
||||||
|
self.gizmoRotXAxis.removeNode()
|
||||||
|
self.gizmoRotXAxis = None
|
||||||
|
if self.gizmoRotYAxis:
|
||||||
|
self.gizmoRotYAxis.removeNode()
|
||||||
|
self.gizmoRotYAxis = None
|
||||||
|
if self.gizmoRotZAxis:
|
||||||
|
self.gizmoRotZAxis.removeNode()
|
||||||
|
self.gizmoRotZAxis = None
|
||||||
|
|
||||||
|
self.createGizmoGeometry()
|
||||||
|
|
||||||
|
self.setGizmoAxisColor("x",self.gizmo_colors["x"])
|
||||||
|
self.setGizmoAxisColor("y",self.gizmo_colors["y"])
|
||||||
|
self.setGizmoAxisColor("z",self.gizmo_colors["z"])
|
||||||
|
|
||||||
|
self.setupGizmoCollision()
|
||||||
|
|
||||||
light_object = self.gizmoTarget.getPythonTag("rp_light_object")
|
light_object = self.gizmoTarget.getPythonTag("rp_light_object")
|
||||||
if light_object:
|
if light_object:
|
||||||
light_pos = light_object.pos
|
light_pos = light_object.pos
|
||||||
self.gizmo.setPos(light_object.pos)
|
self.gizmo.setPos(light_object.pos)
|
||||||
self.gizmoTarget.setPos(light_pos)
|
self.gizmoTarget.setPos(light_pos)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# 只在必要时更新位置和朝向
|
# 只在必要时更新位置和朝向
|
||||||
self._updateGizmoPositionAndOrientation()
|
self._updateGizmoPositionAndOrientation()
|
||||||
@ -486,13 +645,25 @@ class SelectionSystem:
|
|||||||
self.gizmo.setPos(center)
|
self.gizmo.setPos(center)
|
||||||
self._last_gizmo_bounds_update = current_time
|
self._last_gizmo_bounds_update = current_time
|
||||||
|
|
||||||
# 更新朝向
|
is_scale_tool = self.world.tool_manager.isScaleTool() if self.world.tool_manager else False
|
||||||
|
|
||||||
|
if is_scale_tool:
|
||||||
|
self.gizmo.setHpr(self.gizmoTarget.getHpr())
|
||||||
|
else:
|
||||||
parent_node = self.gizmoTarget.getParent()
|
parent_node = self.gizmoTarget.getParent()
|
||||||
if parent_node and parent_node != self.world.render:
|
if parent_node and parent_node != self.world.render:
|
||||||
parent_hpr = parent_node.getHpr()
|
parent_hpr = parent_node.getHpr()
|
||||||
self.gizmo.setHpr(parent_hpr)
|
self.gizmo.setHpr(parent_hpr)
|
||||||
else:
|
else:
|
||||||
self.gizmo.setHpr(0, 0, 0)
|
self.gizmo.setHpr(0,0,0)
|
||||||
|
|
||||||
|
# 更新朝向
|
||||||
|
# parent_node = self.gizmoTarget.getParent()
|
||||||
|
# if parent_node and parent_node != self.world.render:
|
||||||
|
# parent_hpr = parent_node.getHpr()
|
||||||
|
# self.gizmo.setHpr(parent_hpr)
|
||||||
|
# else:
|
||||||
|
# self.gizmo.setHpr(0, 0, 0)
|
||||||
|
|
||||||
def _updateGizmoScreenSize(self):
|
def _updateGizmoScreenSize(self):
|
||||||
"""动态调整坐标轴大小,保持固定的屏幕大小"""
|
"""动态调整坐标轴大小,保持固定的屏幕大小"""
|
||||||
@ -589,6 +760,97 @@ class SelectionSystem:
|
|||||||
# except:
|
# except:
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
|
|
||||||
|
def setGizmoRotAxisColor(self, axis, color):
|
||||||
|
"""使用材质设置坐标轴颜色 - RenderPipeline兼容版本"""
|
||||||
|
try:
|
||||||
|
from panda3d.core import Material, Vec4,ColorWriteAttrib,DepthWriteAttrib,DepthTestAttrib,TransparencyAttrib
|
||||||
|
|
||||||
|
# 获取对应的轴节点
|
||||||
|
axis_nodes = {
|
||||||
|
"x": self.gizmoRotXAxis,
|
||||||
|
"y": self.gizmoRotYAxis,
|
||||||
|
"z": self.gizmoRotZAxis
|
||||||
|
}
|
||||||
|
|
||||||
|
if axis not in axis_nodes or not axis_nodes[axis]:
|
||||||
|
return
|
||||||
|
|
||||||
|
axis_node = axis_nodes[axis]
|
||||||
|
|
||||||
|
handle_node = None
|
||||||
|
handle_node = axis_node.find("x_handle") if axis == "x" else handle_node
|
||||||
|
handle_node = axis_node.find("y_handle") if axis == "y" else handle_node
|
||||||
|
handle_node = axis_node.find("z_handle") if axis == "z" else handle_node
|
||||||
|
|
||||||
|
#如果找不到特定名称的节点,尝试查找任何子节点
|
||||||
|
if not handle_node:
|
||||||
|
children = axis_node.getChildren()
|
||||||
|
if children.getNumPath()>0:
|
||||||
|
handle_node = children[0]
|
||||||
|
|
||||||
|
if not handle_node:
|
||||||
|
print(f"未找到{axis}轴的处理模型")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 创建或获取材质
|
||||||
|
mat = Material()
|
||||||
|
|
||||||
|
# 设置材质属性 - 使用自发光确保在RenderPipeline下可见
|
||||||
|
mat.setBaseColor(Vec4(color[0], color[1], color[2], color[3]))
|
||||||
|
mat.setDiffuse(Vec4(0, 0, 0, 1))
|
||||||
|
#mat.setEmission(Vec4(color[0], color[1], color[2], 1.0)) # 自发光
|
||||||
|
mat.setEmission(Vec4(1,1,1,1.0)) # 自发光
|
||||||
|
mat.set_roughness(1)
|
||||||
|
|
||||||
|
# 应用材质
|
||||||
|
handle_node.setMaterial(mat, 1)
|
||||||
|
|
||||||
|
|
||||||
|
# 设置透明度
|
||||||
|
if color[3] < 1.0:
|
||||||
|
handle_node.setTransparency(TransparencyAttrib.MAlpha)
|
||||||
|
else:
|
||||||
|
handle_node.setTransparency(TransparencyAttrib.MNone)
|
||||||
|
|
||||||
|
handle_node.setLightOff() # 禁用光照影响
|
||||||
|
handle_node.setShaderOff() # 禁用着色器
|
||||||
|
handle_node.setFogOff() # 禁用雾效果
|
||||||
|
|
||||||
|
handle_node.setBin("fixed",31)
|
||||||
|
#arrow_node.setDepthWrite(False)
|
||||||
|
#arrow_node.setDepthTest(True)
|
||||||
|
|
||||||
|
# 保存材质引用以便后续修改
|
||||||
|
if axis == "x":
|
||||||
|
self.xMat = mat
|
||||||
|
elif axis == "y":
|
||||||
|
self.yMat = mat
|
||||||
|
elif axis == "z":
|
||||||
|
self.zMat = mat
|
||||||
|
|
||||||
|
axis_node.setLightOff()
|
||||||
|
axis_node.setShaderOff()
|
||||||
|
axis_node.setFogOff()
|
||||||
|
axis_node.setBin("fixed", 30)
|
||||||
|
axis_node.setDepthWrite(False)
|
||||||
|
axis_node.setDepthTest(True)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"设置坐标轴颜色失败: {str(e)}")
|
||||||
|
# 回退到简单颜色设置
|
||||||
|
try:
|
||||||
|
axis_nodes = {
|
||||||
|
"x": self.gizmoXAxis,
|
||||||
|
"y": self.gizmoYAxis,
|
||||||
|
"z": self.gizmoZAxis
|
||||||
|
}
|
||||||
|
|
||||||
|
if axis in axis_nodes and axis_nodes[axis]:
|
||||||
|
axis_nodes[axis].setColor(color[0], color[1], color[2], color[3])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
def setGizmoAxisColor(self, axis, color):
|
def setGizmoAxisColor(self, axis, color):
|
||||||
"""使用材质设置坐标轴颜色 - RenderPipeline兼容版本"""
|
"""使用材质设置坐标轴颜色 - RenderPipeline兼容版本"""
|
||||||
try:
|
try:
|
||||||
@ -606,17 +868,19 @@ class SelectionSystem:
|
|||||||
|
|
||||||
axis_node = axis_nodes[axis]
|
axis_node = axis_nodes[axis]
|
||||||
|
|
||||||
# 查找箭头模型节点
|
handle_node = None
|
||||||
arrow_node = None
|
handle_node = axis_node.find("x_handle") if axis == "x" else handle_node
|
||||||
if axis == "x":
|
handle_node = axis_node.find("y_handle") if axis == "y" else handle_node
|
||||||
arrow_node = axis_node.find("x_arrow")
|
handle_node = axis_node.find("z_handle") if axis == "z" else handle_node
|
||||||
elif axis == "y":
|
|
||||||
arrow_node = axis_node.find("y_arrow")
|
|
||||||
elif axis == "z":
|
|
||||||
arrow_node = axis_node.find("z_arrow")
|
|
||||||
|
|
||||||
if not arrow_node:
|
#如果找不到特定名称的节点,尝试查找任何子节点
|
||||||
print(f"未找到{axis}轴的箭头模型")
|
if not handle_node:
|
||||||
|
children = axis_node.getChildren()
|
||||||
|
if children.getNumPath()>0:
|
||||||
|
handle_node = children[0]
|
||||||
|
|
||||||
|
if not handle_node:
|
||||||
|
print(f"未找到{axis}轴的处理模型")
|
||||||
return
|
return
|
||||||
|
|
||||||
# 创建或获取材质
|
# 创建或获取材质
|
||||||
@ -630,20 +894,20 @@ class SelectionSystem:
|
|||||||
mat.set_roughness(1)
|
mat.set_roughness(1)
|
||||||
|
|
||||||
# 应用材质
|
# 应用材质
|
||||||
arrow_node.setMaterial(mat, 1)
|
handle_node.setMaterial(mat, 1)
|
||||||
|
|
||||||
|
|
||||||
# 设置透明度
|
# 设置透明度
|
||||||
if color[3] < 1.0:
|
if color[3] < 1.0:
|
||||||
arrow_node.setTransparency(TransparencyAttrib.MAlpha)
|
handle_node.setTransparency(TransparencyAttrib.MAlpha)
|
||||||
else:
|
else:
|
||||||
arrow_node.setTransparency(TransparencyAttrib.MNone)
|
handle_node.setTransparency(TransparencyAttrib.MNone)
|
||||||
|
|
||||||
arrow_node.setLightOff() # 禁用光照影响
|
handle_node.setLightOff() # 禁用光照影响
|
||||||
arrow_node.setShaderOff() # 禁用着色器
|
handle_node.setShaderOff() # 禁用着色器
|
||||||
arrow_node.setFogOff() # 禁用雾效果
|
handle_node.setFogOff() # 禁用雾效果
|
||||||
|
|
||||||
arrow_node.setBin("fixed",31)
|
handle_node.setBin("fixed",31)
|
||||||
#arrow_node.setDepthWrite(False)
|
#arrow_node.setDepthWrite(False)
|
||||||
#arrow_node.setDepthTest(True)
|
#arrow_node.setDepthTest(True)
|
||||||
|
|
||||||
@ -1019,8 +1283,9 @@ class SelectionSystem:
|
|||||||
if not self.gizmo or self.isDraggingGizmo:
|
if not self.gizmo or self.isDraggingGizmo:
|
||||||
return
|
return
|
||||||
|
|
||||||
# 使用统一的检测方法
|
# 使用碰撞检测方法
|
||||||
hoveredAxis = self.detectGizmoAxisAtMouse(mouseX, mouseY)
|
hoveredAxis = self.detectGizmoAxisWithCollision(mouseX, mouseY)
|
||||||
|
#hoveredAxis = self.detectGizmoAxisAtMouse(mouseX, mouseY)
|
||||||
|
|
||||||
# 简化稳定性检测逻辑
|
# 简化稳定性检测逻辑
|
||||||
if not hasattr(self, '_last_detected_axis'):
|
if not hasattr(self, '_last_detected_axis'):
|
||||||
@ -1037,6 +1302,11 @@ class SelectionSystem:
|
|||||||
# 高亮新的轴
|
# 高亮新的轴
|
||||||
if hoveredAxis:
|
if hoveredAxis:
|
||||||
self.setGizmoAxisColor(hoveredAxis, self.gizmo_highlight_colors[hoveredAxis])
|
self.setGizmoAxisColor(hoveredAxis, self.gizmo_highlight_colors[hoveredAxis])
|
||||||
|
else:
|
||||||
|
# 如果没有悬停在任何轴上,确保所有轴都恢复原始颜色
|
||||||
|
for axis_name in ["x", "y", "z"]:
|
||||||
|
if axis_name != self.dragGizmoAxis: # 不要改变正在拖拽的轴的颜色
|
||||||
|
self.setGizmoAxisColor(axis_name, self.gizmo_colors[axis_name])
|
||||||
|
|
||||||
self.gizmoHighlightAxis = hoveredAxis
|
self.gizmoHighlightAxis = hoveredAxis
|
||||||
|
|
||||||
@ -1074,17 +1344,25 @@ class SelectionSystem:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.isDraggingGizmo = True
|
self.isDraggingGizmo = True
|
||||||
# 使用当前高亮的轴,如果有的话
|
|
||||||
|
# 使用当前高亮的轴,如果有的话;否则使用传入的轴
|
||||||
if self.gizmoHighlightAxis:
|
if self.gizmoHighlightAxis:
|
||||||
self.dragGizmoAxis = self.gizmoHighlightAxis
|
self.dragGizmoAxis = self.gizmoHighlightAxis
|
||||||
else:
|
else:
|
||||||
self.dragGizmoAxis = axis
|
self.dragGizmoAxis = axis
|
||||||
|
|
||||||
self.dragStartMousePos = (mouseX, mouseY)
|
self.dragStartMousePos = (mouseX, mouseY)
|
||||||
|
|
||||||
# 保存开始拖拽时目标节点的位置和坐标轴的位置
|
# 保存开始拖拽时目标节点的位置和坐标轴的位置
|
||||||
self.gizmoTargetStartPos = self.gizmoTarget.getPos()
|
self.gizmoTargetStartPos = self.gizmoTarget.getPos()
|
||||||
self.gizmoStartPos = self.gizmo.getPos(self.world.render) # 坐标轴的世界位置
|
self.gizmoStartPos = self.gizmo.getPos(self.world.render) # 坐标轴的世界位置
|
||||||
|
|
||||||
|
# 添加对缩放的支持:保存初始缩放值
|
||||||
|
if self.world.tool_manager.isScaleTool():
|
||||||
|
self.gizmoTargetStartScale = self.gizmoTarget.getScale()
|
||||||
|
elif self.world.tool_manager.isRotateTool():
|
||||||
|
self.gizmoTargetStartHpr = self.gizmoTarget.getHpr()
|
||||||
|
|
||||||
# 确保正在拖动的轴保持高亮状态
|
# 确保正在拖动的轴保持高亮状态
|
||||||
if self.dragGizmoAxis and self.dragGizmoAxis in self.gizmo_colors:
|
if self.dragGizmoAxis and self.dragGizmoAxis in self.gizmo_colors:
|
||||||
# 先将所有轴恢复为正常颜色
|
# 先将所有轴恢复为正常颜色
|
||||||
@ -1094,13 +1372,15 @@ class SelectionSystem:
|
|||||||
|
|
||||||
# 然后将当前拖动的轴设置为高亮颜色
|
# 然后将当前拖动的轴设置为高亮颜色
|
||||||
self.setGizmoAxisColor(self.dragGizmoAxis, self.gizmo_highlight_colors[self.dragGizmoAxis])
|
self.setGizmoAxisColor(self.dragGizmoAxis, self.gizmo_highlight_colors[self.dragGizmoAxis])
|
||||||
self.gizmoHighlightAxis = self.dragGizmoAxis
|
|
||||||
elif axis and axis in self.gizmo_colors:
|
elif axis and axis in self.gizmo_colors:
|
||||||
for axis_name in self.gizmo_colors.keys():
|
for axis_name in self.gizmo_colors.keys():
|
||||||
|
if axis_name != axis:
|
||||||
self.setGizmoAxisColor(axis_name, self.gizmo_colors[axis_name])
|
self.setGizmoAxisColor(axis_name, self.gizmo_colors[axis_name])
|
||||||
|
|
||||||
self.setGizmoAxisColor(axis, self.gizmo_highlight_colors[axis])
|
self.setGizmoAxisColor(axis, self.gizmo_highlight_colors[axis])
|
||||||
self.gizmoHighlightAxis = axis
|
self.dragGizmoAxis = axis
|
||||||
|
|
||||||
|
self.gizmoHighlightAxis = self.dragGizmoAxis
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"开始拖拽 {self.dragGizmoAxis} 轴 - 目标起始位置: {self.gizmoTargetStartPos}, 坐标轴位置: {self.gizmoStartPos}, 鼠标: ({mouseX}, {mouseY})")
|
f"开始拖拽 {self.dragGizmoAxis} 轴 - 目标起始位置: {self.gizmoTargetStartPos}, 坐标轴位置: {self.gizmoStartPos}, 鼠标: ({mouseX}, {mouseY})")
|
||||||
@ -1130,10 +1410,55 @@ class SelectionSystem:
|
|||||||
print("拖拽更新失败: 没有坐标轴起始位置")
|
print("拖拽更新失败: 没有坐标轴起始位置")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
is_scale_tool = self.world.tool_manager.isScaleTool()
|
||||||
|
is_rotate_tool = self.world.tool_manager.isRotateTool()
|
||||||
|
|
||||||
# 计算鼠标移动距离(屏幕像素)
|
# 计算鼠标移动距离(屏幕像素)
|
||||||
mouseDeltaX = mouseX - self.dragStartMousePos[0]
|
mouseDeltaX = mouseX - self.dragStartMousePos[0]
|
||||||
mouseDeltaY = mouseY - self.dragStartMousePos[1]
|
mouseDeltaY = mouseY - self.dragStartMousePos[1]
|
||||||
|
|
||||||
|
if is_scale_tool:
|
||||||
|
scale_factor = 1.0 + (mouseDeltaX + mouseDeltaY) * 0.01
|
||||||
|
start_scale = getattr(self,'gizmoTargetStartScale',Vec3(1,1,1))
|
||||||
|
|
||||||
|
target_hpr = self.gizmoTarget.getHpr()
|
||||||
|
|
||||||
|
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
|
||||||
|
new_scale = Vec3(start_scale.x,start_scale.y,start_scale.z*z_scale_factor)
|
||||||
|
else:
|
||||||
|
new_scale = Vec3(start_scale.x * scale_factor,
|
||||||
|
start_scale * scale_factor,
|
||||||
|
start_scale.z * scale_factor)
|
||||||
|
#应用新缩放值
|
||||||
|
self.gizmoTarget.setScale(new_scale)
|
||||||
|
#实时更新属性面板
|
||||||
|
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
||||||
|
return
|
||||||
|
elif is_rotate_tool:
|
||||||
|
rotation_speed = 0.5
|
||||||
|
rotation_amount = (mouseDeltaX + mouseDeltaY) * rotation_speed
|
||||||
|
start_hpr = getattr(self,'gizmoTargetStartHpr',self.gizmoTarget.getHpr())
|
||||||
|
|
||||||
|
if self.dragGizmoAxis == "x":
|
||||||
|
new_hpr = Vec3(start_hpr.x+rotation_amount,start_hpr.y,start_hpr.z)
|
||||||
|
elif self.dragGizmoAxis == "y":
|
||||||
|
new_hpr = Vec3(start_hpr.x,start_hpr.y+rotation_amount,start_hpr.z)
|
||||||
|
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,
|
||||||
|
start_hpr.y + rotation_amount,
|
||||||
|
start_hpr.z + rotation_amount)
|
||||||
|
self.gizmoTarget.setHpr(new_hpr)
|
||||||
|
self.world.property_panel.refreshModelValues(self.gizmoTarget)
|
||||||
|
return
|
||||||
|
|
||||||
# 使用坐标轴的实际位置而不是目标节点位置来计算屏幕投影
|
# 使用坐标轴的实际位置而不是目标节点位置来计算屏幕投影
|
||||||
gizmo_world_pos = self.gizmoStartPos
|
gizmo_world_pos = self.gizmoStartPos
|
||||||
|
|
||||||
@ -1184,21 +1509,6 @@ class SelectionSystem:
|
|||||||
axis_start_screen = worldToScreen(gizmo_world_pos)
|
axis_start_screen = worldToScreen(gizmo_world_pos)
|
||||||
axis_end_world = gizmo_world_pos + world_axis_vector
|
axis_end_world = gizmo_world_pos + world_axis_vector
|
||||||
axis_end_screen = worldToScreen(axis_end_world)
|
axis_end_screen = worldToScreen(axis_end_world)
|
||||||
#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 axis_start_screen or not axis_end_screen:
|
if not axis_start_screen or not axis_end_screen:
|
||||||
print("拖拽更新失败: 无法获取轴线屏幕坐标")
|
print("拖拽更新失败: 无法获取轴线屏幕坐标")
|
||||||
@ -1209,7 +1519,6 @@ class SelectionSystem:
|
|||||||
axis_end_screen[1] - axis_start_screen[1]
|
axis_end_screen[1] - axis_start_screen[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# 归一化屏幕轴方向
|
# 归一化屏幕轴方向
|
||||||
import math
|
import math
|
||||||
length = math.sqrt(screen_axis_dir[0]**2 + screen_axis_dir[1]**2)
|
length = math.sqrt(screen_axis_dir[0]**2 + screen_axis_dir[1]**2)
|
||||||
@ -1253,40 +1562,16 @@ class SelectionSystem:
|
|||||||
|
|
||||||
currentPos = self.gizmoTargetStartPos
|
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":
|
if self.dragGizmoAxis == "x":
|
||||||
newPos = Vec3(currentPos.x + movement_distance, currentPos.y, currentPos.z)
|
newPos = Vec3(currentPos.x + movement_distance, currentPos.y, currentPos.z)
|
||||||
print(f"X轴移动:{currentPos.x} -> {newPos.x}")
|
#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)
|
newPos = Vec3(currentPos.x, currentPos.y + movement_distance, currentPos.z)
|
||||||
print(f"Y轴移动:{currentPos.y} -> {newPos.y}")
|
#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)
|
newPos = Vec3(currentPos.x, currentPos.y, currentPos.z + movement_distance)
|
||||||
print(f"Z轴移动:{currentPos.z} -> {newPos.z}")
|
#print(f"Z轴移动:{currentPos.z} -> {newPos.z}")
|
||||||
else:
|
else:
|
||||||
print(f"未知轴: {self.dragGizmoAxis}")
|
print(f"未知轴: {self.dragGizmoAxis}")
|
||||||
return
|
return
|
||||||
@ -1329,10 +1614,10 @@ class SelectionSystem:
|
|||||||
def stopGizmoDrag(self):
|
def stopGizmoDrag(self):
|
||||||
"""停止坐标轴拖拽"""
|
"""停止坐标轴拖拽"""
|
||||||
print(f"停止坐标轴拖拽 - 轴: {self.dragGizmoAxis}")
|
print(f"停止坐标轴拖拽 - 轴: {self.dragGizmoAxis}")
|
||||||
if self.dragGizmoAxis and self.dragGizmoAxis in self.gizmo_colors:
|
|
||||||
self.setGizmoAxisColor(self.dragGizmoAxis, self.gizmo_colors[self.dragGizmoAxis])
|
# 恢复所有轴的颜色
|
||||||
# 不要将 gizmoHighlightAxis 设置为 None,保持当前高亮轴的状态
|
for axis_name in ["x", "y", "z"]:
|
||||||
# self.gizmoHighlightAxis = None
|
self.setGizmoAxisColor(axis_name, self.gizmo_colors[axis_name])
|
||||||
|
|
||||||
self.isDraggingGizmo = False
|
self.isDraggingGizmo = False
|
||||||
self.dragGizmoAxis = None
|
self.dragGizmoAxis = None
|
||||||
@ -1341,6 +1626,13 @@ class SelectionSystem:
|
|||||||
self.gizmoTargetStartPos = None
|
self.gizmoTargetStartPos = None
|
||||||
self.gizmoStartPos = None
|
self.gizmoStartPos = None
|
||||||
|
|
||||||
|
if hasattr(self, 'gizmoTargetStartScale'):
|
||||||
|
delattr(self, 'gizmoTargetStartScale')
|
||||||
|
if hasattr(self, 'gizmoTargetStartHpr'):
|
||||||
|
delattr(self, 'gizmoTargetStartHpr')
|
||||||
|
|
||||||
|
# 重置高亮轴
|
||||||
|
self.gizmoHighlightAxis = None
|
||||||
# ==================== 选择管理 ====================
|
# ==================== 选择管理 ====================
|
||||||
|
|
||||||
def updateSelection(self, nodePath):
|
def updateSelection(self, nodePath):
|
||||||
@ -1393,3 +1685,164 @@ class SelectionSystem:
|
|||||||
|
|
||||||
if self.selectionBoxTarget and self.selectionBoxTarget.isEmpty():
|
if self.selectionBoxTarget and self.selectionBoxTarget.isEmpty():
|
||||||
self.clearSelectionBox()
|
self.clearSelectionBox()
|
||||||
|
|
||||||
|
def setupGizmoCollision(self):
|
||||||
|
if not self.gizmo or not self.gizmoXAxis or not self.gizmoYAxis or not self.gizmoZAxis:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 清除现有的碰撞节点
|
||||||
|
for axis_name in ["x", "y", "z"]:
|
||||||
|
axis_node = getattr(self, f"gizmo{axis_name.upper()}Axis")
|
||||||
|
if axis_node:
|
||||||
|
# 查找并移除所有现有的碰撞节点
|
||||||
|
collision_nodes = axis_node.findAllMatches("**/gizmo_collision_*")
|
||||||
|
for collision_node in collision_nodes:
|
||||||
|
collision_node.removeNode()
|
||||||
|
|
||||||
|
# 为每个轴创建碰撞体
|
||||||
|
self.createAxisCollision("x", self.gizmoXAxis)
|
||||||
|
self.createAxisCollision("y", self.gizmoYAxis)
|
||||||
|
self.createAxisCollision("z", self.gizmoZAxis)
|
||||||
|
|
||||||
|
def createAxisCollision(self, axis_name, axis_node):
|
||||||
|
# 为单个轴创建碰撞体
|
||||||
|
try:
|
||||||
|
handle_node = axis_node.find(f"{axis_name}_handle")
|
||||||
|
if not handle_node or handle_node.isEmpty():
|
||||||
|
children = axis_node.getChildren()
|
||||||
|
if children.getNumPaths() > 0:
|
||||||
|
handle_node = children[0]
|
||||||
|
else:
|
||||||
|
print(f"警告: 未找到 {axis_name} 轴的 handle 节点")
|
||||||
|
return
|
||||||
|
|
||||||
|
collision_node = CollisionNode(f"gizmo_collision_{axis_name}")
|
||||||
|
collision_node.setIntoCollideMask(BitMask32.bit(1)) # 设置为into对象
|
||||||
|
collision_node.setFromCollideMask(BitMask32.allOff()) # 不作为from对象
|
||||||
|
|
||||||
|
# 调整碰撞尺寸以匹配实际的轴长度和坐标轴缩放
|
||||||
|
scale_factor = self.gizmo.getScale().x if self.gizmo else 1.0
|
||||||
|
axis_length = 2.0 * scale_factor
|
||||||
|
radius = 0.3 * scale_factor
|
||||||
|
|
||||||
|
# 根据轴的类型创建合适的碰撞体
|
||||||
|
if axis_name == "x":
|
||||||
|
capsule = CollisionCapsule(
|
||||||
|
Point3(0, 0, 0),
|
||||||
|
Point3(axis_length, 0, 0),
|
||||||
|
radius
|
||||||
|
)
|
||||||
|
collision_node.addSolid(capsule)
|
||||||
|
elif axis_name == "y":
|
||||||
|
capsule = CollisionCapsule(
|
||||||
|
Point3(0, 0, 0),
|
||||||
|
Point3(0, axis_length, 0),
|
||||||
|
radius
|
||||||
|
)
|
||||||
|
collision_node.addSolid(capsule)
|
||||||
|
elif axis_name == "z":
|
||||||
|
capsule = CollisionCapsule(
|
||||||
|
Point3(0, 0, 0),
|
||||||
|
Point3(0, 0, axis_length),
|
||||||
|
radius
|
||||||
|
)
|
||||||
|
collision_node.addSolid(capsule)
|
||||||
|
|
||||||
|
# 将碰撞节点附加到handle节点,使其与可视化几何体保持一致
|
||||||
|
collision_np = handle_node.attachNewNode(collision_node)
|
||||||
|
|
||||||
|
# 设置标签以便识别
|
||||||
|
collision_np.setTag("gizmo_axis", axis_name)
|
||||||
|
collision_np.setTag("pickable", "1")
|
||||||
|
|
||||||
|
collision_np.hide() # 隐藏碰撞体,只用于检测
|
||||||
|
|
||||||
|
print(f"✓ 成功创建 {axis_name} 轴碰撞体")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"创建{axis_name}轴碰撞体失败: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
def detectGizmoAxisWithCollision(self, mouseX, mouseY):
|
||||||
|
# 使用碰撞体检测鼠标是否悬停在坐标轴上
|
||||||
|
if not self.gizmo:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
ray = CollisionRay()
|
||||||
|
|
||||||
|
win_width, win_height = self.world.getWindowSize()
|
||||||
|
|
||||||
|
mouse_x_ndc = (mouseX / win_width) * 2.0 - 1.0
|
||||||
|
mouse_y_ndc = 1.0 - (mouseY / win_height) * 2.0
|
||||||
|
|
||||||
|
ray.setFromLens(self.world.cam.node(), mouse_x_ndc, mouse_y_ndc)
|
||||||
|
|
||||||
|
traverser = CollisionTraverser("gizmo_traverser")
|
||||||
|
handler = CollisionHandlerQueue()
|
||||||
|
|
||||||
|
# 创建射线节点
|
||||||
|
ray_node = CollisionNode('mouseRay')
|
||||||
|
ray_node.addSolid(ray)
|
||||||
|
ray_node.setFromCollideMask(BitMask32.bit(1)) # 射线作为from对象
|
||||||
|
ray_node.setIntoCollideMask(BitMask32.allOff()) # 射线不作为into对象
|
||||||
|
ray_np = self.world.render.attachNewNode(ray_node)
|
||||||
|
|
||||||
|
# 为所有轴的碰撞体设置正确的掩码并添加到遍历器
|
||||||
|
collision_found = False
|
||||||
|
for axis_name in ["x", "y", "z"]:
|
||||||
|
axis_node = getattr(self, f"gizmo{axis_name.upper()}Axis")
|
||||||
|
if axis_node:
|
||||||
|
collision_node_path = axis_node.find("**/gizmo_collision_*")
|
||||||
|
if not collision_node_path.isEmpty():
|
||||||
|
collision_node = collision_node_path.node()
|
||||||
|
collision_node.setFromCollideMask(BitMask32.allOff()) # 碰撞体不作为from对象
|
||||||
|
collision_node.setIntoCollideMask(BitMask32.bit(1)) # 碰撞体作为into对象
|
||||||
|
collision_found = True
|
||||||
|
|
||||||
|
if not collision_found:
|
||||||
|
ray_np.removeNode()
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 执行碰撞检测 - 这里是关键修复点
|
||||||
|
traverser.addCollider(ray_np, handler)
|
||||||
|
traverser.traverse(self.world.render)
|
||||||
|
|
||||||
|
ray_np.removeNode()
|
||||||
|
|
||||||
|
# 检查是否有碰撞
|
||||||
|
if handler.getNumEntries() > 0:
|
||||||
|
handler.sortEntries()
|
||||||
|
closest_entry = handler.getEntry(0)
|
||||||
|
|
||||||
|
# 获取碰撞的对象
|
||||||
|
collided_object = closest_entry.getIntoNodePath()
|
||||||
|
axis_tag = collided_object.getTag("gizmo_axis")
|
||||||
|
|
||||||
|
if axis_tag in ["x", "y", "z"]:
|
||||||
|
return axis_tag
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"使用碰撞体检测坐标轴失败: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def debugGizmoCollision(self):
|
||||||
|
print("===碰撞体调试信息===")
|
||||||
|
for axis_name in ["x","y","z"]:
|
||||||
|
axis_node = getattr(self,f"gizmo{axis_name.upper()}Axis")
|
||||||
|
if axis_node:
|
||||||
|
handle_node = axis_node.find(f"{axis_name}_handle")
|
||||||
|
collision_node = axis_node.find("**/gizmo_collision_*")
|
||||||
|
print(f"{axis_name.upper()}轴:")
|
||||||
|
print(f" - 轴节点: {axis_node}")
|
||||||
|
print(f" - Handle节点: {handle_node}")
|
||||||
|
print(f" - 碰撞节点: {collision_node}")
|
||||||
|
if not collision_node.isEmpty():
|
||||||
|
print(f" - 碰撞体标签: {collision_node.getTag('gizmo_axis')}")
|
||||||
|
else:
|
||||||
|
print(f"{axis_name.upper()}轴节点不存在")
|
||||||
@ -150,49 +150,3 @@ class ToolManager:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ 启动插件配置器失败: {e}")
|
print(f"❌ 启动插件配置器失败: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def cleanup_processes(self):
|
|
||||||
"""清理所有启动的进程"""
|
|
||||||
try:
|
|
||||||
# 清理插件配置器进程
|
|
||||||
if hasattr(self, '_plugin_configurator_process') and self._plugin_configurator_process:
|
|
||||||
if self._plugin_configurator_process.poll() is None:
|
|
||||||
print("🔄 正在关闭插件配置器...")
|
|
||||||
self._plugin_configurator_process.terminate()
|
|
||||||
try:
|
|
||||||
# 等待进程结束,最多等待5秒
|
|
||||||
self._plugin_configurator_process.wait(timeout=5)
|
|
||||||
print("✅ 插件配置器已正常关闭")
|
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
print("⚠️ 插件配置器未响应,强制关闭...")
|
|
||||||
self._plugin_configurator_process.kill()
|
|
||||||
self._plugin_configurator_process.wait()
|
|
||||||
print("✅ 插件配置器已强制关闭")
|
|
||||||
self._plugin_configurator_process = None
|
|
||||||
|
|
||||||
# 清理材质编辑器进程(如果存在)
|
|
||||||
if hasattr(self, '_material_editor_process') and self._material_editor_process:
|
|
||||||
if self._material_editor_process.poll() is None:
|
|
||||||
print("🔄 正在关闭材质编辑器...")
|
|
||||||
self._material_editor_process.terminate()
|
|
||||||
try:
|
|
||||||
self._material_editor_process.wait(timeout=5)
|
|
||||||
print("✅ 材质编辑器已正常关闭")
|
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
print("⚠️ 材质编辑器未响应,强制关闭...")
|
|
||||||
self._material_editor_process.kill()
|
|
||||||
self._material_editor_process.wait()
|
|
||||||
print("✅ 材质编辑器已强制关闭")
|
|
||||||
self._material_editor_process = None
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"⚠️ 清理进程时出错: {e}")
|
|
||||||
|
|
||||||
def get_plugin_configurator_status(self):
|
|
||||||
"""获取插件配置器的运行状态"""
|
|
||||||
if hasattr(self, '_plugin_configurator_process') and self._plugin_configurator_process:
|
|
||||||
if self._plugin_configurator_process.poll() is None:
|
|
||||||
return "运行中"
|
|
||||||
else:
|
|
||||||
return "已停止"
|
|
||||||
return "未启动"
|
|
||||||
|
|||||||
@ -395,19 +395,27 @@ class PropertyPanelManager:
|
|||||||
self.scale_y = QDoubleSpinBox()
|
self.scale_y = QDoubleSpinBox()
|
||||||
self.scale_z = QDoubleSpinBox()
|
self.scale_z = QDoubleSpinBox()
|
||||||
|
|
||||||
# 设置缩放控件属性
|
current_scale = model.getScale()
|
||||||
for scale_widget in [self.scale_x, self.scale_y, self.scale_z]:
|
|
||||||
scale_widget.setRange(0.01, 100)
|
|
||||||
scale_widget.setSingleStep(0.1)
|
|
||||||
|
|
||||||
self.scale_x.setValue(model.getScale().getX())
|
# 设置缩放控件属性
|
||||||
self.scale_y.setValue(model.getScale().getY())
|
for i, (scale_widget, scale_value) in enumerate(zip([self.scale_x, self.scale_y, self.scale_z],
|
||||||
self.scale_z.setValue(model.getScale().getZ())
|
[current_scale.getX(), current_scale.getY(),
|
||||||
|
current_scale.getZ()])):
|
||||||
|
scale_widget.setRange(-1000, 1000)
|
||||||
|
scale_widget.setSingleStep(0.1)
|
||||||
|
# 如果缩放值为0,设置为一个很小的非零值
|
||||||
|
if scale_value == 0:
|
||||||
|
scale_value = 0.01 if scale_value >= 0 else -0.01
|
||||||
|
scale_widget.setValue(scale_value)
|
||||||
|
|
||||||
|
self.scale_x.valueChanged.connect(lambda value: self._onScaleValueChanged(self.scale_x, value))
|
||||||
|
self.scale_y.valueChanged.connect(lambda value: self._onScaleValueChanged(self.scale_y, value))
|
||||||
|
self.scale_z.valueChanged.connect(lambda value: self._onScaleValueChanged(self.scale_z, value))
|
||||||
|
|
||||||
# 连接缩放变化事件
|
# 连接缩放变化事件
|
||||||
self.scale_x.valueChanged.connect(lambda v: model.setScale(v, model.getScale().getY(), model.getScale().getZ()))
|
self.scale_x.valueChanged.connect(lambda value: self._updateXScale(model, value))
|
||||||
self.scale_y.valueChanged.connect(lambda v: model.setScale(model.getScale().getX(), v, model.getScale().getZ()))
|
self.scale_y.valueChanged.connect(lambda value: self._updateYScale(model, value))
|
||||||
self.scale_z.valueChanged.connect(lambda v: model.setScale(model.getScale().getX(), model.getScale().getY(), v))
|
self.scale_z.valueChanged.connect(lambda value: self._updateZScale(model, value))
|
||||||
|
|
||||||
# 创建并设置 X, Y, Z 标签居中
|
# 创建并设置 X, Y, Z 标签居中
|
||||||
x_label3 = QLabel("X")
|
x_label3 = QLabel("X")
|
||||||
@ -434,6 +442,72 @@ class PropertyPanelManager:
|
|||||||
# 材质属性组
|
# 材质属性组
|
||||||
self._updateModelMaterialPanel(model)
|
self._updateModelMaterialPanel(model)
|
||||||
|
|
||||||
|
def _onScaleValueChanged(self, scale_widget, value):
|
||||||
|
"""确保缩放值不为0"""
|
||||||
|
if value == 0:
|
||||||
|
# 设置为一个很小的非零值,保持原有符号
|
||||||
|
if hasattr(scale_widget, 'value') and scale_widget.value() > 0:
|
||||||
|
scale_widget.setValue(0.01)
|
||||||
|
else:
|
||||||
|
scale_widget.setValue(-0.01)
|
||||||
|
|
||||||
|
def _updateXScale(self, model, value):
|
||||||
|
"""更新X轴缩放值"""
|
||||||
|
# 确保值不为0
|
||||||
|
if value == 0:
|
||||||
|
sender = None
|
||||||
|
# 通过遍历找到发出信号的控件
|
||||||
|
for widget in [self.scale_x, self.scale_y, self.scale_z]:
|
||||||
|
if widget.value() == value:
|
||||||
|
sender = widget
|
||||||
|
break
|
||||||
|
if sender:
|
||||||
|
self._onScaleValueChanged(sender, value)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 更新模型的X轴缩放
|
||||||
|
current_scale = model.getScale()
|
||||||
|
model.setScale(value, current_scale.getY(), current_scale.getZ())
|
||||||
|
self.refreshModelValues(model)
|
||||||
|
|
||||||
|
def _updateYScale(self, model, value):
|
||||||
|
"""更新Y轴缩放值"""
|
||||||
|
# 确保值不为0
|
||||||
|
if value == 0:
|
||||||
|
sender = None
|
||||||
|
# 通过遍历找到发出信号的控件
|
||||||
|
for widget in [self.scale_x, self.scale_y, self.scale_z]:
|
||||||
|
if widget.value() == value:
|
||||||
|
sender = widget
|
||||||
|
break
|
||||||
|
if sender:
|
||||||
|
self._onScaleValueChanged(sender, value)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 更新模型的Y轴缩放
|
||||||
|
current_scale = model.getScale()
|
||||||
|
model.setScale(current_scale.getX(), value, current_scale.getZ())
|
||||||
|
self.refreshModelValues(model)
|
||||||
|
|
||||||
|
def _updateZScale(self, model, value):
|
||||||
|
"""更新Z轴缩放值"""
|
||||||
|
# 确保值不为0
|
||||||
|
if value == 0:
|
||||||
|
sender = None
|
||||||
|
# 通过遍历找到发出信号的控件
|
||||||
|
for widget in [self.scale_x, self.scale_y, self.scale_z]:
|
||||||
|
if widget.value() == value:
|
||||||
|
sender = widget
|
||||||
|
break
|
||||||
|
if sender:
|
||||||
|
self._onScaleValueChanged(sender, value)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 更新模型的Z轴缩放
|
||||||
|
current_scale = model.getScale()
|
||||||
|
model.setScale(current_scale.getX(), current_scale.getY(), value)
|
||||||
|
self.refreshModelValues(model)
|
||||||
|
|
||||||
def refreshModelValues(self,nodePath):
|
def refreshModelValues(self,nodePath):
|
||||||
if not nodePath or self._propertyLayout is None:
|
if not nodePath or self._propertyLayout is None:
|
||||||
return
|
return
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user