优化导入模型设置碰撞体的位置及大小与模型相对应

This commit is contained in:
Hector 2025-10-29 11:11:58 +08:00
parent 85f61bd78a
commit e1b4731443

View File

@ -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()} 设置碰撞检测完成")