Merge remote-tracking branch 'refs/remotes/origin/main_ch_eg' into addRender
This commit is contained in:
commit
97fea27d02
@ -37,6 +37,9 @@ class PropertyPanelManager:
|
||||
self.world.terrain_edit_strength = 0.3
|
||||
if not hasattr(self.world, 'terrain_edit_operation'): # 这里原来是 terrain_edit_opertaion
|
||||
self.world.terrain_edit_operation = "add"
|
||||
|
||||
# 初始化碰撞参数加载标志位
|
||||
self._loading_collision_params = False
|
||||
|
||||
# 定义紧凑样式
|
||||
self.compact_style = """
|
||||
@ -8788,6 +8791,13 @@ except Exception as e:
|
||||
self.collision_pos_y = self._createCollisionSpinBox(-100, 100, 2)
|
||||
self.collision_pos_z = self._createCollisionSpinBox(-100, 100, 2)
|
||||
|
||||
# 只在没有现有碰撞时设置默认值,否则由_loadCurrentCollisionParameters加载实际值
|
||||
if not self._hasCollision(model):
|
||||
# 设置默认位置偏移(无偏移)
|
||||
self.collision_pos_x.setValue(0.0)
|
||||
self.collision_pos_y.setValue(0.0)
|
||||
self.collision_pos_z.setValue(0.0)
|
||||
|
||||
layout.addWidget(QLabel("X:"), current_row, 0)
|
||||
layout.addWidget(self.collision_pos_x, current_row, 1)
|
||||
current_row += 1
|
||||
@ -8842,18 +8852,20 @@ except Exception as e:
|
||||
|
||||
self.collision_radius = self._createCollisionSpinBox(0.1, 100, 2)
|
||||
|
||||
# 设置基于模型变换后尺寸的默认值
|
||||
if hasattr(self.world, 'collision_manager'):
|
||||
transformed_info = self.world.collision_manager._getTransformedModelInfo(model)
|
||||
if transformed_info:
|
||||
default_radius = transformed_info['radius']
|
||||
self.collision_radius.setValue(default_radius)
|
||||
else:
|
||||
# 回退到原始包围盒
|
||||
bounds = model.getBounds()
|
||||
if not bounds.isEmpty():
|
||||
default_radius = bounds.getRadius()
|
||||
self.collision_radius.setValue(default_radius)
|
||||
# 只在没有现有碰撞时设置默认值,否则由_loadCurrentCollisionParameters加载实际值
|
||||
if not self._hasCollision(model):
|
||||
# 设置基于模型变换后尺寸的默认值
|
||||
if hasattr(self.world, 'collision_manager'):
|
||||
transformed_info = self.world.collision_manager._getTransformedModelInfo(model)
|
||||
if transformed_info:
|
||||
default_radius = transformed_info['radius']
|
||||
self.collision_radius.setValue(default_radius)
|
||||
else:
|
||||
# 回退到原始包围盒
|
||||
bounds = model.getBounds()
|
||||
if not bounds.isEmpty():
|
||||
default_radius = bounds.getRadius()
|
||||
self.collision_radius.setValue(default_radius)
|
||||
|
||||
self.collision_radius.valueChanged.connect(lambda v: self._updateSphereRadius(model, v))
|
||||
layout.addWidget(self.collision_radius, current_row, 1)
|
||||
@ -8874,22 +8886,24 @@ except Exception as e:
|
||||
self.collision_length = self._createCollisionSpinBox(0.1, 100, 2)
|
||||
self.collision_height = self._createCollisionSpinBox(0.1, 100, 2)
|
||||
|
||||
# 设置基于模型变换后尺寸的默认值
|
||||
if hasattr(self.world, 'collision_manager'):
|
||||
transformed_info = self.world.collision_manager._getTransformedModelInfo(model)
|
||||
if transformed_info:
|
||||
actual_size = transformed_info['size']
|
||||
self.collision_width.setValue(actual_size.x)
|
||||
self.collision_length.setValue(actual_size.y)
|
||||
self.collision_height.setValue(actual_size.z)
|
||||
else:
|
||||
# 回退到原始包围盒
|
||||
bounds = model.getBounds()
|
||||
if not bounds.isEmpty():
|
||||
model_size = bounds.getMax() - bounds.getMin()
|
||||
self.collision_width.setValue(model_size.x)
|
||||
self.collision_length.setValue(model_size.y)
|
||||
self.collision_height.setValue(model_size.z)
|
||||
# 只在没有现有碰撞时设置默认值,否则由_loadCurrentCollisionParameters加载实际值
|
||||
if not self._hasCollision(model):
|
||||
# 设置基于模型变换后尺寸的默认值
|
||||
if hasattr(self.world, 'collision_manager'):
|
||||
transformed_info = self.world.collision_manager._getTransformedModelInfo(model)
|
||||
if transformed_info:
|
||||
actual_size = transformed_info['size']
|
||||
self.collision_width.setValue(actual_size.x)
|
||||
self.collision_length.setValue(actual_size.y)
|
||||
self.collision_height.setValue(actual_size.z)
|
||||
else:
|
||||
# 回退到原始包围盒
|
||||
bounds = model.getBounds()
|
||||
if not bounds.isEmpty():
|
||||
model_size = bounds.getMax() - bounds.getMin()
|
||||
self.collision_width.setValue(model_size.x)
|
||||
self.collision_length.setValue(model_size.y)
|
||||
self.collision_height.setValue(model_size.z)
|
||||
|
||||
layout.addWidget(QLabel("宽度:"), current_row, 0)
|
||||
layout.addWidget(self.collision_width, current_row, 1)
|
||||
@ -8920,22 +8934,24 @@ except Exception as e:
|
||||
|
||||
self.collision_capsule_radius = self._createCollisionSpinBox(0.1, 100, 2)
|
||||
|
||||
# 设置基于模型变换后尺寸的默认值
|
||||
if hasattr(self.world, 'collision_manager'):
|
||||
transformed_info = self.world.collision_manager._getTransformedModelInfo(model)
|
||||
if transformed_info:
|
||||
actual_size = transformed_info['size']
|
||||
# 更合理的默认半径:基于变换后模型宽度的平均值
|
||||
default_radius = min(actual_size.x, actual_size.y) / 2.5
|
||||
self.collision_capsule_radius.setValue(default_radius)
|
||||
else:
|
||||
# 回退到原始包围盒
|
||||
bounds = model.getBounds()
|
||||
if not bounds.isEmpty():
|
||||
model_size = bounds.getMax() - bounds.getMin()
|
||||
# 更合理的默认半径:基于模型宽度的平均值
|
||||
default_radius = min(model_size.x, model_size.y) / 2.5
|
||||
self.collision_capsule_radius.setValue(default_radius)
|
||||
# 只在没有现有碰撞时设置默认值,否则由_loadCurrentCollisionParameters加载实际值
|
||||
if not self._hasCollision(model):
|
||||
# 设置基于模型变换后尺寸的默认值
|
||||
if hasattr(self.world, 'collision_manager'):
|
||||
transformed_info = self.world.collision_manager._getTransformedModelInfo(model)
|
||||
if transformed_info:
|
||||
actual_size = transformed_info['size']
|
||||
# 更合理的默认半径:基于变换后模型宽度的平均值
|
||||
default_radius = min(actual_size.x, actual_size.y) / 2.5
|
||||
self.collision_capsule_radius.setValue(default_radius)
|
||||
else:
|
||||
# 回退到原始包围盒
|
||||
bounds = model.getBounds()
|
||||
if not bounds.isEmpty():
|
||||
model_size = bounds.getMax() - bounds.getMin()
|
||||
# 更合理的默认半径:基于模型宽度的平均值
|
||||
default_radius = min(model_size.x, model_size.y) / 2.5
|
||||
self.collision_capsule_radius.setValue(default_radius)
|
||||
|
||||
self.collision_capsule_radius.valueChanged.connect(lambda v: self._updateCapsuleRadius(model, v))
|
||||
layout.addWidget(self.collision_capsule_radius, current_row, 1)
|
||||
@ -8946,18 +8962,20 @@ except Exception as e:
|
||||
|
||||
self.collision_capsule_height = self._createCollisionSpinBox(0.1, 100, 2)
|
||||
|
||||
# 设置基于模型变换后高度的默认值
|
||||
if hasattr(self.world, 'collision_manager'):
|
||||
transformed_info = self.world.collision_manager._getTransformedModelInfo(model)
|
||||
if transformed_info:
|
||||
actual_size = transformed_info['size']
|
||||
self.collision_capsule_height.setValue(actual_size.z)
|
||||
else:
|
||||
# 回退到原始包围盒
|
||||
bounds = model.getBounds()
|
||||
if not bounds.isEmpty():
|
||||
model_size = bounds.getMax() - bounds.getMin()
|
||||
self.collision_capsule_height.setValue(model_size.z)
|
||||
# 只在没有现有碰撞时设置默认值,否则由_loadCurrentCollisionParameters加载实际值
|
||||
if not self._hasCollision(model):
|
||||
# 设置基于模型变换后高度的默认值
|
||||
if hasattr(self.world, 'collision_manager'):
|
||||
transformed_info = self.world.collision_manager._getTransformedModelInfo(model)
|
||||
if transformed_info:
|
||||
actual_size = transformed_info['size']
|
||||
self.collision_capsule_height.setValue(actual_size.z)
|
||||
else:
|
||||
# 回退到原始包围盒
|
||||
bounds = model.getBounds()
|
||||
if not bounds.isEmpty():
|
||||
model_size = bounds.getMax() - bounds.getMin()
|
||||
self.collision_capsule_height.setValue(model_size.z)
|
||||
|
||||
self.collision_capsule_height.valueChanged.connect(lambda v: self._updateCapsuleHeight(model, v))
|
||||
layout.addWidget(self.collision_capsule_height, current_row, 1)
|
||||
@ -8978,6 +8996,13 @@ except Exception as e:
|
||||
self.collision_normal_y = self._createCollisionSpinBox(-1, 1, 2)
|
||||
self.collision_normal_z = self._createCollisionSpinBox(-1, 1, 2)
|
||||
|
||||
# 只在没有现有碰撞时设置默认值,否则由_loadCurrentCollisionParameters加载实际值
|
||||
if not self._hasCollision(model):
|
||||
# 设置默认法向量(向上)
|
||||
self.collision_normal_x.setValue(0.0)
|
||||
self.collision_normal_y.setValue(0.0)
|
||||
self.collision_normal_z.setValue(1.0)
|
||||
|
||||
layout.addWidget(QLabel("Nx:"), current_row, 0)
|
||||
layout.addWidget(self.collision_normal_x, current_row, 1)
|
||||
current_row += 1
|
||||
@ -9123,6 +9148,10 @@ except Exception as e:
|
||||
return
|
||||
|
||||
self._adding_collision = True
|
||||
|
||||
# 初始化加载参数标志位
|
||||
if not hasattr(self, '_loading_collision_params'):
|
||||
self._loading_collision_params = False
|
||||
|
||||
if hasattr(self.world, 'scene_manager'):
|
||||
# 获取选中的碰撞形状
|
||||
@ -9299,17 +9328,44 @@ except Exception as e:
|
||||
def _loadCurrentCollisionParameters(self, model, shape_type):
|
||||
"""加载当前碰撞参数到界面"""
|
||||
try:
|
||||
# 设置标志位,防止在加载参数时触发更新
|
||||
self._loading_collision_params = True
|
||||
|
||||
collision_nodes = model.findAllMatches("**/+CollisionNode")
|
||||
for collision_np in collision_nodes:
|
||||
collision_node = collision_np.node()
|
||||
if collision_node.getNumSolids() > 0:
|
||||
solid = collision_node.getSolid(0)
|
||||
|
||||
# 获取碰撞节点的位置
|
||||
pos = collision_np.getPos()
|
||||
self.collision_pos_x.setValue(pos.x)
|
||||
self.collision_pos_y.setValue(pos.y)
|
||||
self.collision_pos_z.setValue(pos.z)
|
||||
# 从碰撞体形状中提取位置偏移
|
||||
if hasattr(self, 'collision_pos_x'):
|
||||
# 获取模型的实际中心(考虑变换)
|
||||
if hasattr(self.world, 'collision_manager'):
|
||||
transformed_info = self.world.collision_manager._getTransformedModelInfo(model)
|
||||
if transformed_info:
|
||||
model_center = transformed_info['center']
|
||||
else:
|
||||
model_center = model.getBounds().getCenter() if not model.getBounds().isEmpty() else Point3(0, 0, 0)
|
||||
else:
|
||||
model_center = model.getBounds().getCenter() if not model.getBounds().isEmpty() else Point3(0, 0, 0)
|
||||
|
||||
# 获取碰撞体的中心
|
||||
collision_center = self._getCollisionShapeCenter(solid)
|
||||
if collision_center:
|
||||
# 计算偏移:碰撞体中心 - 模型中心
|
||||
offset_x = collision_center.x - model_center.x
|
||||
offset_y = collision_center.y - model_center.y
|
||||
offset_z = collision_center.z - model_center.z
|
||||
self.collision_pos_x.setValue(offset_x)
|
||||
self.collision_pos_y.setValue(offset_y)
|
||||
self.collision_pos_z.setValue(offset_z)
|
||||
print(f"加载位置偏移: ({offset_x:.2f}, {offset_y:.2f}, {offset_z:.2f})")
|
||||
else:
|
||||
# 如果无法计算偏移,设置为0
|
||||
self.collision_pos_x.setValue(0.0)
|
||||
self.collision_pos_y.setValue(0.0)
|
||||
self.collision_pos_z.setValue(0.0)
|
||||
print("无法计算位置偏移,设置为0")
|
||||
|
||||
if shape_type == 'sphere':
|
||||
self._loadSphereParameters(solid)
|
||||
@ -9323,6 +9379,40 @@ except Exception as e:
|
||||
|
||||
except Exception as e:
|
||||
print(f"加载碰撞参数失败: {e}")
|
||||
finally:
|
||||
# 重置标志位
|
||||
self._loading_collision_params = False
|
||||
|
||||
def _getCollisionShapeCenter(self, solid):
|
||||
"""从碰撞体形状中获取中心点"""
|
||||
try:
|
||||
from panda3d.core import CollisionSphere, CollisionBox, CollisionCapsule, CollisionPlane, Point3
|
||||
|
||||
if isinstance(solid, CollisionSphere):
|
||||
return solid.getCenter()
|
||||
elif isinstance(solid, CollisionBox):
|
||||
# 盒子的中心是最小点和最大点的中点
|
||||
min_pt = solid.getMin()
|
||||
max_pt = solid.getMax()
|
||||
return Point3((min_pt.x + max_pt.x) * 0.5,
|
||||
(min_pt.y + max_pt.y) * 0.5,
|
||||
(min_pt.z + max_pt.z) * 0.5)
|
||||
elif isinstance(solid, CollisionCapsule):
|
||||
# 胶囊体的中心是两个端点的中点
|
||||
point_a = solid.getPointA()
|
||||
point_b = solid.getPointB()
|
||||
return Point3((point_a.x + point_b.x) * 0.5,
|
||||
(point_a.y + point_b.y) * 0.5,
|
||||
(point_a.z + point_b.z) * 0.5)
|
||||
elif isinstance(solid, CollisionPlane):
|
||||
# 平面没有明确的中心,返回平面上的一个点
|
||||
plane = solid.getPlane()
|
||||
return plane.getPoint()
|
||||
else:
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"获取碰撞体中心失败: {e}")
|
||||
return None
|
||||
|
||||
def _loadSphereParameters(self, solid):
|
||||
"""加载球形参数"""
|
||||
@ -9383,8 +9473,8 @@ except Exception as e:
|
||||
def _updateCollisionPosition(self, model, axis, value):
|
||||
"""更新碰撞位置偏移"""
|
||||
try:
|
||||
# 防止重复调用导致无限循环
|
||||
if getattr(self, '_updating_collision_position', False):
|
||||
# 防止重复调用导致无限循环,以及在加载参数时防止更新
|
||||
if getattr(self, '_updating_collision_position', False) or getattr(self, '_loading_collision_params', False):
|
||||
return
|
||||
self._updating_collision_position = True
|
||||
|
||||
@ -9431,8 +9521,8 @@ except Exception as e:
|
||||
def _updateSphereRadius(self, model, radius):
|
||||
"""更新球形半径"""
|
||||
try:
|
||||
# 防止重复调用导致无限循环
|
||||
if getattr(self, '_updating_sphere_radius', False):
|
||||
# 防止重复调用导致无限循环,以及在加载参数时防止更新
|
||||
if getattr(self, '_updating_sphere_radius', False) or getattr(self, '_loading_collision_params', False):
|
||||
return
|
||||
self._updating_sphere_radius = True
|
||||
|
||||
@ -9453,8 +9543,8 @@ except Exception as e:
|
||||
def _updateBoxSize(self, model, dimension, value):
|
||||
"""更新盒型尺寸"""
|
||||
try:
|
||||
# 防止重复调用导致无限循环
|
||||
if getattr(self, '_updating_box_size', False):
|
||||
# 防止重复调用导致无限循环,以及在加载参数时防止更新
|
||||
if getattr(self, '_updating_box_size', False) or getattr(self, '_loading_collision_params', False):
|
||||
return
|
||||
self._updating_box_size = True
|
||||
|
||||
@ -9480,8 +9570,8 @@ except Exception as e:
|
||||
def _updateCapsuleRadius(self, model, radius):
|
||||
"""更新胶囊体半径"""
|
||||
try:
|
||||
# 防止重复调用导致无限循环
|
||||
if getattr(self, '_updating_capsule_radius', False):
|
||||
# 防止重复调用导致无限循环,以及在加载参数时防止更新
|
||||
if getattr(self, '_updating_capsule_radius', False) or getattr(self, '_loading_collision_params', False):
|
||||
return
|
||||
self._updating_capsule_radius = True
|
||||
|
||||
@ -9504,8 +9594,8 @@ except Exception as e:
|
||||
def _updateCapsuleHeight(self, model, height):
|
||||
"""更新胶囊体高度"""
|
||||
try:
|
||||
# 防止重复调用导致无限循环
|
||||
if getattr(self, '_updating_capsule_height', False):
|
||||
# 防止重复调用导致无限循环,以及在加载参数时防止更新
|
||||
if getattr(self, '_updating_capsule_height', False) or getattr(self, '_loading_collision_params', False):
|
||||
return
|
||||
self._updating_capsule_height = True
|
||||
|
||||
@ -9528,8 +9618,8 @@ except Exception as e:
|
||||
def _updatePlaneNormal(self, model, axis, value):
|
||||
"""更新平面法向量"""
|
||||
try:
|
||||
# 防止重复调用导致无限循环
|
||||
if getattr(self, '_updating_plane_normal', False):
|
||||
# 防止重复调用导致无限循环,以及在加载参数时防止更新
|
||||
if getattr(self, '_updating_plane_normal', False) or getattr(self, '_loading_collision_params', False):
|
||||
return
|
||||
self._updating_plane_normal = True
|
||||
|
||||
@ -9553,7 +9643,7 @@ except Exception as e:
|
||||
self._updating_plane_normal = False
|
||||
|
||||
def _recreateCollisionShape(self, model, shape_type, **kwargs):
|
||||
"""重新创建碰撞形状(保持位置和可见性)"""
|
||||
"""重新创建碰撞形状(保持可见性)"""
|
||||
try:
|
||||
# 保存当前状态
|
||||
collision_nodes = model.findAllMatches("**/+CollisionNode")
|
||||
@ -9561,7 +9651,6 @@ except Exception as e:
|
||||
return
|
||||
|
||||
collision_np = collision_nodes[0]
|
||||
current_pos = collision_np.getPos()
|
||||
is_visible = not collision_np.isHidden()
|
||||
|
||||
# 移除旧的碰撞体
|
||||
@ -9572,7 +9661,7 @@ except Exception as e:
|
||||
cNode = CollisionNode(f'modelCollision_{model.getName()}')
|
||||
cNode.setIntoCollideMask(BitMask32.bit(2))
|
||||
|
||||
# 创建新形状
|
||||
# 创建新形状(位置偏移已经烘焙在形状中)
|
||||
if hasattr(self.world, 'collision_manager'):
|
||||
collision_shape = self.world.collision_manager.createCollisionShape(model, shape_type, **kwargs)
|
||||
else:
|
||||
@ -9582,9 +9671,10 @@ except Exception as e:
|
||||
|
||||
cNode.addSolid(collision_shape)
|
||||
|
||||
# 重新附加并恢复状态
|
||||
# 重新附加(不设置额外位置,因为位置偏移已经在形状中)
|
||||
new_collision_np = model.attachNewNode(cNode)
|
||||
new_collision_np.setPos(current_pos)
|
||||
# 碰撞节点默认位置为 (0, 0, 0),位置偏移通过形状几何体处理
|
||||
new_collision_np.setPos(0, 0, 0)
|
||||
|
||||
if is_visible:
|
||||
new_collision_np.show()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user