diff --git a/RenderPipelineFile/config/daytime.yaml b/RenderPipelineFile/config/daytime.yaml index af9861ed..98f9815c 100644 --- a/RenderPipelineFile/config/daytime.yaml +++ b/RenderPipelineFile/config/daytime.yaml @@ -17,7 +17,7 @@ control_points: scattering: sun_intensity: [[[0.0000000000,0.0000000000],[0.0041666667,0.0000000000],[0.0083333333,0.0000000000],[0.0125000000,0.0000000000],[0.0166666667,0.0000000000],[0.0208333333,0.0000000000],[0.0250000000,0.0000000000],[0.0291666667,0.0000000000],[0.0333333333,0.0000000000],[0.0375000000,0.0000000000],[0.0416666667,0.0000000000],[0.0458333333,0.0000000000],[0.0500000000,0.0000000000],[0.0541666667,0.0000000000],[0.0583333333,0.0000000000],[0.0625000000,0.0000000000],[0.0666666667,0.0000000000],[0.0708333333,0.0000000000],[0.0750000000,0.0000000000],[0.0791666667,0.0000000000],[0.0833333333,0.0000000000],[0.0875000000,0.0000000000],[0.0916666667,0.0000000000],[0.0958333333,0.0000000000],[0.1000000000,0.0000000000],[0.1041666667,0.0000000000],[0.1083333333,0.0000000000],[0.1125000000,0.0000000000],[0.1166666667,0.0000000000],[0.1208333333,0.0000000000],[0.1250000000,0.0000000000],[0.1291666667,0.0000000000],[0.1333333333,0.0000000000],[0.1375000000,0.0000000000],[0.1416666667,0.0000000000],[0.1458333333,0.0000000000],[0.1500000000,0.0000000000],[0.1541666667,0.0000000000],[0.1583333333,0.0000028805],[0.1625000000,0.0003577724],[0.1666666667,0.0013331400],[0.1708333333,0.0029671803],[0.1750000000,0.0052963381],[0.1791666667,0.0083550556],[0.1833333333,0.0121755589],[0.1875000000,0.0167876159],[0.1916666667,0.0222183530],[0.1958333333,0.0284919947],[0.2000000000,0.0356297193],[0.2041666667,0.0436494349],[0.2083333333,0.0525656099],[0.2125000000,0.0623891610],[0.2166666667,0.0731272461],[0.2208333333,0.0847831708],[0.2250000000,0.0973563167],[0.2291666667,0.1108419698],[0.2333333333,0.1252313631],[0.2375000000,0.1405115250],[0.2416666667,0.1566653434],[0.2458333333,0.1736715009],[0.2500000000,0.1915046014],[0.2541666667,0.2101350464],[0.2583333333,0.2295292930],[0.2625000000,0.2496498145],[0.2666666667,0.2704552670],[0.2708333333,0.2919006662],[0.2750000000,0.3139375192],[0.2791666667,0.3365139497],[0.2833333333,0.3595750662],[0.2875000000,0.3830630359],[0.2916666667,0.4069173972],[0.2958333333,0.4310753462],[0.3000000000,0.4554720417],[0.3041666667,0.4800408236],[0.3083333333,0.5047136020],[0.3125000000,0.5294212108],[0.3166666667,0.5540936424],[0.3208333333,0.5786605298],[0.3250000000,0.6030514553],[0.3291666667,0.6271963182],[0.3333333333,0.6510256858],[0.3375000000,0.6744711982],[0.3416666667,0.6974659988],[0.3458333333,0.7199450163],[0.3500000000,0.7418453485],[0.3541666667,0.7631067095],[0.3583333333,0.7836717291],[0.3625000000,0.8034862953],[0.3666666667,0.8224999302],[0.3708333333,0.8406661079],[0.3750000000,0.8579425235],[0.3791666667,0.8742914270],[0.3833333333,0.8896799131],[0.3875000000,0.9040801386],[0.3916666667,0.9174695289],[0.3958333333,0.9298310650],[0.4000000000,0.9411533765],[0.4041666667,0.9514309312],[0.4083333333,0.9606641691],[0.4125000000,0.9688595571],[0.4166666667,0.9760296330],[0.4208333333,0.9821930708],[0.4250000000,0.9873746114],[0.4291666667,0.9916050060],[0.4333333333,0.9949209310],[0.4375000000,0.9973647924],[0.4416666667,0.9989845508],[0.4458333333,0.9998334497],[0.4500000000,0.9999696949],[0.4541666667,0.9994560801],[0.4583333333,0.9983595429],[0.4625000000,0.9967506613],[0.4666666667,0.9947030614],[0.4708333333,0.9922927758],[0.4750000000,0.9895975125],[0.4791666667,0.9866958610],[0.4833333333,0.9836664262],[0.4875000000,0.9805868867],[0.4916666667,0.9775330316],[0.4958333333,0.9745777179],[0.5000000000,0.9717898417],[0.5041666667,0.9692332877],[0.5083333333,0.9669658924],[0.5125000000,0.9650384806],[0.5089595376,0.9690650222],[0.5208333333,0.9623666659],[0.5250000000,0.9616814371],[0.5291666667,0.9614534423],[0.5333333333,0.9616877089],[0.5375000000,0.9623790807],[0.5416666667,0.9635123329],[0.5458333333,0.9650624244],[0.5500000000,0.9669949804],[0.5541666667,0.9692669864],[0.5583333333,0.9718275065],[0.5625000000,0.9746185969],[0.5666666667,0.9775762863],[0.5708333333,0.9806315864],[0.5750000000,0.9837115661],[0.5791666667,0.9867403433],[0.5833333333,0.9896401655],[0.5875000000,0.9923323562],[0.5916666667,0.9947382579],[0.5958333333,0.9967800977],[0.6000000000,0.9983817820],[0.6041666667,0.9994696263],[0.6083333333,0.9999730028],[0.6125000000,0.9998249266],[0.6166666667,0.9989625601],[0.6208333333,0.9973276624],[0.6250000000,0.9948669567],[0.6291666667,0.9915324664],[0.6333333333,0.9872817545],[0.6375000000,0.9820781426],[0.6416666667,0.9758908775],[0.6458333333,0.9686952146],[0.6500000000,0.9604725211],[0.6541666667,0.9512102537],[0.6583333333,0.9409019858],[0.6625000000,0.9295473441],[0.6666666667,0.9171518878],[0.6708333333,0.9037270619],[0.6750000000,0.8892899902],[0.6791666667,0.8738633008],[0.6833333333,0.8574749656],[0.6875000000,0.8401579787],[0.6916666667,0.8219502453],[0.6958333333,0.8028941798],[0.7000000000,0.7830364456],[0.7041666667,0.7624277344],[0.7083333333,0.7411222520],[0.7125000000,0.7191776044],[0.7166666667,0.6966542563],[0.7208333333,0.6736152714],[0.7250000000,0.6501259629],[0.7291666667,0.6262533880],[0.7333333333,0.6020661121],[0.7375000000,0.5776338043],[0.7416666667,0.5530267796],[0.7458333333,0.5283156992],[0.7500000000,0.5035711751],[0.7541666667,0.4788634341],[0.7583333333,0.4542618347],[0.7625000000,0.4298347613],[0.7666666667,0.4056490351],[0.7708333333,0.3817697830],[0.7750000000,0.3582600107],[0.7791666667,0.3351803495],[0.7833333333,0.3125888445],[0.7875000000,0.2905406366],[0.7916666667,0.2690876955],[0.7958333333,0.2482787388],[0.8000000000,0.2281588906],[0.8041666667,0.2087696425],[0.8083333333,0.1901486315],[0.8125000000,0.1723295359],[0.8166666667,0.1553419918],[0.8208333333,0.1392115328],[0.8250000000,0.1239595144],[0.8291666667,0.1096030703],[0.8333333333,0.0961551918],[0.8375000000,0.0836246599],[0.8416666667,0.0720161369],[0.8458333333,0.0613302273],[0.8500000000,0.0515635598],[0.8541666667,0.0427088803],[0.8583333333,0.0347551990],[0.8625000000,0.0276878920],[0.8666666667,0.0214889271],[0.8708333333,0.0161369711],[0.8750000000,0.0116076130],[0.8791666667,0.0078735477],[0.8833333333,0.0049047927],[0.8875000000,0.0026688977],[0.8916666667,0.0011311782],[0.8958333333,0.0002549473],[0.9000000000,0.0000000000],[0.9041666667,0.0000000000],[0.9083333333,0.0000000000],[0.9125000000,0.0000000000],[0.9166666667,0.0000000000],[0.9208333333,0.0000000000],[0.9250000000,0.0000000000],[0.9291666667,0.0000000000],[0.9333333333,0.0000000000],[0.9375000000,0.0000000000],[0.9416666667,0.0000000000],[0.9458333333,0.0000000000],[0.9500000000,0.0000000000],[0.9541666667,0.0000000000],[0.9583333333,0.0000000000],[0.9625000000,0.0000000000],[0.9666666667,0.0000000000],[0.9708333333,0.0000000000],[0.9750000000,0.0000000000],[0.9791666667,0.0000000000],[0.9833333333,0.0000000000],[0.9875000000,0.0000000000],[0.9916666667,0.0000000000],[0.9958333333,0.0000000000]]] sun_color: [[[0.5010435645,0.5818710306],[0.0433100000,0.8999700000],[0.8635787716,0.9130000000],[0.1785000000,0.8973600000],[0.8099800000,0.8651100000],[0.2360800000,0.7712700000],[0.6583432177,0.8485126184],[0.1266806142,0.9648102053],[0.9558541267,0.9090909091],[0.5568400771,0.7353760446]],[[0.5001318426,0.5160300000],[0.0572700000,0.6541600000],[0.2395000000,0.5976800000],[0.8104600000,0.6009000000],[0.6967400000,0.5483900000]],[[0.0862400000,0.4257800000],[0.4955600000,0.4033000000],[0.8234200000,0.4340200000]]] - sun_azimuth: [[[0.5000000000,0.5000000000]]] + sun_azimuth: [[[0.5000000000,0.9555555556]]] sun_altitude: [[[0.5000000000,1.0000000000]]] extinction: [[[0.4913294798,0.6378830084]]] volumetrics: diff --git a/core/RotationHandleFull.fbx b/core/RotationHandleFull.fbx new file mode 100755 index 00000000..8c42b1b9 Binary files /dev/null and b/core/RotationHandleFull.fbx differ diff --git a/core/RotationHandleQuarter.fbx b/core/RotationHandleQuarter.fbx new file mode 100755 index 00000000..d12b04bc Binary files /dev/null and b/core/RotationHandleQuarter.fbx differ diff --git a/core/UniformScaleHandle.fbx b/core/UniformScaleHandle.fbx new file mode 100755 index 00000000..dc0bfb89 Binary files /dev/null and b/core/UniformScaleHandle.fbx differ diff --git a/core/selection.py b/core/selection.py index 22ff8ef5..8cd4e826 100644 --- a/core/selection.py +++ b/core/selection.py @@ -11,7 +11,7 @@ from PIL.ImageChops import lighter from panda3d.core import (Vec3, Point3, Point2, LineSegs, ColorAttrib, RenderState, DepthTestAttrib, CollisionTraverser, CollisionHandlerQueue, CollisionNode, CollisionRay, GeomNode, BitMask32, Material, LColor, DepthWriteAttrib, - TransparencyAttrib, Vec4) + TransparencyAttrib, Vec4, CollisionCapsule) from direct.task.TaskManagerGlobal import taskMgr import math @@ -38,6 +38,9 @@ class SelectionSystem: self.gizmoXAxis = None # X轴 self.gizmoYAxis = None # Y轴 self.gizmoZAxis = None # Z轴 + self.gizmoRotXAxis = None + self.gizmoRotYAxis = None + self.gizmoRotZAxis = None self.axis_length = 5.0 # 坐标轴长度(增加到5.0) # 拖拽相关状态 @@ -312,6 +315,8 @@ class SelectionSystem: self._setupGizmoRendering() + self.setupGizmoCollision() + # 现在才显示坐标轴 self.gizmo.show() @@ -329,41 +334,120 @@ class SelectionSystem: if not self.gizmo: return - model_paths = [ - "core/TranslateArrowHandle.fbx", - "EG/core/TranslateArrowHandle.fbx", - ] - arrow_model = None + 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 = [ + "core/TranslateArrowHandle.fbx", + ] + + # model_paths = [ + # "core/TranslateArrowHandle.fbx", + # "EG/core/TranslateArrowHandle.fbx", + # ] + gizmo_model = None + gizmoRot_model = None for path in model_paths: try: - arrow_model = self.world.loader.loadModel(path) - if arrow_model: - print(f"成功加载模型: {path}") - break + if is_rotate_tool: + 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}") + break except: 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") - x_arrow = arrow_model.copyTo(self.gizmoXAxis) - x_arrow.setName("x_arrow") - x_arrow.setHpr(0,-90,0) - x_arrow.setScale(0.1,0.05,0.05) - x_arrow.setPos(0,0,0) + x_handle = gizmo_model.copyTo(self.gizmoXAxis) + x_handle.setName("x_handle") self.gizmoYAxis = self.gizmo.attachNewNode("gizmo_y_axis") - y_arrow = arrow_model.copyTo(self.gizmoYAxis) - y_arrow.setName("y_arrow") - y_arrow.setHpr(90,0,0) - y_arrow.setScale(0.1,0.05,0.05) - y_arrow.setPos(0,0,0) + y_handle = gizmo_model.copyTo(self.gizmoYAxis) + y_handle.setName("y_handle") - # 创建Z轴(蓝色) self.gizmoZAxis = self.gizmo.attachNewNode("gizmo_z_axis") - z_arrow = arrow_model.copyTo(self.gizmoZAxis) - z_arrow.setName("z_arrow") - # 旋转箭头使其指向Z轴正方向 - z_arrow.setHpr(0, 0, -90) # 根据需要调整旋转 - z_arrow.setScale(0.1,0.05,0.05) - z_arrow.setPos(0, 0, 0) + z_handle = gizmo_model.copyTo(self.gizmoZAxis) + z_handle.setName("z_handle") + + if is_scale_tool: + x_handle.setHpr(0,-90,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"]) @@ -379,6 +463,7 @@ class SelectionSystem: def _setupGizmoRendering(self): try: axis_nodes = [self.gizmoXAxis,self.gizmoYAxis,self.gizmoZAxis] + axis_Rotnodes = [self.gizmoRotXAxis, self.gizmoRotYAxis, self.gizmoRotZAxis] for axis_node in axis_nodes: if axis_node: @@ -388,21 +473,45 @@ class SelectionSystem: axis_node.setFogOff() #设置渲染层级,确保大多数对象之前渲染 axis_node.setBin("fixed",30) - axis_node.setDepthWrite(False) - axis_node.setDepthTest(False) + #axis_node.setDepthWrite(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 = [] if self.gizmoXAxis: - x_arrow = self.gizmoXAxis.find("x_arrow") - if x_arrow: - arrow_nodes.append(x_arrow) + x_handle = self.gizmoXAxis.find("x_handle") + if x_handle: + arrow_nodes.append(x_handle) if self.gizmoYAxis: - y_arrow = self.gizmoYAxis.find("y_arrow") - if y_arrow: - arrow_nodes.append(y_arrow) + y_handle = self.gizmoYAxis.find("y_handle") + if y_handle: + arrow_nodes.append(y_handle) if self.gizmoZAxis: - z_arrow = self.gizmoZAxis.find("z_arrow") - if z_arrow: - arrow_nodes.append(z_arrow) + z_handle = self.gizmoZAxis.find("z_handle") + if z_handle: + 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: if arrow_node: @@ -410,17 +519,30 @@ class SelectionSystem: arrow_node.setShaderOff() arrow_node.setFogOff() arrow_node.setBin("fixed",31) - arrow_node.setDepthWrite(False) - arrow_node.setDepthTest(False) + #arrow_node.setDepthWrite(False) + #arrow_node.setDepthTest(False) #启用透明度S 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: self.gizmo.setLightOff() self.gizmo.setShaderOff() self.gizmo.setFogOff() self.gizmo.setBin("fixed",29) - self.gizmo.setDepthWrite(False) - self.gizmo.setDepthTest(False) + # self.gizmo.setDepthWrite(False) + #self.gizmo.setDepthTest(False) + except Exception as e: print(f"设置坐标轴渲染属性失败: {str(e)}") @@ -448,12 +570,49 @@ class SelectionSystem: self.clearGizmo() 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") if light_object: light_pos = light_object.pos self.gizmo.setPos(light_object.pos) self.gizmoTarget.setPos(light_pos) - else: # 只在必要时更新位置和朝向 self._updateGizmoPositionAndOrientation() @@ -486,13 +645,25 @@ class SelectionSystem: self.gizmo.setPos(center) self._last_gizmo_bounds_update = current_time - # 更新朝向 - parent_node = self.gizmoTarget.getParent() - if parent_node and parent_node != self.world.render: - parent_hpr = parent_node.getHpr() - self.gizmo.setHpr(parent_hpr) + 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: - 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) + + # 更新朝向 + # 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): """动态调整坐标轴大小,保持固定的屏幕大小""" @@ -589,6 +760,97 @@ class SelectionSystem: # except: # 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): """使用材质设置坐标轴颜色 - RenderPipeline兼容版本""" try: @@ -606,17 +868,19 @@ class SelectionSystem: axis_node = axis_nodes[axis] - # 查找箭头模型节点 - arrow_node = None - if axis == "x": - arrow_node = axis_node.find("x_arrow") - elif axis == "y": - arrow_node = axis_node.find("y_arrow") - elif axis == "z": - arrow_node = axis_node.find("z_arrow") + 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 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 # 创建或获取材质 @@ -630,20 +894,20 @@ class SelectionSystem: mat.set_roughness(1) # 应用材质 - arrow_node.setMaterial(mat, 1) + handle_node.setMaterial(mat, 1) # 设置透明度 if color[3] < 1.0: - arrow_node.setTransparency(TransparencyAttrib.MAlpha) + handle_node.setTransparency(TransparencyAttrib.MAlpha) else: - arrow_node.setTransparency(TransparencyAttrib.MNone) + handle_node.setTransparency(TransparencyAttrib.MNone) - arrow_node.setLightOff() # 禁用光照影响 - arrow_node.setShaderOff() # 禁用着色器 - arrow_node.setFogOff() # 禁用雾效果 + handle_node.setLightOff() # 禁用光照影响 + handle_node.setShaderOff() # 禁用着色器 + handle_node.setFogOff() # 禁用雾效果 - arrow_node.setBin("fixed",31) + handle_node.setBin("fixed",31) #arrow_node.setDepthWrite(False) #arrow_node.setDepthTest(True) @@ -1019,8 +1283,9 @@ class SelectionSystem: if not self.gizmo or self.isDraggingGizmo: return - # 使用统一的检测方法 - hoveredAxis = self.detectGizmoAxisAtMouse(mouseX, mouseY) + # 使用碰撞检测方法 + hoveredAxis = self.detectGizmoAxisWithCollision(mouseX, mouseY) + #hoveredAxis = self.detectGizmoAxisAtMouse(mouseX, mouseY) # 简化稳定性检测逻辑 if not hasattr(self, '_last_detected_axis'): @@ -1037,6 +1302,11 @@ class SelectionSystem: # 高亮新的轴 if 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 @@ -1074,17 +1344,25 @@ class SelectionSystem: return self.isDraggingGizmo = True - # 使用当前高亮的轴,如果有的话 + + # 使用当前高亮的轴,如果有的话;否则使用传入的轴 if self.gizmoHighlightAxis: self.dragGizmoAxis = self.gizmoHighlightAxis else: self.dragGizmoAxis = axis + self.dragStartMousePos = (mouseX, mouseY) # 保存开始拖拽时目标节点的位置和坐标轴的位置 self.gizmoTargetStartPos = self.gizmoTarget.getPos() 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: # 先将所有轴恢复为正常颜色 @@ -1094,13 +1372,15 @@ class SelectionSystem: # 然后将当前拖动的轴设置为高亮颜色 self.setGizmoAxisColor(self.dragGizmoAxis, self.gizmo_highlight_colors[self.dragGizmoAxis]) - self.gizmoHighlightAxis = self.dragGizmoAxis elif axis and axis in self.gizmo_colors: for axis_name in self.gizmo_colors.keys(): - self.setGizmoAxisColor(axis_name, self.gizmo_colors[axis_name]) + if axis_name != axis: + self.setGizmoAxisColor(axis_name, self.gizmo_colors[axis_name]) self.setGizmoAxisColor(axis, self.gizmo_highlight_colors[axis]) - self.gizmoHighlightAxis = axis + self.dragGizmoAxis = axis + + self.gizmoHighlightAxis = self.dragGizmoAxis print( f"开始拖拽 {self.dragGizmoAxis} 轴 - 目标起始位置: {self.gizmoTargetStartPos}, 坐标轴位置: {self.gizmoStartPos}, 鼠标: ({mouseX}, {mouseY})") @@ -1130,10 +1410,55 @@ class SelectionSystem: print("拖拽更新失败: 没有坐标轴起始位置") return + is_scale_tool = self.world.tool_manager.isScaleTool() + is_rotate_tool = self.world.tool_manager.isRotateTool() + # 计算鼠标移动距离(屏幕像素) mouseDeltaX = mouseX - self.dragStartMousePos[0] 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 @@ -1184,21 +1509,6 @@ class SelectionSystem: 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) - - # 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: print("拖拽更新失败: 无法获取轴线屏幕坐标") @@ -1209,7 +1519,6 @@ class SelectionSystem: axis_end_screen[1] - axis_start_screen[1] ) - # 归一化屏幕轴方向 import math length = math.sqrt(screen_axis_dir[0]**2 + screen_axis_dir[1]**2) @@ -1253,40 +1562,16 @@ class SelectionSystem: 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": 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": 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": 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: print(f"未知轴: {self.dragGizmoAxis}") return @@ -1329,10 +1614,10 @@ class SelectionSystem: def stopGizmoDrag(self): """停止坐标轴拖拽""" 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,保持当前高亮轴的状态 - # self.gizmoHighlightAxis = None + + # 恢复所有轴的颜色 + for axis_name in ["x", "y", "z"]: + self.setGizmoAxisColor(axis_name, self.gizmo_colors[axis_name]) self.isDraggingGizmo = False self.dragGizmoAxis = None @@ -1341,6 +1626,13 @@ class SelectionSystem: self.gizmoTargetStartPos = 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): @@ -1393,3 +1685,164 @@ class SelectionSystem: if self.selectionBoxTarget and self.selectionBoxTarget.isEmpty(): 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()}轴节点不存在") \ No newline at end of file diff --git a/core/tool_manager.py b/core/tool_manager.py index c9344f69..4f5f4cdf 100644 --- a/core/tool_manager.py +++ b/core/tool_manager.py @@ -150,49 +150,3 @@ class ToolManager: except Exception as e: print(f"❌ 启动插件配置器失败: {e}") 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 "未启动" diff --git a/ui/property_panel.py b/ui/property_panel.py index d2c51790..0421e5b3 100644 --- a/ui/property_panel.py +++ b/ui/property_panel.py @@ -395,19 +395,27 @@ class PropertyPanelManager: self.scale_y = QDoubleSpinBox() self.scale_z = QDoubleSpinBox() - # 设置缩放控件属性 - for scale_widget in [self.scale_x, self.scale_y, self.scale_z]: - scale_widget.setRange(0.01, 100) - scale_widget.setSingleStep(0.1) + current_scale = model.getScale() - self.scale_x.setValue(model.getScale().getX()) - self.scale_y.setValue(model.getScale().getY()) - self.scale_z.setValue(model.getScale().getZ()) + # 设置缩放控件属性 + for i, (scale_widget, scale_value) in enumerate(zip([self.scale_x, self.scale_y, self.scale_z], + [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_y.valueChanged.connect(lambda v: model.setScale(model.getScale().getX(), v, model.getScale().getZ())) - self.scale_z.valueChanged.connect(lambda v: model.setScale(model.getScale().getX(), model.getScale().getY(), v)) + self.scale_x.valueChanged.connect(lambda value: self._updateXScale(model, value)) + self.scale_y.valueChanged.connect(lambda value: self._updateYScale(model, value)) + self.scale_z.valueChanged.connect(lambda value: self._updateZScale(model, value)) # 创建并设置 X, Y, Z 标签居中 x_label3 = QLabel("X") @@ -434,6 +442,72 @@ class PropertyPanelManager: # 材质属性组 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): if not nodePath or self._propertyLayout is None: return