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

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 PyQt5.QtWidgets import QTreeWidgetItem
from panda3d.core import ( from panda3d.core import (
ModelPool, ModelRoot, Filename, NodePath, GeomNode, Material, Vec4, Vec3, ModelPool, ModelRoot, Filename, NodePath, GeomNode, Material, Vec4, Vec3,
MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere, MaterialAttrib, ColorAttrib, Point3, CollisionNode, CollisionSphere, CollisionBox,
BitMask32, TransparencyAttrib, LColor, TransformState, RenderModeAttrib BitMask32, TransparencyAttrib, LColor, TransformState, RenderModeAttrib
) )
import json import json
@ -164,7 +164,7 @@ class SceneManager:
#self._adjustModelToGround(model) #self._adjustModelToGround(model)
# 创建并设置基础材质 # 创建并设置基础材质
print("\n=== 开始设置材质 ===") #print("\n=== 开始设置材质 ===")
#self._applyMaterialsToModel(model) #self._applyMaterialsToModel(model)
# 设置碰撞检测(重要!用于选择功能) # 设置碰撞检测(重要!用于选择功能)
@ -718,7 +718,6 @@ class SceneManager:
def setupCollision(self, model): def setupCollision(self, model):
"""为模型设置碰撞检测(增强版本)""" """为模型设置碰撞检测(增强版本)"""
try: try:
# 创建碰撞节点 # 创建碰撞节点
cNode = CollisionNode(f'modelCollision_{model.getName()}') cNode = CollisionNode(f'modelCollision_{model.getName()}')
@ -734,39 +733,61 @@ class SceneManager:
cNode.setIntoCollideMask(current_mask | model_collision_mask) cNode.setIntoCollideMask(current_mask | model_collision_mask)
print(f"{model.getName()} 启用模型间碰撞检测") print(f"{model.getName()} 启用模型间碰撞检测")
# 获取模型的边界 # 获取模型的边界信息,使用与选择框相同的计算方法
bounds = model.getBounds() minPoint = Point3()
if bounds.isEmpty(): maxPoint = Point3()
print(f"⚠️ 模型 {model.getName()} 边界为空,使用默认碰撞体")
# 使用默认的小球体 # 使用与选择框相同的calcTightBounds方法获取边界
cSphere = CollisionSphere(Point3(0, 0, 0), 1.0) if model.calcTightBounds(minPoint, maxPoint, self.world.render):
else: # 检查边界框的有效性
center = bounds.getCenter() if (abs(minPoint.x) < 1e10 and abs(minPoint.y) < 1e10 and abs(minPoint.z) < 1e10 and
radius = bounds.getRadius() 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'):
if radius <= 0: 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 radius = 1.0
print(f"⚠️ 模型 {model.getName()} 半径为零,使用默认半径 1.0") cSphere = CollisionSphere(Point3(0, 0, 0), radius)
# cNode.addSolid(cSphere)
# # 添加碰撞球体 else:
# cSphere = CollisionSphere(center, radius) # 使用默认球体
cSphere = self.world.collision_manager.createCollisionShape(model, 'polygon') radius = 1.0
cSphere = CollisionSphere(Point3(0, 0, 0), radius)
cNode.addSolid(cSphere) cNode.addSolid(cSphere)
# 将碰撞节点附加到模型上 # 将碰撞节点附加到模型上
cNodePath = model.attachNewNode(cNode) cNodePath = model.attachNewNode(cNode)
# 根据调试设置决定是否显示碰撞体 # 根据调试设置决定是否显示碰撞体
if hasattr(self.world, 'debug_collision') and self.world.debug_collision: # if hasattr(self.world, 'debug_collision') and self.world.debug_collision:
cNodePath.hide() # cNodePath.show()
else: # else:
cNodePath.hide() # cNodePath.hide()
# 为模型添加碰撞相关标签 # 为模型添加碰撞相关标签
model.setTag("has_collision", "true") 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()} 设置碰撞检测完成") print(f"✅ 为模型 {model.getName()} 设置碰撞检测完成")