1
0
forked from Rowland/EG

拖动节点面板属性实时更新

This commit is contained in:
Hector 2025-08-18 09:33:10 +08:00
parent 6e3f47b7b0
commit 0cce93b05a
5 changed files with 152 additions and 35 deletions

2
.idea/EG.iml generated
View File

@ -4,7 +4,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.10 (EG)" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3.12 (PythonProject)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">

2
.idea/misc.xml generated
View File

@ -3,5 +3,5 @@
<component name="Black">
<option name="sdkName" value="Python 3.12 (PythonProject)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (EG)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (PythonProject)" project-jdk-type="Python SDK" />
</project>

File diff suppressed because one or more lines are too long

View File

@ -105,6 +105,37 @@ class SelectionSystem:
if not self.selectionBox or not self.selectionBoxTarget:
return
# 检查是否需要重新计算边界框
if not hasattr(self, '_bounds_cache'):
self._bounds_cache = {}
node_name = self.selectionBoxTarget.getName()
import time
current_time = time.time()
# 如果缓存存在且未过期,则使用缓存
if (node_name in self._bounds_cache and
current_time - self._bounds_cache[node_name]['time'] < 0.1):
minPoint, maxPoint = self._bounds_cache[node_name]['bounds']
else:
# 计算新的边界框并缓存
minPoint = Point3()
maxPoint = Point3()
if not self.selectionBoxTarget.calcTightBounds(minPoint, maxPoint, self.world.render):
return
# 缓存结果
self._bounds_cache[node_name] = {
'bounds': (minPoint, maxPoint),
'time': current_time
}
# 清理旧缓存
expired_keys = [k for k, v in self._bounds_cache.items()
if current_time - v['time'] > 1.0]
for key in expired_keys:
del self._bounds_cache[key]
# 清除现有的几何体
self.selectionBox.removeNode()
self.selectionBox = self.world.render.attachNewNode("selectionBox")
@ -177,6 +208,15 @@ class SelectionSystem:
def updateSelectionBoxTask(self, task):
"""选择框更新任务"""
try:
if not hasattr(self,'_last_selection_box_update'):
self._last_selection_box_update = 0
import time
current_time = time.time()
if current_time - self._last_selection_box_update < 0.1:
return task.cont
self._last_selection_box_update = current_time
if not self.selectionBox or not self.selectionBoxTarget:
return task.done # 结束任务
@ -598,6 +638,16 @@ class SelectionSystem:
def updateGizmoTask(self, task):
"""坐标轴更新任务 - 包含固定大小功能"""
try:
# 限制更新频率
if not hasattr(self, '_last_gizmo_update'):
self._last_gizmo_update = 0
import time
current_time = time.time()
if current_time - self._last_gizmo_update < 0.05: # 每0.05秒更新一次
return task.cont
self._last_gizmo_update = current_time
if not self.gizmo or not self.gizmoTarget:
return task.done
@ -613,25 +663,27 @@ class SelectionSystem:
self.gizmoTarget.setPos(light_pos)
else:
# 更新坐标轴位置,始终在目标节点中心
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)
# 【关键修复】:更新坐标轴朝向以跟踪父节点的变化
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)
# 只在必要时更新位置和朝向
self._updateGizmoPositionAndOrientation()
# # 更新坐标轴位置,始终在目标节点中心
# 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)
#
# # 【关键修复】:更新坐标轴朝向以跟踪父节点的变化
# 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)
# 【新功能】:动态调整坐标轴大小,保持固定的屏幕大小
self._updateGizmoScreenSize()
@ -642,6 +694,33 @@ class SelectionSystem:
print(f"坐标轴更新任务出错: {str(e)}")
return task.done
def _updateGizmoPositionAndOrientation(self):
"""优化的Gizmo位置和朝向更新"""
# 只在必要时重新计算边界框
if not hasattr(self, '_last_gizmo_bounds_update'):
self._last_gizmo_bounds_update = 0
import time
current_time = time.time()
if current_time - self._last_gizmo_bounds_update > 0.2: # 每0.2秒计算一次边界框
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._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)
else:
self.gizmo.setHpr(0, 0, 0)
def _updateGizmoScreenSize(self):
"""动态调整坐标轴大小,保持固定的屏幕大小"""
try:

