diff --git a/scene/scene_manager.py b/scene/scene_manager.py index 274f9a36..64cec8d3 100644 --- a/scene/scene_manager.py +++ b/scene/scene_manager.py @@ -14,7 +14,7 @@ from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QTreeWidgetItem from panda3d.core import ( ModelPool, ModelRoot, Filename, NodePath, GeomNode, Material, Vec4, Vec3, - MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere, + MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere, CollisionBox, BitMask32, TransparencyAttrib, LColor, TransformState, RenderModeAttrib ) import json @@ -164,7 +164,7 @@ class SceneManager: #self._adjustModelToGround(model) # 创建并设置基础材质 - print("\n=== 开始设置材质 ===") + #print("\n=== 开始设置材质 ===") #self._applyMaterialsToModel(model) # 设置碰撞检测(重要!用于选择功能) @@ -718,7 +718,6 @@ class SceneManager: def setupCollision(self, model): """为模型设置碰撞检测(增强版本)""" try: - # 创建碰撞节点 cNode = CollisionNode(f'modelCollision_{model.getName()}') @@ -734,39 +733,61 @@ class SceneManager: cNode.setIntoCollideMask(current_mask | model_collision_mask) print(f"为 {model.getName()} 启用模型间碰撞检测") - # 获取模型的边界 - bounds = model.getBounds() - if bounds.isEmpty(): - print(f"⚠️ 模型 {model.getName()} 边界为空,使用默认碰撞体") - # 使用默认的小球体 - cSphere = CollisionSphere(Point3(0, 0, 0), 1.0) - else: - center = bounds.getCenter() - radius = bounds.getRadius() - - # 确保半径不为零 - if radius <= 0: + # 获取模型的边界信息,使用与选择框相同的计算方法 + minPoint = Point3() + maxPoint = Point3() + + # 使用与选择框相同的calcTightBounds方法获取边界 + if model.calcTightBounds(minPoint, maxPoint, self.world.render): + # 检查边界框的有效性 + if (abs(minPoint.x) < 1e10 and abs(minPoint.y) < 1e10 and abs(minPoint.z) < 1e10 and + abs(maxPoint.x) < 1e10 and abs(maxPoint.y) < 1e10 and abs(maxPoint.z) < 1e10): + # 特殊处理FBX模型的碰撞体 + if model.hasTag("model_path") and model.getTag("model_path").lower().endswith('.fbx'): + print("检测到FBX模型,调整碰撞体...") + # 反向应用FBX的变换以匹配视觉表现 + # 缩放调整: 乘以100(因为模型被缩小了0.01倍) + minPoint *= 100 + maxPoint *= 100 + + # 旋转调整: 绕P轴旋转-90度 + # 创建旋转矩阵 + from panda3d.core import Mat4, LRotation + rotation = LRotation(0, -90, 0) # 绕P轴旋转-90度 + rot_matrix = Mat4() + rotation.extractToMatrix(rot_matrix) + + # 应用旋转变换到边界点 + minPoint = rot_matrix.xformPoint(minPoint) + maxPoint = rot_matrix.xformPoint(maxPoint) + + # 创建与选择框完全一致的碰撞体 + cBox = CollisionBox(minPoint, maxPoint) + cNode.addSolid(cBox) + radius = max(maxPoint.x - minPoint.x, maxPoint.y - minPoint.y, maxPoint.z - minPoint.z) / 2 + else: + # 使用默认球体 radius = 1.0 - print(f"⚠️ 模型 {model.getName()} 半径为零,使用默认半径 1.0") - # - # # 添加碰撞球体 - # cSphere = CollisionSphere(center, radius) - cSphere = self.world.collision_manager.createCollisionShape(model, 'polygon') - - cNode.addSolid(cSphere) + cSphere = CollisionSphere(Point3(0, 0, 0), radius) + cNode.addSolid(cSphere) + else: + # 使用默认球体 + radius = 1.0 + cSphere = CollisionSphere(Point3(0, 0, 0), radius) + cNode.addSolid(cSphere) # 将碰撞节点附加到模型上 cNodePath = model.attachNewNode(cNode) # 根据调试设置决定是否显示碰撞体 - if hasattr(self.world, 'debug_collision') and self.world.debug_collision: - cNodePath.hide() - else: - cNodePath.hide() + # if hasattr(self.world, 'debug_collision') and self.world.debug_collision: + # cNodePath.show() + # else: + # cNodePath.hide() # 为模型添加碰撞相关标签 model.setTag("has_collision", "true") - model.setTag("collision_radius", str(radius if 'radius' in locals() else 1.0)) + model.setTag("collision_radius", str(radius)) print(f"✅ 为模型 {model.getName()} 设置碰撞检测完成")