View File

@ -309,6 +309,50 @@ class PropertyPanelManager:
# 材质属性组
self._updateModelMaterialPanel(model)
def refreshModelValues(self,nodePath):
if not nodePath or self._propertyLayout is None:
return
parent = nodePath.getParent()
render = self.world.render
relPos = nodePath.getPos(parent) if parent else nodePath.getPos()
if hasattr(self,'pos_x') and self.pos_x:
self.pos_x.blockSignals(True)
self.pos_x.setValue(relPos.getX())
self.pos_x.blockSignals(False)
if hasattr(self,'pos_y') and self.pos_y:
self.pos_y.blockSignals(True)
self.pos_y.setValue(relPos.getY())
self.pos_y.blockSignals(False)
if hasattr(self,'pos_z') and self.pos_z:
self.pos_z.blockSignals(True)
self.pos_z.setValue(relPos.getZ())
self.pos_z.blockSignals(False)
worldPos = nodePath.getPos(render)
for axis,attr in zip(('x','y','z'),('world_pos_x','world_pos_y','world_pos_z')):
spin = getattr(self,attr,None)
if spin:
spin.blockSignals(True)
spin.setValue(getattr(worldPos,axis))
spin.blockSignals(False)
hpr = nodePath.getHpr()
for idx,(attr,val) in enumerate(zip(('rot_h','rot_p','rot_r'),hpr)):
spin = getattr(self,attr,None)
if spin:
spin.blockSignals(True)
spin.setValue(val)
spin.blockSignals(False)
scale = nodePath.getScale()
for axis,attr in zip(('x','y','z'),('scale_x','scale_y','scale_z')):
spin = getattr(self,attr,None)
if spin:
spin.blockSignals(True)
spin.setValue(getattr(scale,axis))
spin.blockSignals(False)
def updateGUIPropertyPanel(self, gui_element):
"""更新GUI元素属性面板"""
@ -877,7 +921,7 @@ class PropertyPanelManager:
print(f"材质基础颜色: {base_color}")
# 基础颜色标题
color_row = 2 if material_status != "标准PBR材质" else 0
color_row = 2 if material_status != "标准PBR材质" else 1
material_layout.addWidget(QLabel("基础颜色"), color_row, 0)
# R, G, B 标签
@ -3870,20 +3914,14 @@ class PropertyPanelManager:
azimuth, altitude = presets[preset_name]
# 更新滑块和数值框
self.sun_azimuth_slider.blockSignals(True)
self.sun_azimuth_spinbox.blockSignals(True)
self.sun_altitude_slider.blockSignals(True)
self.sun_altitude_spinbox.blockSignals(True)
self.azimuthSpinBox.blockSignals(True)
self.altitudeSpinBox.blockSignals(True)
self.sun_azimuth_slider.setValue(azimuth)
self.sun_azimuth_spinbox.setValue(azimuth)
self.sun_altitude_slider.setValue(altitude)
self.sun_altitude_spinbox.setValue(altitude)
self.azimuthSpinBox.setValue(azimuth)
self.altitudeSpinBox.setValue(altitude)
self.sun_azimuth_slider.blockSignals(False)
self.sun_azimuth_spinbox.blockSignals(False)
self.sun_altitude_slider.blockSignals(False)
self.sun_altitude_spinbox.blockSignals(False)
self.azimuthSpinBox.blockSignals(False)
self.altitudeSpinBox.blockSignals(False)
# 应用设置 - 优先使用Day Time Editor
azimuth_success = self._updateDayTimeEditorSetting("scattering", "sun_azimuth", azimuth)